12.1.进程的优先级

12.1.1.概述

Android规定:进程的优先级分为以下五个级别,如图-1所示:

图-1

1、前台进程-Activteprocess

Active(前台)process是包含(与用户交互的)控件的那种应用程序。这些是Android通过回收资源来极力保护的进程。Activeprocess包括:

(1)处于“active”状态的Activity,它们运行在前台来响应用户的事件。

(2)ActivityService或者正在执行onReceive事件处理函数的BroadcastReceiver。

(3)正在执行onStart,onCreate,OnDestroy事件处理函数的Service。

2、可见进程-VisibleProcess

可见但不活动的进程是那些拥有“可见”Activity的进程。“可见”Activity是那些在屏幕上可见,但不是在前台或不响应用户事件的Activity。这种情况发生在当一个Activity被部分遮盖的时候(被一个非全屏或者透明的Activity)。可见进程只在极端的情况下,才会被杀死来保证ActiveProcess的运行。包括以下情况:

(1)可见的Activity,但处于暂停(onPause())状态;

(2)被可见Activity绑定的Service

3、服务进程Serviceprocess

进程中包含已经启动的Service。Service以动态的方式持续运行但没有可见的界面。因为Service不直接和用户交互,它们拥有比visibleProcess较低的优先级。它们还是可以被认为是前台进程,不会被杀死,直到资源被active/visibleProcess需求。

4、背景进程Backgroundprocess

进程中的Activity不可见和进程中没有任何启动的Service,这些进程都可以看作是后台进程。在系统中,拥有大量的后台进程,并且Android按照后看见先杀掉的原则来杀掉后台进程以获取资源给前台进程。

5、空进程-Emptyprocess

为了改善整个系统的性能,Android经常在内存中保留那些已经走完生命周期的应用程序。Android维护这些缓存来改善应用程序重新启动的时间。这些进程在资源需要的时候常常被杀掉。

当一个进程被杀掉,进程保留,变成空进程。

12.1.2.设置/取消Service为前台进程的方法

由上所述,Service排在进程的第三优先级,通常耗时的操作是放在线程中,那么将这样的线程放在Service中将会有较高的优先级,降低被Android系统杀掉的几率。

若是将线程放在Activity中,当Activity被完全遮盖,处于onStop状态时,其进程的优先级别降为第四级。明显不如放在处于第三级别的Service中更保险。

应用场景,如音乐播放器,通过在前台做其它操作时,音乐播放器在后台播放音乐,这种情况将播放音乐的线程放在Service中是适宜的。

Service类中有两个方法,分别用来设置Service为前台进程和取消前台进程。被设置为前台进程的Service拥有最高的优先级别,被Android系统杀掉的几率降至最低。

1startForeground(intid,Notificationnoti);

作用:设置Service对象为前台进程。

说明:

第一个参数是通知的id值。

第二个参数是通知对象。

startForegroud方法的参数与通知管理器相同,使用上也类似,都是发送一个通知,并指定该通知对象的id值。

2stopForeGround(intid);

作用:取消(指定id值所通知的Service对象)前台进程。

12.1.3.设置Service为前台进程的步骤

步骤1Service类的onStartCommand方法中(通常在该方法中)创建Intent对象,并指定与其绑定的Activity,示例代码如下:

IntentforeIntent=newIntent(this,MainActivity.class);

步骤2创建PendingIntetn对象

PendingIntentpintent=PendingIntent.getActivity(

this,0,foreIntent,PendingIntent.FLAG_UPDATE_CURRENT);

说明:第四个参数指明在通知栏随时刷新通知。

步骤3创建通知对象,示例代码如下:

Notificationnoti=newNotification(

R.drawable.icon,"notification",System.currentTimeMillis());

说明:

第一个参数是通知栏中显示的本通知的图标。

第二个参数是通知栏中显示的本通知的标题。

第三个参数是本通知发出的时间。

步骤4将此通知放到通知栏的(Ongoing)正在运行组中,示例代码如下:

noti.flags=Notification.FLAG_ONGOING_EVENT;

步骤5设置通知的点击事件,示例代码如下:

noti.setLatestEventInfo(this,"title","content",pintent);

步骤6向指定的Activity发送通知,并设置当前的Service对象为前台进程,示例代码如下:

startForeground(97789,noti);

12.1.4.示例

运行图-1所示的窗口:

图-2

1、单击图-1中的startforeground按钮,将启动一个Service对象,并设置改Service为前台进程,在该在日志窗口中出现图-2中红框内的第一行信息。

2、单击图-2中的stopforeground按钮,将取消Service的当前进程,并在日志窗口中显示图-2中红框内的第二行信息。

以下列出关键代码:

步骤1创建项目exer12_01,包名为com.tarena.exer12_01,项目入口:MainActivity类,该中关键代码如下所示:

@Override

publicvoidonClick(Viewv){

//创建Intent对象,并设置目标组件为MyService

Intentintent=newIntent();

intent.setClass(this,MyService.class);

switch(v.getId()){

caseR.id.btnStartFore:

//设置intent.action的值为Constant.ACTION_FORE

intent.setAction(Constant.ACTION_FORE);

startService(intent);//启动服务

break;

caseR.id.btnStopFore:

//设置intent.action的值为Constant.ACTION_STOP_FORE

intent.setAction(Constant.ACTION_STOP_FORE);

startService(intent);

break;

caseR.id.btnStopService:

stopService(intent);//停止服务

break;

}

}

步骤2src/com.tarena.exer12_01包下创建MyService.java该类继承自Service类。关键代码如下所示:

@Override

publicintonStartCommand(Intentintent,intflags,intstartId){

Stringaction=intent.getAction();

if(Constant.ACTION_FORE.equals(action)){

Log.i(tag,"startForeground");

IntentforeIntent=newIntent();

foreIntent.setClass(this,MainActivity.class);

PendingIntentpintent=PendingIntent.getActivity(

this,0,foreIntent,PendingIntent.FLAG_UPDATE_CURRENT);

Notificationnoti=newNotification(

R.drawable.icon,"notification",System.currentTimeMillis());

//将此通知放到通知栏的"Ongoing""正在运行"组中

noti.flags=Notification.FLAG_ONGOING_EVENT;

noti.setLatestEventInfo(

this,"改变Service优先级","设置serviceforeground级别",pintent);

startForeground(97789,noti);

}elseif(Constant.ACTION_STOP_FORE.equals(action)){

Log.i(tag,"stopForeground");

stopForeground(true);//取消当前服务为前台服务

}

returnsuper.onStartCommand(intent,flags,startId);

}

步骤3打开项目清单文件,注册该服务,如下代码中红框中代码所示:

<applicationandroid:icon="@drawable/icon"

android:label="@string/app_name">

<serviceandroid:name="MyService"></service>

</application>

12.2.UI与线程

12.2.1.概述

UI是英文UserInterface单词的简称。

当应用程序启动时,系统会为应用程序创建一个主线程(main)或者叫UI线程,它负责分发事件到不同的控件(例如绘画事件)以完成应用程序与AndroidUI孔庙件的交互。

例如,当触摸屏幕上的一个按钮时,UI线程会把触摸事件分发到控件上,更改状态并加入事件队列,UI线程会分发请求和通知到各个控件,完成相应的动作。

单线程模型的性能是非常差的,除非应用程序相当简单,特别是当所有的操作都在主线程中执行,比如访问网络或数据库之类的耗时操作将会导致用户界面锁定,所有的事件将不能分发,应用程序就像死了一样,更严重的是当超过5秒时,系统就会弹出应用程序无响应的对话框。

12.2.2.main线程

主线程也叫UI线程,主线程负责UI的创建,UI的刷新以及处理用户的输入事件。

提示:Android规定,Activity中的控件的刷新由主线程负责,其它线程不能直接刷新。

12.2.3.ANR术语

ANR的全称:ActivityorApplicationisnotresponding,当用户操作超过系统规定的响应时间时,会弹出ANR对话框,如图-3所示:

图-3

若选择Forceclose按钮将强制关闭当前的Activity

若选择Wait按钮将保留当前的Activity继续等待。

出现ANR的条件:

1.main线程(或称主线程)中有一个耗时操作正在执行,此时用户输入事件并且这个事件在5秒内没有得到响应,就会弹出ANR

2.广播接收者的onReceive()方法在10秒内没有执行完成,也会弹出ANR

提示:在广播接收者的onReceive方法中要避免执行耗时的操作。

12.2.4.示例-测试ANR发生的两种情况

创建项目exer12_02,在该类中创建MyReceiver类,该类是BroadcastRecevier的子类。

-4

1、单击download按钮,在主线程中执行一个循环模拟从网络下载数据的操作,该循环耗时10秒,在该循环执行过程中,在图-4的标注所指的编辑框中连续试图输入字符串,5秒后,将弹出图-3所示的ANR对话框。

2、单击sendbroadcast按钮,发送广播,然后在图-4的标注所指的编辑框内连续试图输入字符串,10秒后将弹出ANR对话框。

以下是关键代码:

步骤1创建工具类-CommonUtils.java,该类中定义了一个模拟耗时操作的循环,代码如下所示:

publicfinalclassCommonUtils{

publicstaticfinalStringACTION_RECEIVER="com.tarena.ACTION_RECEIVER";

publicstaticvoidtimeConsuming(intn){

for(inti=0;i<n;i++){

try{

Thread.sleep(1000);

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

}

}

步骤2创建MyReceiver.java类,该类继承自BroadcastReceiver类,代码如下所示:

publicclassMyReceiverextendsBroadcastReceiver{

privatestaticfinalStringtag="MyReceiver";

@Override

publicvoidonReceive(Contextcontext,Intentintent){

Log.i(tag,"onReceiver");

CommonUtils.timeConsuming(15);

}

}

步骤3以下是MainActivity.java类的代码,该代码负责发送广播,模拟下载的耗时操作,代码如下所示:

publicclassMainActivityextendsActivityimplementsOnClickListener{

TextViewmTextView;

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

mTextView=(TextView)findViewById(R.id.tv);

//实例化按钮对象

ButtonbtnDownload=(Button)findViewById(R.id.btnDownload);

ButtonbtnSendBraodcast=(Button)findViewById(R.id.btnSendBroadcast);

//注册按钮对象的单击事件

btnDownload.setOnClickListener(this);

btnSendBraodcast.setOnClickListener(this);

}

//实现按钮的单击事件

@Override

publicvoidonClick(Viewv){

switch(v.getId()){

caseR.id.btnDownload://下载按钮

CommonUtils.timeConsuming(10);//模拟(耗时10秒的)下载

mTextView.setText("finished");

break;

caseR.id.btnSendBroadcast://发送广播按钮

//发送广播

Intentintent=newIntent(CommonUtils.ACTION_RECEIVER);

sendBroadcast(intent);

mTextView.setText("finished");

break;

}

}

}

12.3.Message对象

12.3.1.概述

Message类用于存放消息,该类通常与Handler类配合使用。

12.3.2.常用属性

1intarg1:存放一个int类型的数据。

2intarg2:存放一个int类型的数据。

3intwhat:存放一个int类型的数据。

4Objectobj:存放任意类型的对象。

12.3.3.示例代码

Messagemsg=newMessage();

msg.what=1;

msg.arg1=100;

msg.obj=”hello”;

msg.obj=newRunnable();

12.4.Handler更新UI

12.4.1.概述

由以上所述,在主线程中不宜执行耗时操作,因此,通常的耗时操作都放在其它线程中,Androidghi称这样的线程为workthread(工作线程)。但Android还规定:只有主线程才能修改Activity中的控件,其它线程不能修改。

解决以上问题有多种方法,本节介绍如何通过Handler类提供的方法解决工作线程不能直接修改UI的问题。

Handler修改主线程UI的思路:Handler对象通过在工作线程中发送消息,该消息发送至消息对列中,等待处理。

在主线程中从消息对列中接收消息,根据消息中的信息决定如何更新主线程中UI.

12.4.2.常用方法

1sendEmptyMessage(intwhat);

作用:从workthead(工作线程)向主线程发送一个空消息。

说明:若多个线程向主线程发送消息,则参数what用于区别不同的线程。

2sendEmptyMessageAtTime(intwhat,longuptime);

作用:从workthead(工作线程)按指定时间发送空消息。

说明:第二个参数uptime:指定的时间。

3sendEmptyMessageDelayed(intwhat,longdelay);

作用:从workthead(工作线程)延迟发送空消息。

说明:第二个参数用于指定延迟的时间,单位:毫秒。

5sendMessage(Messagemsg);

作用:从workthead(工作线程)向主线程发送消息;

说明:msg是存放消息数据的对象。

6sendMessageAtTime(Messagemsg,longuptime);

作用:从workthead(工作线程)按指定时间向主线程发送消息

7sendMessageDelayed(Messagemsg,longdelay);

作用:从workthead(工作线程)延迟指定时间向主线程发送消息。

8handleMessage(Messagemsg);

作用:接收并处理从workthread发送的消息。

说明:参数-msgsend***Message发送过来的消息对象。

图-5Android处理消息机制的示意图:

图-5

图-5显示了Android系统提供了一个称为Looper(循环对列)用来管理消息对列,各线程通过Handler类的Send***Message命令将消息发送至消息对列,Looper再将消息对列中的消息依次交给主线程处理。

12.4.3.示例

从两个工作线程向主线程发送不同的消息,主线程接收消息并显示不同的处理信息。

步骤1、以下是Activity类中的onClick()方法中的代码,该方法用于处理按钮单击事件。

@Override

publicvoidonClick(Viewv){

switch(v.getId()){

caseR.id.btnDownload://若单击了标题为下载的按钮

//创建一个workthread(工作线程)线程对象

newThread(){

publicvoidrun(){

//以下一行代码模拟下载进度,执行时间约为10

CommonUtils.timeConsuming(10);

//创建消息对象

Messagemsg=newMessage();

//CommonUtils.FLAG_DOWNLOAD值代表下载操作

msg.what=CommonUtils.FLAG_DOWNLOAD;

msg.obj="downloadfinished";

mHandler.sendMessage(msg);//发送消息

};

}.start();//启动线程

break;

caseR.id.btnUpdate://若单击了标题为更新的按钮

//创建一个workthread(工作线程对象)

newThread(){

publicvoidrun(){

//以下一行代码模拟更新进度,执行时间约为10

CommonUtils.timeConsuming(8);

//创建消息对象

Messagemsg=newMessage();

//CommonUtils.FLAG_UPDATE代表更新操作

msg.what=CommonUtils.FLAG_UPDATE;

msg.obj="updatefinished";

mHandler.sendMessage(msg);//发送消息

};

}.start();//启动线程

break;

}

}

步骤2、以下是在Activity.onCreate()方法中(主线程)中创建的Handler对象-mHandler

ButtonbtnDownload.setOnClickListener(this);

ButtonbtnUpdate.setOnClickListener(this);

mHandler=newHandler(){

@Override

publicvoidhandleMessage(Messagemsg){

switch(msg.what){

caseCommonUtils.FLAG_DOWNLOAD:

mTextView.setText(下载结束);

break;

caseCommonUtils.FLAG_UPDATE:

mTextView.setText(更新结束);

break;

}

}

说明:

1CommonUtils是一个自定义的工具类,该类中包括以下两个int类型的常量:

publicstaticfinalintFLAG_DOWNLOAD=1;

publicstaticfinalintFLAG_UPDATE=2;

2msgworkthread线程发送过来的消息对象,该线程代码在步骤1中列出。

3、若msg.what的值是CommonUtils.FLAG_DOWNLOAD,则在标签中显示:下载结束。

msg.what的值是CommonUtils.FLAG_UPDATE,则在标签中显示:更新结束。

12.4.发送Runnalbe对象-更新UI

12.4.1.概述

1Runnable接口

该接口的源代码如下所示:

publicinterfaceRunnable{

publicvoidrun();

}

Java规定:一个线程要实现Runnable中的run方法。Android的线程也同样如此。在new一个Thread时,查看Android源代码,将发现内部代码也是要创建一个Runnable的对象,并实现run方法。

2Handler.post()方法

Handler类中有一个方法:post(Runnabler);

作用:将Runnable对象作为参数发送至消息对列中,以下是post方法的源代码:

publicfinalbooleanpost(Runnabler)

{

returnsendMessageDelayed(getPostMessage(r),0);

}

由上代码可知,Runnable对象r被当作消息的第一个参数发送至消息队列,然后由Looper交给主线程处理,如图-5所示。

根据以上原理,Runnable.run中的代码可以在主线程中运行,那么在Runnable.run方法中可以编写更新主线程UI的代码。

12.4.2.示例

在按钮单击事件方法中创建一个工作线程,在该线程中先模拟下载操作,操作结束后,向主线程发送了一个实现Runnable的内部匿名类,代码如下所示:

publicvoidonClick(Viewv){

switch(v.getId()){

caseR.id.btnDownload:

//创建Handler对象

finalHandlerhandler=newHandler();

//new一个工作线程模拟下载操作

newThread(){

publicvoidrun(){

CommonUtils.timeConsuming(5);//模拟下载操作

/*下载结束后,

*Runable的内部匿名类的代码

*当作消息中的第一个参数发送至消息对列,

*再由Looper交给主线程执行*/

handler.post(newRunnable(){

@Override

publicvoidrun(){

mTextView.setText("downloadfinished");

}

});

};

}.start();//启动工作线程

break;

caseR.id.btnUpdate:

break;

}

}

12.5.runOnUiThread()发送Runnable对象

12.5.1.概述

Activity类中提供了一个runOnUiThread方法,该方法封装了Handler.post方法,因此作用与Handler.post相同。

12.5.2.示例

runOnUiThread方法发送Runnable对象,让主线程执行该对象中的run方法。示例代码如下:

//new一个工作线程

newThread(){

publicvoidrun(){

CommonUtils.timeConsuming(8);//模拟更新操作

//创建一个Runnable接口的实例

Runnableaction=newRunnable(){

//实现run方法,在该方法中可修改UI

@Override

publicvoidrun(){

mTextView.setText("updatefinished");

}

};

//action对象发送至消息对列,交由主线程执行run方法中的代码

runOnUiThread(action);

};

}.start();//启动线程

12.6.View.post()发送Runnable对象-更新UI

12.6.1.概述

View类中也提供了发送Runnable对象至消息对列,然后由Looper交给主线程的方法:

1Post(Runnabler);

2postDelayed(Runnabler,longdelayMillis);

作用:延迟指定时间,再将r对象发送至主线程执行。

12.6.2.示例

@Override

publicvoidonClick(finalViewv){

switch(v.getId()){

caseR.id.download:

newThread(){

publicvoidrun(){

CommonUtils.timeConsuming(1);

Runnableaction=newRunnable(){

@Override

publicvoidrun(){

mTextView.setText("下载完成");

}

};

//v-当前的按钮对象,延迟1秒发送action对象由主线程执行

v.postDelayed(action,1000);

}

}.start();

break;

caseR.id.update:

newThread(){

publicvoidrun(){

CommonUtils.timeConsuming(8);

Runnableaction=newRunnable(){

@Override

publicvoidrun(){

mTextView.setText("更新新闻完成");

}

};

/v-当前的按钮对象,延迟3秒发送action对象由主线程执行

v.postDelayed(action,3000);

}

}.start();

break;

12.7.post总结

12.7.1.概述

Android提供了post方法,将Runnable对象(当作消息中的第一参数)发送至消息对列,然后由Looper将消息对列中的消息交给主线程执行。如此,就可以在Runnable.run中编写修改UI的代码。但要注意:不要在run方法中编写耗时操作的代码。耗时的代码要放在工作线程的run方法中运行。以下列出已介绍过的post的方法

1、runOnUiThread(Runnable):该方法对handler.post进行了封装。

2、View.post(Runnable):运行被选择的控件对象发送Runnable对象。

3、Handler.post(Runnable)

4、View.postDelayed(Runnable,long):延迟发送

5、Handler.postDelayed(Runnable,long):延迟发送

12.7.2.Handler.postrunOnUiThread的比较

1.Handler可以实现线程间消息通讯。

2.在代码的可读性和性能(创建对象的个数)方面,Handler都更有优势。

12.8.AsyncTask更新UI

12.8.1.概述

前面我们采用的都是new一个线程对象,采用这种匿名线程的方式存在以下缺陷:

第一,线程的开销较大,如果每个任务都要创建一个线程,那么应用程序的效率要低很多;

第二,线程无法管理,匿名线程创建并启动后就不受程序的控制了,如果有很多个请求发送,那么就会启动非常多的线程,系统将不堪重负。另外,在工作线程中更新UI还必须要引入handler,这让代码看上去非常臃肿。

为了解决这一问题,引入了AsyncTaskAsyncTask的特点是任务在主线程之外运行,而回调方法是在主线程中执行,这就有效地避免了使用Handler带来的麻烦。阅读AsyncTask的源码可知,AsyncTask是使用java.util.concurrent框架来管理线程以及任务的执行的,concurrent框架是一个非常成熟,高效的框架,经过了严格的测试。这说明AsyncTask的设计很好的解决了匿名线程存在的问题。

AsyncTask是抽象类,子类必须实现抽象方法doInBackground(Params...p),在此方法中实现任务的执行工作,比如连接网络获取数据等。通常还应该实现onPostExecute(Resultr)方法,因为应用程序关心的结果在此方法中返回。

提示:AsyncTask一定要在主线程中创建实例。

AsyncTask定义了三种泛型类型ParamsProgressResult

(1)Params启动任务执行的输入参数,比如HTTP请求的URL

(2)Progress后台任务执行的百分比。

(3)Result后台执行任务最终返回的结果,比如String

12.8.2.常用方法

AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,需要注意的是这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。在任务的执行过程中,这些方法被自动调用。

1、onPreExecute();

作用:当任务执行之前开始调用此方法,可以在这里显示进度对话框。
2doInBackground(Params...);

作用:在后台线程执行,执行耗时操作。在执行过程中可以调用publicProgress(Progress...)来更新任务的进度。

提示:publicProgress()相当于Handler.sendmessage()方法

3onProgressUpdate(Progress...);

作用:此方法在主线程执行,用于显示任务执行的进度。
4onPostExecute(Result);

作用:此方法在主线程执行,任务执行的结果作为此方法的参数返回。

12.8.3.示例

AsyncTask实现图-6效果,当单击dwonload按钮后,在进度条中显示模拟的下载进度,并在标签中显示进度的百分比。下载结束后显示downloadfinised

图-6a 图-6b

publicclassMainActivityextendsActivityimplementsOnClickListener{

HandlermHandler;

ProgressBarmProgressBar;//声明进度条

TextViewmTextView;//标签:显示进度的百分比和操作的结果

@Override

publicvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

//实例化各控件

mProgressBar=(ProgressBar)findViewById(R.id.progressBar);

mTextView=(TextView)findViewById(R.id.tvMessage);

ButtonbtnDownload=(Button)findViewById(R.id.btnDownload);

ButtonbtnUpdate=(Button)findViewById(R.id.btnUpdate);

//注册按钮的单击事件

btnDownload.setOnClickListener(this);

btnUpdate.setOnClickListener(this);

}

//实现按钮的单击时间事件

@Override

publicvoidonClick(Viewv){

switch(v.getId()){

caseR.id.btnDownload:

//创建对象

MyAsyncTaskmyAsyncTask=newMyAsyncTask();

myAsyncTask.execute(null);//执行任务

break;

caseR.id.btnUpdate:

break;

}

}

privateclassMyAsyncTaskextendsAsyncTask<URL,Integer,String>{

//UI中执行,更新UI

@Override

protectedvoidonProgressUpdate(Integer...values){

mProgressBar.setProgress(values[0]);

if(values[0]<100){

mTextView.setText("progress="+values[0]+"%");

}

}

//现在workthread中执行耗时操作

@Override

protectedStringdoInBackground(URL...params){

for(inti=0;i<100;i++){

publishProgress(i+1);//onProgressUpdate发送消息

try{

Thread.sleep(100);

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

return"downloadfinished";

}

//doInBackground结束后,执行本方法,resultdoInBackground方法返回的数据

@Override

protectedvoidonPostExecute(Stringresult){

mTextView.setText(result);

}

}

}

12.9.软件开发术语

12.9.1性能

临时对象越多,垃圾回收(GC)的频率越高

GC占用CPUCPU被占用时,无法响应用户的操作

用户感觉到卡,影响用户体验。

12.9.2资源池

存放一定数量的同样类型的对象,当程序需要使用时,可以从资源池中获取,使用完成,收回资源池。

等待下一次被使用。

示例:从资源池中获取Message对象。

Messagemsg=Message.obtainMessage();

提示:若之前没有创建过Message,则创建给对象。Android系统会在适当时候回收该对象,方便下次取用。

提示:解决性能问题的前提是不能影响功能。


更多相关文章

  1. Android---多线程的处理
  2. Android JNI开发详解(7)-线程操作,异常处理
  3. Android线程与进程(二)线程详解
  4. AsyncTask,IntentService工作原理分析&Android线程池
  5. Android中用AsyncTask简单实现多线程
  6. 微软发布 mircosft remote desktop for android
  7. Android 线程池框架、Executor、ThreadPoolExecutor详解

随机推荐

  1. 项目打包后出现第三方JAR包找不到
  2. oauth 授权显示无权访问页面问题的解决方
  3. Android(安卓)NDK 开发+cygwin 的安装 +e
  4. Android(安卓)RIL源码研究笔记 の ril_co
  5. Android(安卓)触摸事件
  6. Android(安卓)Fillder工具网络监测
  7. Android(安卓)studio for mac 的一些常用
  8. 【短信】短信模块的多平台适配
  9. Android(安卓)深入理解Android中的自定义
  10. [置顶] Android开发者社区