教程: 记事本习作之二


在这次练习中,你将会添加第二个Activity到你的记事本程序中, 使用户能创建,编辑,删除记录。这个新的activity将会采用用户输入信息来创建新纪录的方式, 本次练习将演示下面的操作:


* 构建一个新的activity,并且添加到manifest中
* 使用 startSubActivity() 异步地调用其它 activity
* 在activity中间使用bundle传递数据
* 如何使用更高级的屏幕布局


步骤一



从NotepadLab文件夹下导入Notepadv2项目, 如果你看到关于AndroidManifest.xml的错误或者一些关于android.zip文件的问题, 请在项目上右键点击,选择Android Tools -> Fix Project
打开 Notepadv2项目,并且看下面的内容:


a, 打开 res/values 下面的 strings.xml 文件-------这里有些我们要使用的新的字符串


b, 同时查看Notepadv2类顶部, 你会看到一些新的代码------一些已经定义好的常量, 为记录行而定义的成员变量(如何从列表中提取行记录)


c, 同时查看fillData()方法已经变得简单些,使用rows域来代替本地变量


d, 这里也有几个新的重载的方法(onListItemClick() 和 onActivityResult()) ), 我们要在下面填写他们。


步骤二


检查onCreate()方法, 你会发现它跟在练习一的例子中完全一样。


步骤三


我们需要添加一个删除的入口点在菜单中


a, 在 onCreateOptionMenu() 方法中,添加一行
menu.add(0, DELETE_ID, R.string.menu_delete);


b, 下面是整个方法体


@Override

public boolean onCreateOptionsMenu(Menu menu) { 
 
 super.onCreateOptionsMenu(menu); 
 
 menu.add(0, INSERT_ID, R.string.menu_insert); 
 
 menu.add(0, DELETE_ID, R.string.menu_delete); 
 
 return true; 
 
 }





步骤四


在 onMenuItemSelected() 方法中,添加一个新的 case DELETE_ID


dbHelper.deleteRow(rows.get(getSelection()).rowId);
fillData();
break;


a,使用 getSelection() 方法从 ListActivity中 查看哪个是正在选择的记录在列表中
b,它将会以行排列的形式得到行 id, 然后使用它通过DBHelper去删除一行
c,我们填写数据然后去保持一切是最新的
d,那么整个方法将看起来像下面这样


@Override

public boolean onMenuItemSelected(int featureId, Item item) { 
 
 super.onMenuItemSelected(featureId, item); 
 
 switch(item.getId()) { 
 
 case INSERT_ID: 
 
 createNote(); 
 
 fillData(); 
 
 break; 
 
 case DELETE_ID: 
 
 dbHelper.deleteRow(rows.get(getSelection()).rowId); 
 
 fillData(); 
 
 break; 
 
 }



return true;
}


步骤五


填写 createNote() 方法体


我们将创建一个新的Intent对象用来使用 NoteEidt 类创建新记录, 我们之后使用startSubActivity() 激活 intent 。


Intent i = new Intent(this, NoteEdit.class);
startSubActivity(i, ACTIVITY_CREATE);


不要为了真正的NoteEdit还不存在而担心, 我们以后填写它。

步骤6

重载onListItemClick()的方法体

这个方法是当用户从list中选择item时要相应的方法.它传递了四个参数:生成的ListView对象;点击Listview时其中的view; list上被点击的位置position,被点击的标题item的rowId.在这个例子中我们可以忽略前面2个参数(我们只有一个Listview), 我们也可忽略rowId.我们感兴趣的是用户选择的postion.我们用这个position从正确的row中选择数据,并绑定送给NoteEdit类

此法用NoteEdite 类创建一个intent,如代码中的i,来编辑note.然后可加数据到多于的bundle在intent中,可以传递信息到intent中.我们使用i 传递为了我们要编辑的文本中出现的title,body,rowId.最后, 开动intent使用startSubActivity()方法(因为intent的目的此时就是调用子活动)

super.onListItemClick(l, v, position, id);

Intent i = new Intent(this, NoteEdit.class);

i.putExtra(KEY_ROW_ID, rows.get(position).rowId);

i.putExtra(KEY_BODY, rows.get(position).body);

i.putExtra(KEY_TITLE, rows.get(position).title);

startSubActivity(i, ACTIVITY_EDIT);

a这个实现中我们使用了一个可以 传递多个参数的bundle在intent中,我们用这个bundle传递我们想编辑的文本的标题,主体,和rowId,然后在NoteEdite class上唤醒intent ACTIVITY_EDIT

b putExtra()是种可以加add items到多于的bundle中的方法,来传递到intent invocations(启用激活)中.

步骤7

createNote() 和onListItemClick()方法用了一个同时的intent的启用即都用了自活动调用.我们需要一个handler,所以我们填写onActivityResult()方法体的重载.

onActivityResult()方法当有子活动返回时被调用.参数如下

requestCode 最初的应答code(requestCode)在intent启动时特别声明过了的

resultCode调用的结果,必须是0如果一切ok,但失败时会有非0 code返回,有些标准结果可用你也可自己创造常量显示特别 问题.

data (对应extras) 单个的字符串,可以承接某些文本返回信息. (比如用户输入某些信息到

段落中,此时可以用) 若多就使用extra bundle

extras 由被调用的intent提供的多的绑定.(此处的extras表示不只一个)

this is the returned extras bundle (if any)provided by the called intent.



startSubActivity() 和onActivityResult()结合可被认为一个remote procedure call远程调用,并是个可推荐的方法使得活动可互相唤醒彼此以及services.

代码如下

super.onActivityResult(requestCode, resultCode, data, extras); 
 



 switch(requestCode) { 
 

 case ACTIVITY_CREATE: 
 

 String title = extras.getString(KEY_TITLE); 
 

 String body = extras.getString(KEY_BODY); 
 

 dbHelper.createRow(title, body); 
 

 fillData(); 
 

 break; 
 

 case ACTIVITY_EDIT: 
 

 Long rowId = extras.getLong(KEY_ROW_ID); 
 

 if (rowId != null) { 
 

 String editTitle = extras.getString(KEY_TITLE); 
 

 String editBody = extras.getString(KEY_BODY); 
 

 dbHelper.updateRow(rowId, editTitle, editBody); 
 

 } 
 

 fillData(); 
 

 break; 
 

 }



步骤8

打开note_edit.xml,这个是UI的code 为了Note Editor.是我们到现在为止见过的最复杂的

这里有个新的android:layout_weight 这里值为1

一般默认0,代表只占它们需要的空间,高于0的值将会占用剩下的可用空间根据值.比率

比如有一个文本标签和2个文本视图,标签没有这个参数,所以它占用所需的最小空间,若其他2个分别为1,则剩下的给这2个平分.

这个布局也展示了如何嵌套多层布局,来完成一个更复杂和好看的布局.

(对布局有更多兴趣的可以参看旁边小字的布局的艺术)

步骤 9

如何生成一个NoteEdit类继承自android.app.Activity

这是我们第一次创建一个活动没有用到android eclipse插件,当你这样做时,onCreate方法不会自动重载,很难想象(当然也有右键点击跳出菜单供重载或实现方法的选项)

a 先生成一个类

b在名字上写NoteEdit

c父类中写android.app.Activity

d finish

e在完成的类中,点击editor窗口 选择source--Override/Implement Methods

f翻动checklist找到onCreate点击

g ok

步骤10

继续填写onCreate()方法

这将使得新活动的标题为 Edit Note(定义在strings.xml)也将让内容视图使用note_edit.xml layout文件中.我们可以获得title和body手柄,还有按钮,这样我们的类可以使用它们设置和得到文本标题和主体,和attach一个事件对应的按钮 当这个按钮被user点击.

我们可以对这些values分类,这些values从在call的intent中的多的捆绑中来,并传递到activity中.并且用这些有值的values来预先为titles body text等分配位置,这样用户可以编辑它们.我们同时可以抓取和储存rowId这样我们可以追踪用户在处理哪些文本 notes

a 布置布局setContentView(R.layout.note_edit);

b找到我们需要的edit和按钮组件

以下是根据关联的IDs在R class中找到,需要被转化为view的对的类型

代码如下

titleText = (EditText) findViewById(R.id.title); 
 

 bodyText = (EditText) findViewById(R.id.body); 
 

 ButtonconfirmButton=(Button) findViewById(R.id.confirm);



c创建一个私有long rowId来储存当前的rowId值

d加入代码,初始化title,body和rowId 从intent的extras bundle中得到

rowId = null; 
 

 Bundle extras = getIntent().getExtras(); 
 

 if (extras != null) { 
 

 String title = extras.getString(Notepadv2.KEY_TITLE); 
 

 String body = extras.getString(Notepadv2.KEY_BODY); 
 

 rowId = extras.getLong(Notepadv2.KEY_ROW_ID); 
 



 if (title != null) { 
 

 titleText.setText(title); 
 

 } 
 

 if (body != null) { 
 

 bodyText.setText(body); 
 

 } 
 

 }


@从intent的启动的extras bundle中pulling出title和body

@有当text field为空时的处理

e为button创建一个onClickListener()

在其中创建一个onClick()方法,我们可以使用它做些事和返回被编辑的文本的值给intent的调用者.我们做这些使用一个匿名的内部类.这有点混乱除非你曾经看过这些.但你要掌握的就是将来你能认出这些code来明白如何创建一个listener和attach to一个按钮

confirmButton.setOnClickListener(new View.OnClickListener() { 
 



 public void onClick(View view) { 
 



 } 
 



 });



步骤11

添加onClick方法.

下面是code,我们希望这些code从可以编辑文本区域中得到title和body,并把这些值放入返回的bundle中这样它们可以被传递回唤醒这个 intent的前面的一个activity.如果这个操作是编辑而不是创建,我们也希望将rowId也放入bundle中,这样Notpadv2 类可以保存这些变化回到正确文本中.

a 创建一个bundle,将title和body放入其中 用定义好的常量作为keys 代码如下

Bundle bundle = new Bundle(); 
 



 bundle.putString(Notepadv2.KEY_TITLE, titleText.getText().toString()); 
 

 bundle.putString(Notepadv2.KEY_BODY, bodyText.getText().toString()); 
 

 if (rowId != null) { 
 

 bundle.putLong(Notepadv2.KEY_ROW_ID, rowId); 
 

 }



b设置结果信息,包括bundle,完成这个活动.

setResult()被用来设置返回代码,返回数据字符串,和extras bundle去给传递回去给intent调用者.

这里,所有worked,所有我们返回result_ok值代表返回代码.我们不用字符串数据在这个case中,所以我 们传递一个字符串数据空值,和传递这个bundle.这个bundle由title,body和rowId这些消息生成.



这个finish()被用来表示活动完成.所有在result中的设置都会返回给caller,连同执行控制.

setResult(RESULT_OK, null, bundle);

finish();

步骤12

在运行这个活动前,它需要自己的活动 入口在 AndroidManifest.xml 中.这是让系统知道这个活动在那里并可以被调用.我们也可以指明哪个IntentFilters赛选活动实行处,但我们也可以跳过这个只让Android知道这个活动被定义了. <activity class=".NoteEdit"/>

步骤13
Run运行吧..