刘关张三人在茅房外听孔明讲述了Android各界面控件的使用方法。等孔明好不容易讲完的时候,不觉之间天已大亮。
刘备好奇道:“诸葛先生一直在茅房里,难道这么一直上厕所不会累的吗?”
孔明说:“嘿嘿,我特意我的茅坑上加了个掏空的椅子改装成了坐式的,茅房里电视冰箱厨具装饰品应有尽有,进茅房之前我还沏了壶茶,煮了碗拉面,别说待上一个晚上,就是在这里待上几天我都不会累!”
刘备感叹道:“看来先生真是一位特别讲究如厕情趣的男人!刚才我听先生讲解时闻到一阵清香,我还以为大牛如先生这般境界,如厕的味道都不比常人,现在想想原来是拉面味……真是想不到一个简单的茅房竟然被诸葛先生改造的如此奢华!”
孔明说:“嘿嘿,其实方法很简单,我就是把茅厕挪到卧室里了……好了,不要拍没有意义的马屁了,我能教你们的都已经教给你们了,没什么事的话你们就散了吧。”
刘备急道:“我等三人远道而来探访先生就是想向先生求教Android开发之道,如今还有很多不会的,还望先生指教哇!”
张飞问道:“大哥?我们不就走了50米吗?为啥是远道而来?”
孔明不耐烦道:“不管你们近道还是远道,现在天都亮了,我也到点该睡觉了呀!”说完就传来了阵阵呼噜声,也不知是真睡还是假睡着了。
张飞说:“这厮好没礼貌,这半天连个面都不露,倒头就睡。大哥,现在怎么办?”
刘备无助的看了看关羽,关羽捋了捋胡子,说道:“做开发,人品很重要!我们不如就在此休息一下,等诸葛先生醒了我们再请教不迟。”
刘备赞道:“楼上正解!”
于是三人席地而睡,抱作一团。
三人醒过来的时候已是晚上。茅房里传来孔明的声音:“醒了?”
刘备奇道:“先生真乃神人,为何知道我们醒了?”
孔明说:“唉,本来这个世界充满了呼噜声,后来这个世界安静了,我就知道你们醒了……醒了就赶紧走吧,吵得我心情好烦躁,上个厕所都不得安宁”
刘备说:“前面先生介绍了Android的界面控件,我们受益匪浅,不过光会这些控件使用好像远远不够啊,听说Android的Activity异常重要,求先生再指点一二!”
孔明无奈道:“唉,没办法,看你们这么沉迷,那我再给你们透露一下Android的Activity开发的小秘密,听完了可就得乖乖给我走人哈!”
刘备一副阴谋得逞的表情说道:“一定一定!”
Activity是Android的MVC架构中的Controller,即控制器,是整个架构的关键。因此学好Activity非常地重要,前面的几章我们在示例工程的时候都有创建Activity,但是这章我们来详细的介绍一下Activity。
Activity是Android程序的四大组件之一,Activity是Android程序的表示层,我们可以简单地把程序的每一个显示屏幕理解成一个Activity,学过WEB开发的读者,可以把Activity理解成网页中的一个JSP文件,或者你可以把它理解成一个Windows的窗口,它是应用程序与用户发生交互的地方。
孔明:Android四大基本组件分别是Activity(活动),Service(服务),Content Provider(内容提供者),BroadcastReceiver(广播接收器)。 |
一个应用程序通常都包含一个或多个Activity。Activity之间的相互协作构成了整个应用程序的完整存在。Activity主要有以下两个非常重要的功能:
l 显示指定的视图组件
通过Activity的setContentView()方法将xml布局文件或视图组件设置为Activity的布局。
l 接收与分发用户事件
Activity接收用户与应用程序交互产生的点击,触摸等事件,接收到事件之后分发给相应的视图组件,由各组件的监听器进行处理。
开发者在编写自己的应用界面时往往先需要继承Activity类,重写相应的方法从而完成自定义的功能。在之前的章节中,我们用到的Activity都重写过了onCreate()方法,此方法是在Activity创建的时候被调用的,因此我们可以把初始化的操作放到这个方法里面执行,除此之外,Activity还有许多方法,下面几节我们来一一介绍!
Activity是Android API中的类,是Context类的子类,它是Android的四大组件之一,是构建Android应用的基石。Android手机的一切活动,包括打电话,玩游戏等都与Activity离不开关系。
1.2.1. Activity生命周期
在Android中,系统会创建Activity的栈来管理Activity。栈的特性是后进先出,因此可以用来恢复上一个Activity,也就是当用户按返回键时在系统中就会进行一个弹出操作,来展示用户之前的Activity。Activity拥有四种基本状态,分别是:
Active/Runing即活动状态,一个新 Activity 启动入栈后,它在屏幕最前端,处于栈的最顶端,此时它处于可见并可和用户交互的激活状态。
Paused 即处于运行但失去焦点的状态,是一种暂停的状态。当 Activity 被一个透明的对话框或者 对话框样式的 Activity 覆盖时,此时它依然与窗口管理器保持连接,系统继续维护其内部状态,所以它仍然可见,但它已经失去了焦点故不可与用户交互。
Stopped即停止状态,当 Activity 被另外一个 Activity 覆盖、失去焦点并不可见时,处于 Stopped状态。
Killed即结束状态,Activity 被系统杀死回收或者没有被启动时处于 Killed状态。
Activity的生命周期是由系统来控制的而不是Activity本身,与Activity的生命周期有关的方法包括:onCreate(),onStart(),onResume(),onPause(),onStop(),onDestroy(),onRestart()。从名字上可以看出以下6种方法是一一对应的,onCreate()创建与onDestroy()销毁;onStart()可见与onStop()不可见;onResume()恢复(即获取焦点)与onPause()暂停。onRestart()是当Activity被onStop()后,但是没有被onDestroy()销毁,再次启动此Activity时调用;如果被onDestroy()了,则是调用onCreate()方法。
Activity的生命周期图如6-1所示:
onRestart() |
onDestory() |
onStart() |
onCreate() |
onResume() |
onStop() |
onPause() |
图6-1 Activity的生命周期图
当Activity第一次被创建的时候,onCreate()方法被调用,再执行完初始化操作之后界面出现时onStart()方法被调用,此方法结束之后Activity进入到Paused状态,待执行完onResume()方法之后,Activity进入到Active/Running状态,当Activity被暂停,调用onPause()方法之后,Activity进入到Paused状态,当Activity 被另外一个 Activity 覆盖、失去焦点并不可见时,onStop()方法被调用,Activity进入到Stopped状态,当Activity被系统杀死回收时,onDestory()方法被调用,Activity处于Killed即结束状态。
我们再通过一个比喻来看Activity的生命周期。我们把Activity比作一本书,我们要看书,首先从书架上取出书(onCreate()),然后放到桌上(onStart()),接着打开书(onResume()),这样我们就可以看书并可以在书本上写字了。如果这时候我们要启动另一个Activity,也就是要看另一本书,首先我们放下手中的笔或者说合上书(onPause()),然后从书架上拿下另一本书(书2:onCreate()),然后把书本2放到桌上并打开(书2:onStart()、onResume())。如果书本1被书本2完全盖住了,即不可见了,就调用书本1的onStop();而如果书本2较小,没有完全盖住书本1,则不会调用。我们还可以把书本1放回书架上,即onDestroy()。
onCreate()方法在初始化时被调用,因此最适合重写这个方法来初始化开发者需要的内容;onStart()当界面出现时被调用,onResume()是Activity获得焦点时被调用,此后Activity进入到Active状态,因此这个方法里面最适合来写需要进行的一些恢复操作,onPause()最适合进行一些保存数据的操作,因为此后系统随时都有可能销毁Activity,onStop()和onDestroy()方法不一定会被调用,onStop()也会写一些释放界面资源的方法,onDestroy()方法的内容往往是释放占用的资源,这也是保存数据的最后关卡,过了这一步,数据就无法保存。
在前面已经提到过了,系统使用栈来管理Activity。正在运行的Activity 处在在栈的最顶端,它是运行状态的,当有新Activity进入屏幕最上端时,原来的Activity就会被压入第二层,如果它的屏幕没有被完全遮盖,那么他处于Paused状态,如果它被遮盖那么他处于Stopped状态。当然不管Activity处于哪一层,都可能在系统觉得资源不足时被强行关闭,关闭时在栈底的程序最先被关闭。
1.2.2. Activity配置详解
系统是如何得知开发者创建了一个Activity的呢?在Android中,系统提供了一个AndroidManifest.xml文件,在这个文件中,开发者需要为创建的每一个Activity进行配置,这样系统才会找到开发者定义的Activity。
在AndroidManifest.xml文件中,在application标签下面开发者必须为每一个自定义的Activity创建一个activity标签,否则,系统将报错。我们通过一个具体的示例来看一下Activity的xml文件配置。
代码清单6-1 AndroidManifest.xml:
<activity
android:name=".DialogActivity"
android:label="@string/title_activity_main">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
android:name是指Activity的名字,这个名字必须和开发者定义的类名相同。android:label是指Activity的标签,这个可以由开发者自由指定,可以是string.xml文件中的一个字符串。<intent-filter>标签告诉系统该Activity将如何被调用。<actionandroid:name="android.intent.action.MAIN"/>是指该Activity作为应用程序的入口,<category android:name="android.intent.category.LAUNCHER"/>是指由系统来启动这个Activity,当用户点击应用图标时会启动这个Activity。
Activity还有许多其他的配置,我们列表如下:
属性名 | 属性值 |
android:screenOrientation | 这个属性用于设置Activity在设备上显示的方向。默认是由系统来选择,landscape是横向的,portrait是竖向的。 |
android:stateNotNeeded | 这个属性用于设置在没有保存Activity状态的情况下,Activity能否在被销毁后成功的重启。如果设置为true,则不引用Activity之前的状态就能够被重启,如果设置为false,重启Activity时,则需要它之前的状态。默认值是false。 |
android:process | 这个属性用于设置Activity运行时特定的进程名字。通常,应用程序的所有组件都运行在为这个程序所创建的一个默认的进程中。它跟应用程序的包有相同的名字。<application>元素的process属性能够给所有的组件设置一个不同的默认值。但是每个组件都能够覆盖这个默认设置,允许把应用程序分离到多个进程中。 |
android:permission | 这个属性用于设定启动Activity的客户端或者是响应一个Intent对象的请求所必须要有的权限。如果startActivity()方法或startActivityForResult()方法的调用者没有被授予指定的权限,那么它的Intent对象就不会发送给对应的Activity。 |
android:noHistory | 这个属性用于设置在用户离开该Activity,并且它在屏幕上不再可见的时候,它是否应该从Activity的堆栈被删除。如果设置了true,则要删除,否则不删除。默认值是false。 |
android:multiprocess | 这个属性用于设置Activity的实例能否被加载到与启动它的那个组件所在的进程中,如果设置为true,则可以,否则不可以。默认值是false。 |
android:theme | activity的样式主题,如果没有设置,则从属于应用程序的样式主题。 |
孔明:你们听好了!Activity的属性配置非常复杂,使用恰当时往往会达到一些意象不到的效果,当然这需要在平时的编程中多积累经验才行啊!
|
Activity之间的交互非常重要,在Android中,一个应用程序往往有很多的Activity,这些Activity之间的相互协作才能构成一个完美的程序。本节我们来看下Activity之间到底是如何交互的,数据是如何传递的。
1.3.1. 使用Intent传递数据
通过Intent来传递数据是在Activity之间传递数据的一种常用手段,使用起来非常方便,只需要做的是在使用Intent启动另一个Activity的时候使用Intent类的方法为Intent实例增加数据,然后在目标Activity里面将数据接收即可。下面我们来讲一下如何创建Intent以及如何使用Intent来传递数据。
Intent的创建非常简单,代码示例如下:
Intent it = new Intent(MainActivity.this, SlaveActivity.class);
代码里面的第一个参数是创建Intent的Activity,第二个参数是接收Intent实例的Activity,接下来我们使用Intent的putExtra()方法来添加要传递的数据。putExtra()方法有许多重构的方法,可以满足我们添加各种类型的参数,我们以字符串类型的参数为例,添加数据的代码为如下所示:
it.putExtra("send_data","从MainActivity传过来的数据");
第一个字符串相当于一个键值对中的键,也就是key,也就是在目的Activity中取数据需要用到的一个值。第二个字符串相对于键值对中的值,是我们要实际传递的值,如果我们传递的值不是字符串类型,我们可以使用putExtra()方法的重构方法来传递不同类型的值。
上面讲到了如何在源Activity里面将数据添加到Intent里面,而数据是如何在目的Activity里面接收呢,实际上也是非常简单的。代码如下:
Intent intent =getIntent();
String text =intent.getStringExtra("send_data");
首先,需要获取Intent的实例,然后再根据发送的键值来获取数据即可,比如上面的发送Activity中以“send_data”作为键值,接收类中,就要以这个键值来获取发送的数据。完整的代码如下所示:
代码清单6-2 MainActivity.java:
/**
* Activity展示类
* @author孔明
*/
public class MainActivityextends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent it = new Intent(MainActivity.this,SlaveActivity.class);
it.putExtra("send_data","从MainActivity传过来的数据");
startActivity(it);
}
}
上面是发送Activity的类,我们只是在onCreate方法里面创建了一个Intent,然后加入要发送的数据,启动一个名为SlaveActivity的Activity。代码如下:
代码清单6-3 SlaveActivity.java:
/**
* Activity数据的接收类
* @author孔明
*/
public class SlaveActivityextends Activity {
private TextView tv1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slave);
tv1 = (TextView)findViewById(R.id.tv1);
Intent intent = getIntent();
String text =intent.getStringExtra("send_data");
tv1.setText(text);
}
}
在上面的代码中,我们将接收到的数据显示到一个TextView中,在实际的编程中,用户可以根据需要调整数据的使用方式。上面两个Activity中用的布局文件如下所示:
代码清单6-4 activity_main.xml:
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="@dimen/padding_medium"
android:text="@string/hello_world"
tools:context=".MainActivity" />
</RelativeLayout>
代码清单6-5 slave.xml:
<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</LinearLayout>
运行程序之后,MainActivity的界面将不会显示,直接跳到SlaveActivity的界面,如图6-2所示:
图6-2 Intent传递数据示意图
孔明:MainActivity界面没有显示是因为创建和启动SlaveActivity的动作是在onCreate方法里面执行的,所以MainActivity还没来得及显示就跳转到SlaveActivity了,想必你一定知道吧! |
使用静态变量来传递数据,看到这个题目,Java程序员们也就大概猜到了这个传递数据的方式是如何进行的,因为在Java中,我们会经常用到这种方法来传递数据。大体上说来就是在目的Activity中创建一个静态变量,然后在源Activity将其赋值改变即可达到传递数据的目的,比如我们在SlaveActivity中建立如下一个静态变量:
代码清单6-6 SlaveActivity.java:
/**
* Activity数据的接收类
* @author孔明
*/
public class SlaveActivityextends Activity {
staticString SLAVE = null;
privateTextView tv2;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slave);
tv2 = (TextView)findViewById(R.id.tv2);
tv2.setText(SLAVE);
}
}
然后我们在发送Activity中将SLAVE这个静态变量的值改变即可,代码如下:
代码清单6-7 MainActivity.java:
/**
* Activity展示类
* @author孔明
*/
public class MainActivityextends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SlaveActivity.SLAVE= "静态变量传递的数据";
Intent it = new Intent(MainActivity.this,SlaveActivity.class);
startActivity(it);
}
}
上面的代码中,在使用Intent启动SlaveActivity之前,我们给SlaveActivity.SLAVE,这样SlaveActivity在接收到新值之后就可以将其显示出来了,运行程序,界面如图6-2所示:
图6-2 静态变量传递数据示意图
使用剪贴板来传递数据的功能类似于Windows上的“复制+粘贴”的功能,相信大家对这个功能都非常的熟悉。
那么按照上述的原理呢,我们需要在发送类里面做的工作是获取Android系统的剪贴板,然后将数据添加到剪贴板上去,在接收类里面要做的工作是获取剪贴板,然后获取剪贴板上的数据。代码如下:
代码清单6-8 MainActivity.java:
/**
* Activity展示类
* @author孔明
*/
public class MainActivityextends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ClipboardManager cm =
(ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
cm.setText("剪贴板传递的数据");
Intent it = new Intent(MainActivity.this,SlaveActivity.class);
startActivity(it);
}
}
在上面的代码中,我们使用getSystemService()方法来获取了剪贴板实例,然后将数据设置到剪贴板上去,最后启动SlaveActivity。
代码清单6-9 SlaveActivity.java:
/**
* Activity数据的接收类
* @author孔明
*/
public class SlaveActivityextends Activity {
private TextView tv4;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slave);
tv4 = (TextView)findViewById(R.id.tv4);
ClipboardManager cm =
(ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
tv4.setText(cm.getText());
}
}
上面的代码中,我们首先获取了剪贴板的实例,然后获取剪贴板上的数据,最后将数据显示到TextView上,界面如图6-3所示:
图6-3 剪贴板传递数据示意图
1.3.4. 使用Application传递数据
使用Application来传递数据更具有一般性。我们在这个过程中需要创建自定义的Application类,然后在自定义的Application类里面增加我们需要传递的数据。为了演示传递数据的过程,我们编写了如下自定义Application类:
代码清单6-9 MyApp.java:
/**
* 自定义App示例类
* @author孔明
*/
public class MyApp extends Application {
privateString myString;
publicString getMyString() {
returnmyString;
}
public void setMyString(String myString) {
this.myString= myString;
}
}
上面代码中的myString域就是我们要传递的数据,创建完这个类之后呢,我们同时要修改一下AndroidMenifest.xml文件,在<application>中加入一个说明,表示程序中使用的Application类是我们创建的MyApp,而不是系统自己的Application类型,代码如下:
android:name=".MyApp"
接下来的工作是在数据源Activity里面将数据添加到MyApp里面,具体来看下如何实现:
代码清单6-10 MainActivity.java:
/**
* Activity展示类
* @author孔明
*/
public class MainActivityextends Activity {
@Override
public voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyApp myApp =(MyApp)getApplicationContext();
myApp.setMyString("全局变量传递的数据");
Intent it = new Intent(MainActivity.this,SlaveActivity.class);
startActivity(it);
}
}
在上面的代码中,我们在onCreate方法里面通过getApplicationContext()方法来获取一个Application,通过强制类型转换成我们定义的MyApp类型,然后调用MyApp的setMyString方法将数据保存到MyApp中,在目标Activity中,我们只需要获取到MyApp,然后用相应的get方法就可以获取数据了,代码如下:
代码清单6-11 SlaveActivity.java:
/**
* Activity数据的接收类
* @author孔明
*/
public class SlaveActivityextends Activity {
privateTextView tv3;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slave);
tv3 = (TextView)findViewById(R.id.tv3);
MyApp myApp =(MyApp)getApplicationContext();
tv3.setText(myApp.getMyString());
}
}
运行程序之后,截图如图6-4所示:
图6-4 全局变量传递数据示意图
1.3.5. 返回数据到前一个Activity
返回数据到前一个Activity也是Activity交互中的一个非常重要的环节。在本节,我们要讲一个Android系统本身所具有的一个返回数据的方式。
要想有数据返回到一个Activity,那么我们在这个Activity启动另外一个Activity的时候要调用startActivityForResult方法,而不是startActivity。startActivityForResult方法有两个参数,第一个参数是Intent,第二个是一个int类型,代表一个需求码,即REQUEST_CODE。那么具体如何实现呢?我们来看下面代码:
代码清单6-12 MainActivity.java:
/**
* Activity展示类
* @author孔明
*/
public class MainActivityextends Activity {
staticintREQUEST_CODE = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent it = new Intent(MainActivity.this,SlaveActivity.class);
startActivityForResult(it, REQUEST_CODE);
}
@Override
protected void onActivityResult(intrequestCode, int resultCode,Intent data) {
super.onActivityResult(requestCode,resultCode, data);
if (requestCode == REQUEST_CODE) {
String text =data.getStringExtra("result_back");
Toast.makeText(this,text, Toast.LENGTH_LONG).show();
}
}
}
REQUEST_CODE是我们自行定义的,如果这个值是大于0的,那么它将在目的Activity退出的时候返回到前一个Activity的onActivityResult方法中来,因此上面的代码中,我们重写了这个方法,而返回的数据是封装到一个Intent实例中的,因此只要调用Intent相应的get方法即可获得返回的数据。
在接收的Activity里面显然需要我们将要返回的数据封装到一个Intent实例里面去了,具体实现如下所示:
代码清单6-13 SlaveActivity.java:
/**
* Activity数据的接收类
* @author关云长
*/
public class SlaveActivityextends Activity {
private TextView tv3;
@Override
public voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slave);
Intent intent = getIntent();
intent.putExtra("result_back", "从SlaveActivity返回的数据");
setResult(RESULT_OK, intent);
}
}
在接收类的onCreate方法里面获取Intent实例,并通过putExtra方法将数据设置到Intent中,最后通过调用setResult(RESULT_OK,intent)来设置将会返回的结果,其中RESULT_OK表示操作成功。因此当我们在SlaveActivity界面的时候,按下返回键或者后退键就会看到从SlaveActivity中返回的数据了,如界面6-5所示:
图6-5 返回数据到前一个Activity示意图
上面两节,我们介绍了Activity的基本原理,使用方法以及如何交互,实际上在Android系统中有一些Activity的子类。这些子类除了有Activity的功能之外还有一些其他的功能,使得在使用这些Activity子类来解决某一类问题的时候特别方便。比如下面第一小节要介绍的ListActivity在解决含有ListView布局的Activity时就非常地好用。
ListActivity是Android中Activity的子类,因此拥有Activity的所有特性,同时,ListActivity可以看做是一个Activity与一个ListView的结合体,因此我们在使用ListActivity的时候都不需要去设置ListActivity的布局了,因为默认是一个ListView。而且这个ListView的id是android:list,不能随便取名字的。因此在使用ListActivity的时候,我们只需要给ListActivity设置一个适配器以及定义事件监听器即可。我们来写一个简单的ListActivity如下所示:
代码清单6-14 SlaveActivity.java:
/**
* ListActivity展示类
* @author孔明
*/
public class ListActivityTestextends ListActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 创建ListView要用的ArrayList
List<String> items = fillArray();
// 创建并设置适配器
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, items);
setListAdapter(adapter);
}
// 创建ListView要用的ArrayList
privateList<String> fillArray() {
List<String> items = newArrayList<String>();
items.add("星期一");
items.add("星期二");
items.add("星期三");
items.add("星期四");
items.add("星期五");
items.add("星期六");
items.add("星期日");
returnitems;
}
// 设置点击事件
@Override
protected void onListItemClick(ListView l, View v, int position, longid) {
Toast.makeText(this,l.getItemAtPosition(position).toString(),
Toast.LENGTH_LONG).show();
}
}
在上面的代码中,我们在onCreate方法里面创建了一个ArrayList来填充数据,并创建了一个Adapter,并将其设置为ListView的适配器。onListItemClick是列表点击事件监听器方法,我们在这个方法中通过Toast显示点击的星期几。运行程序,界面如图6-6所示:
图6-6 ListActivity示意图
在开发Android上的应用程序以及游戏的时候经常会遇到一些需要进行设置的界面,比如是否静音,铃声选项等等。Android提供了PreferenceActivity这个类来完成这一类的工作,PreferenceActivity可以看做是Preference与Activity的结合体。
首先,我们来创建一个PreferenceActivity,这一步骤非常简单,我们新建一个类,命名为PreferenceActivityTest并使这个类继承自PreferenceActivity,那么一个PreferenceActivity就创建好了,代码如下:
代码清单6-15 PreferenceActivityTest.java:
/**
* PreferenceActivity展示类
* @author孔明
*/
public class PreferenceActivityTestextends PreferenceActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 添加配置界面使用的布局文件
addPreferencesFromResource(R.xml.pref);
}
}
需要注意的是,我们为PreferenceActivity指定布局文件的时候,这个布局文件一定要在res/xml文件夹中,并且要使用addPreferencesFromResource方法,而不是setContentView方法。
然后,我们再来看一下PreferenceActivity的xml界面文件如何定义,pref.xml的内容如下:
代码清单6-16 pref.xml:
<?xmlversion="1.0"encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 分组 -->
<PreferenceCategory android:title="短信助手">
<!-- checkbox 控件 -->
<CheckBoxPreference
android:key="smsSilence"
android:title="静音"
android:summaryOn="开启"
android:summaryOff="关闭"
android:defaultValue="false" />
<PreferenceScreenandroid:title="更多选项">
<CheckBoxPreference
android:key="sms1"
android:title="系统默认铃声"
android:summaryOn="开启"
android:summaryOff="关闭"
android:defaultValue="true" />
<CheckBoxPreference
android:key="sms2"
android:title="自定义铃声"
android:summaryOn="使用"
android:summaryOff="停用"
android:defaultValue="true" />
<!-- List 控件 -->
<ListPreference
android:key="list"
android:title="ListPreference"
android:summary="手机品牌"
android:dialogTitle="请选择品牌"
android:entries="@array/entries_list_preference"
android:entryValues="@array/entriesvalue_list_preference"/>
<!-- edittext控件 -->
<EditTextPreference
android:key="et"
android:title="EditTextPreference"
android:summary="点击输入"
android:dialogTitle="输入你最喜爱的动物的名称"
android:defaultValue="刀疤鸭" />
</PreferenceScreen>
</PreferenceCategory>
<!-- 分组 -->
<PreferenceCategory android:title="铃声设置">
<RingtonePreference
android:key="ring"
android:title="老男孩"
android:summary="选择铃声" />
</PreferenceCategory>
</PreferenceScreen>
首先,整个PreferenceActivity的界面根元素必须是PreferenceScreen,在这个根元素下面,我们可以添加许多选项。也就是说PreferenceScreen是可以嵌套的。当我们点击子PreferenceScreen的时候,将会打开一个新的界面。PreferenceCategory是用来分组的,一个完整的PreferenceCategory标签就是一组控件的集合。控件有四种,分别是CheckBoxPreference、ListPreference、EditTextPreference、RingtonePreference,分别有不同的功能。CheckBoxPreference是以复选框的形式给用户选择,ListPreference是以列表的形式供用户选择,EditTextPreference可以让用户输入一些设置,RingtonePreference使得用户可以选择铃声。
在Android系统中,我们知道配置都是按照键值对的形式存放的,因此android:key就指明了这个设置的键,也就是写到Android配置文件中的键,而实际的值是需要根据用户的选择来决定的。
android:title指的是这个配置将要显示的名称,android:summaryOn是配置是true时显示的内容,同理,android:summaryOff是配置为false时显示的内容。android:dialogTitle是显示的对话框的题目。android:defaultValue是默认状态下显示的值。在PreferenceActivity里面有的配置都将放在data/data/项目包名/shared_prefs下,名字为“包名_preferences.xml”
运行上面的程序,如图6-7所示:
图6-7 PreferenceActivity示意图
当我们点击更多选项时,一个新的界面会打开,如图6-8所示:
图6-8 PreferenceActivity更多选项示意图
点击ListPreference以及EditTextPreference时分别会出现如6-9界面:
图6-9 ListPreference示意图
图6-10 EditTextPreference示意图
孔明:既然设置的信息都被放到配置文件里面了,那么以后我们就可以到配置文件里读取这些信息。 |
1.5. Application与Activity
相对于Application来说,Activity更为大家所熟知,这是因为在编程过程中,很多时候需要用到Activity,而Application出场的机会很少,但是Application却非常有用。
首先,对于一个Android应用程序,Application有且只有一个,所以它是一个Android系统的单例模式实现的。在不同的Activity当中使用getApplication方法获得的都是同一个Application对象,而且Application的生命周期是最长的,跟应用的生命周期相同。通常我们不需要指定一个Application,因为系统会自定帮助我们创建一个,如果我们需要指定一个Application,那么我们可以继承Application创建一个子类,并在manifest的application标签中进行注册。
其次,对于一个Android应用来说,Application是一个系统组件,一个Application实例中有多个Activity、Service、ContentProvider或Broadcast Receiver,并且Application实例中保存了与应用主题,资源文件内容等全局性的变量。
最后,一个Android应用程序的启动过程,总是先启动Application,然后再启动Application下的某一个Activity。
从以上的不同点来分析,Application可以用于Activity之间的数据传递,在这个过程中Application起到了一个全局变量的作用。除此之外呢,Application还可以作为数据的缓存来使用,比如在一个与网络相关的应用当中,我们可以将网络上的数据先保存到位于Application的缓存当中,这样每次启动Activity就不用访问网络了,直接从Application里拿过来就可以用了。当然了,我们也可以使用Application来改变应用的主题等全局性的变量。
张飞:如果Activity传递的数据是多个键值对的话,该如何使用Intent进行传递呢?
刘备:这个问题我知道!首先使用bundle来绑定键值对,然后使用intent来传递bundle,一个键对应一个需要传递的值。最后通过键将bundle中的值取出来。
张飞:大哥,没看出来,你这都会呀!
刘备:三弟,你倒说说,我啥不会呀!
张飞:那么大哥,Activity这么多传递数据的方式,到底哪种好呢?
刘备:每一种都有每一种的特点,需要结合程序需要而定,比如Intent传递数据的方法特别适合两个Activity之间传递数据。而使用静态变量或者Application适合在多个Activity之间进行数据交互。
刘备:大哥威武!
张飞:三弟客气!