Android手机开发专题博客

Android手机开发专题博客,为您精选安卓手机开发教程,助您手机开发愉快!

公告信息
欢迎光临Android手机开发专题博客,祝您手机开发愉快!
文章档案

Android 记事本开发实例详解

Android 记事本开发实例详解:本节将介绍Android自带的一个范例程序:记事本,通过讲解相关内容,让大伙能快速的对android开发有一个基础的了解:

  小技巧预告

  1,在命令行中使用”adb shell”命令进入系统中,然后”cd app”进入应用程序所在目录,”rm XXX”就可以删除你指定的apk,从而去掉其在系统顶层界面占据的图标,若两次”cd data”则可以进入应用程序使用的数据目录,你的数据可以保存在这里,例如Notepad就是把其数据库放在它的databases目录下,名为note_pad.db.

  2,第一次启动模拟器会比较慢,但以后就别关闭模拟器了,修改代码,调试都不需要再次启动的,直接修改后rundebug就是。

下面开始正文内容:

  预备知识

      搭建开发环境,尝试编写”Hello World”,了解Android的基本概念,熟悉AndroidAPI(官方文档中都有,不赘述)

  程序截图

      先来简单了解下程序运行的效果







  程序入口点 

  类似于win32程序里的WinMain函数,Android自然也有它的程序入口点。它通过在AndroidManifest.xml文件中配置来指明,可以看到名为NotesListactivity节点下有这样一个intent-filter,actionandroid.intent.action.MAIN, Category指定为 android.intent.category.LAUNCHER,这就指明了这个activity是作为入口activity,系统查找到它后,就会创建这个activity实例来运行,若未发现就不启动(你可以把MAIN改名字试试)

  <intent-filter>
                
<action android:name="android.intent.action.MAIN" />
                
<category android:name="android.intent.category.LAUNCHER" />
            
</intent-filter>

  NotesList详解

      就从入口点所在的activity(见图1)开始,可以看到这个activity最重要的功能就是显示日志列表。这个程序的日志都存放在Sqlite数据库中,因此需要读取出所有的日志记录并显示。先来看两个重要的私有数据,第一个PROJECTION字段指明了日志列表所关注的数据库中的字段(即只需要IDTitle就可以了)。

   private static final String[] PROJECTION = new String[] {
            Notes._ID, 
// 0
            Notes.TITLE, // 1
    };

     第二个字段COLUMN_INDEX_TITLE指明title字段在数据表中的索引。

private static final int COLUMN_INDEX_TITLE = 1;

然后就进入第一个调用的函数onCreate

        Intent intent = getIntent();
        
if (intent.getData() == null
        {
            intent.setData(Notes.CONTENT_URI);
        }

      因为NotesList这个activity是系统调用的,此时的intent是不带数据和操作类型的,系统只是在其中指明了目标组件是Notelist,所以这里把”content:// com.google.provider.NotePad/notes”保存到intent里面,这个URI地址指明了数据库中的数据表名(参见以后的NotePadProvider类),也就是保存日志的数据表notes

        Cursor cursor = managedQuery(getIntent().getData(), PROJECTION, nullnull, Notes.DEFAULT_SORT_ORDER);

      然后调用managedQuery函数查询出所有的日志信息,这里第一个参数就是上面设置的” content:// com.google.provider.NotePad/notes”这个URI,即notes数据表。PROJECTION 字段指明了结果中所需要的字段,Notes.DEFAULT_SORT_ORDER 指明了结果的排序规则。实际上managedQuery并没有直接去查询数据库,而是通过Content Provider来完成实际的数据库操作,这样就实现了逻辑层和数据库层的分离。

 SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.noteslist_item, cursor,
                
new String[] { Notes.TITLE }, new int[] { android.R.id.text1 });
        setListAdapter(adapter);

      查询出日志列表后,构造一个CursorAdapter,并将其作为List View的数据源,从而在界面上显示出日志列表。可以看到,第二个参数是R.layout.noteslist_item,打开对应的noteslist_item.xml文件,

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id
="@android:id/text1"
    android:layout_width
="fill_parent"
    android:layout_height
="?android:attr/listPreferredItemHeight"
    android:textAppearance
="?android:attr/textAppearanceLarge"
    android:gravity
="center_vertical"
    android:paddingLeft
="5dip"
    android:singleLine
="true"
/>

  就是用来显示一条日志记录的TextView,最后两个字段指明了实际的字段映射关系,通过这个TextView来显示一条日志记录的title字段。

  处理选择日志事件

      既然有了日志列表,就自然要考虑如何处理某一条日志的单击事件,这通过重载onListItemClick方法来完成,

    @Override
    
protected void onListItemClick(ListView l, View v, int position, long id) {
        Uri uri 
= ContentUris.withAppendedId(getIntent().getData(), id);
        
        String action 
= getIntent().getAction();
        
if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {
            
// The caller is waiting for us to return a note selected by
            
// the user.  The have clicked on one, so return it now.
            setResult(RESULT_OK, new Intent().setData(uri));
        } 
else {
            
// Launch activity to view/edit the currently selected item
            startActivity(new Intent(Intent.ACTION_EDIT, uri));
        }
    }

     首先通过”content:// com.google.provider.NotePad/notes”和日志的id 号拼接得到选中日志的真正URI,然后创建一个新的Intent,其操作类型为Intent.ACTION_EDIT,数据域指出待编辑的日志URI(这里只分析else块)。

  Intent深度剖析

那么,上面这句startActivity(new Intent(Intent.ACTION_EDIT, uri))执行后会发生什么事情呢?这时候Android系统就跳出来接管了,它会根据intent中的信息找到对应的activity,在这里找到的是NoteEditor这个activity,然后创建这个activity的实例并运行。

那么,Android又是如何找到NoteEditor这个对应的activity的呢?这就是intent发挥作用的时刻了。

new Intent(Intent.ACTION_EDIT, uri)

这里的Intent.ACTION_EDIT=” android.intent.action.EDIT”,另外通过设置断点,我们看下这里的uri值:

      可以看到选中的日志条目的URI是:content://com.google.provider.NotePad/notes/1。然后我们再来看下Androidmanfest.xml,其中有这个provider

<provider android:name="NotePadProvider"
            android:authorities
="com.google.provider.NotePad"
        
/>

      发现没有?它也有com.google.provider.NotePad,这个是content://com.google.provider.NotePad/notes/1的一部分,同时

    <activity android:name="NoteEditor"
            android:theme
="@android:style/Theme.Light"
            android:label
="@string/title_note"
            android:screenOrientation
="sensor"
            android:configChanges
="keyboardHidden|orientation"
        
>
            
<!-- This filter says that we can view or edit the data of
                 a single note 
-->
            
<intent-filter android:label="@string/resolve_edit">
                
<action android:name="android.intent.action.VIEW" />
                
<action android:name="android.intent.action.EDIT" />
                
<action android:name="com.android.notepad.action.EDIT_NOTE" />
                
<category android:name="android.intent.category.DEFAULT" />
                
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
            
</intent-filter>
            
<!-- This filter says that we can create a new note inside
                 of a directory of notes. 
-->
            
<intent-filter>
                
<action android:name="android.intent.action.INSERT" />
                
<category android:name="android.intent.category.DEFAULT" />
                
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
            
</intent-filter>
        
</activity>

上面第一个intent-filter中有一个action 名为android.intent.action.EDIT,而前面我们创建的Intent也正好是Intent.ACTION_EDIT=” android.intent.action.EDIT”,想必大家已经明白是怎么回事了吧。

  下面就进入activity选择机制了:

  系统从intent中获取道uri,得到了content://com.google.provider.NotePad/notes/1,去掉开始的content:标识,得到com.google.provider.NotePad/notes/1,然后获取前面的com.google.provider.NotePad,然后就到Androidmanfest.xml中找到authoritiescom.google.provider.NotePadprovider,这个就是后面要讲的contentprovider,然后就加载这个content provider

        <provider android:name="NotePadProvider"
            android:authorities
="com.google.provider.NotePad"
        
/>

在这里是NotePadProvider,然后调用NotePadProvidergettype函数,并把上述URI传给这个函数,函数返回URI所对应的类型(这里返回Notes.CONTENT_ITEM_TYPE,代表一条日志记录,而CONTENT_ITEM_TYPE = " vnd.android.cursor.item/vnd.google.note ")。

   @Override
    
public String getType(Uri uri) {
        
switch (sUriMatcher.match(uri)) {
        
case NOTES:
            
return Notes.CONTENT_TYPE;
        
case NOTE_ID:
            
return Notes.CONTENT_ITEM_TYPE;
        
default:
            
throw new IllegalArgumentException("Unknown URI " + uri);
        }
}

     上面的sUriMatcher.match是用来检测uri是否能够被处理,而sUriMatcher.match(uri)返回值其实是由决定的。

        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(NotePad.AUTHORITY, 
"notes", NOTES);
        sUriMatcher.addURI(NotePad.AUTHORITY, 
"notes/#", NOTE_ID);


然后系统使用获得的" vnd.android.cursor.item/vnd.google.note "”android.intent.action.EDIT”androidmanfest.xml中去找匹配的activity.

  <intent-filter android:label="@string/resolve_edit">
                
<action android:name="android.intent.action.VIEW" />
                
<action android:name="android.intent.action.EDIT" />
                
<action android:name="com.android.notepad.action.EDIT_NOTE" />
                
<category android:name="android.intent.category.DEFAULT" />
                
<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
            
</intent-filter>


NoteEditor这个activityintent-filter满足上述条件,这样就找到了NoteEditor。于是系统加载这个类并实例化,运行,然后就到了NoteEditorOnCreate函数中。

新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"

2012/2/10 3:00:35 | android开发入门 | |

#25游客[注册][123.114.231.*]2017/1/25 10:35:22
可以发下代码吗。不胜感激。953797234@qq.com
#24游客[注册][112.96.37.*]2016/12/28 9:27:57
可不可发一下代码,不胜感激1696837065@qq.com
#23游客[注册][112.96.37.*]2016/12/28 9:22:46
快乐
#22游客[注册][119.4.186.*]2016/6/15 14:23:04
可不可发一下代码,不胜感激1415410443@qq.com
#21发帖][180.98.165.*]2016/5/6 10:19:36
楼主,对增删功能的实现代码有很多疑惑,能看一下工程么,架构一些的还是没弄明白,邮箱943051230@qq.com,不胜感激
#20游客[注册][122.192.239.*]2015/4/26 19:48:42
楼主,你好,我是刚刚接触安卓开发的,能不能把这个发给我邮箱吗
1083611303@qq.com,感激不尽!
#19candykk2015/4/22 17:39:39
hao
#18游客[注册][114.255.122.*]2015/1/8 15:14:02
你好,我也是安卓初学者,能不能参考一下你的工程源码啊,邮箱992494897@qq.com,谢谢楼主,不胜感激
#17游客[注册][183.250.211.*]2014/12/16 9:59:27
你好,我android刚刚入门,能把工程发到我的邮箱吗?emma_1chan@126.com。十分感谢!
#16游客[注册][61.153.150.*]2014/12/8 15:52:52
你好,楼主,能否要一下你的工程文件学习下,不胜感激 470121406@qq.com
#15游客[注册][117.184.107.*]2014/8/22 9:46:40
你好,我android刚刚入门,能把工程发到我的邮箱吗?931376517@qq.com。十分感谢!
#14游客[注册][58.59.0.*]2014/8/2 17:15:15
亲,能学习下你的源码吗,1397184207@qq.com,谢谢
#13adang2014/5/27 23:06:40
楼主你好,我android刚刚入门,你的例子很不错,可以共享学习下吗,我的邮箱393723714@qq.com。十分感谢!
#12游客[注册][182.138.127.*]2014/5/21 7:39:18
你好,我android刚刚入门,能把工程发到我的邮箱吗?812038024@qq.com。十分感谢!
#11游客[注册][115.200.150.*]2014/5/11 13:46:20
549823854@qq.com 求发源码
#10alisa2014/5/7 11:22:30
楼主写的很详细,能把demo发出来吗。或者发我邮箱328536472@qq.com,感激不尽
#9游客[注册][61.155.4.*]2014/5/7 11:18:18
能把楼主的Demo发我邮箱吗,分析的很好,328536472@qq.com,感激不尽
#8lzq06302014/4/17 10:31:01
楼主的 写的很好 我很喜欢 可以把工程发我邮箱吗870755880@qq.com 感激不尽!谢谢!
#7游客[注册][122.227.213.*]2014/3/19 19:36:10
楼主,才开始学android,还不是看的很懂 能把你的demo发给我吗? 526373150@qq.com 不胜感激
#6游客[注册][61.180.201.*]2014/3/3 9:32:18
谢谢博主无私分享,对新手意义很大。
#5游客[注册][183.237.4.*]2014/2/21 11:08:36
你好,我android刚刚入门,想看一下你的demo,能发到我的邮箱吗?542681172@qq.com。十分感谢!
#4游客[注册][113.235.121.*]2013/5/24 9:54:20
楼主,对增删功能的实现代码有很多疑惑,能看一下工程么,架构一些的还是没弄明白,邮箱ilikezss@163.com,不胜感激
#3游客[注册][60.247.35.*]2012/12/21 16:44:03
可以把工程发我邮箱吗1522039180@qq.com 感激不尽!
#2游客[注册][112.228.43.*]2012/8/6 17:48:32
楼主啊,写的很好很详细,只是剩下的呢
#1游客[注册][59.52.229.*]2012/3/8 12:34:41
博主 很喜欢你的博客 本人刚入门 能推荐几本android的书么或学习方法
回复做一个小软件,边做边学,比啥都强。
  • 发表评论