您的位置:首页 > 移动开发 > Android开发

Android33_Service

2016-01-20 10:19 411 查看
Service及AIDL


一、Service:
(一)、Service 简介:

[align=left]1、何谓“Service”?[/align]

[align=left] “Service” 意思即“服务”的意思, Service是Android中实现程序后台运行的解决方案,它适合用于执行不需要和用户交互而还要求长期运行的任务。Service运行在后台,它是不可见的、无界面的程序。Service的运行不依赖于任何用户界面,承担着静悄悄的不为人所注意的工作,即使当程序被切换到后台,或者用户打开了另外一个应用程序,服务仍然能够保持正常运行。[/align]
[align=left] 但是,Service并不是运行在一个独立的进程当中的,而是依赖于创建服务时所在的应用程序进程。另外,不要被Service的后台概念所迷惑,Service不会自动开启线程,所有的代码都默认运行在主线程当中。使用Service时,如果担心主线程被阻塞,就需要在Service的内部手动创建一个子线程来执行任务。[/align]
[align=left] Service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity,这个时候程序要在后台继续播放;比如检测SD卡上文件的变化;再或者在后台记录用户的地理信息位置的改变;或者启动一个服务来运行并一直监听某种动作等等。[/align]

[align=left]【备注:】[/align]
[align=left] 三大智能手机操作系统中,IOS是不支持后台的,当应用程序不在前台运行时就会进入到挂起状态。Android则沿用了Symbian的老习惯,加入了后台功能,这样应用程序即使在关闭的情况下仍然可在后台继续运行。Windows Phone则经历了由不支持后台到支持后台的过程。目前Windows Phone8系统也具备后台功能。[/align]

[align=left]2、Service概念的总结:[/align]

Service在后台运行,不可以与用户直接交互;
一个服务不是一个单独的进程。服务对象本身并不意味着它是在自己的进程中运行,除非另有规定,否则它与运行程序是同在一个进程中;
一个服务不是一个单独的线程。Service和其他组件一样,默认情况下,Service中的所有代码都是运行在主线程中;
Service存在的价值虽然不如Activity那么清晰。但是一般都让Service执行耗时较长的操作。例如:播放音乐、下载文件、上传文件等等。但是因为Service默认运行在主线程中,因此不能直接用它来做耗时的请求或者动作,最好在Service中启动新线程来运行耗时的任务;
需要通过某一个Activity或其他Context对象来启动Service。context.startService() 或 context.bindService();
Service很大程度上充当了应用程序后台线程管理器的角色。(如果Activity中新开启一个线程,当该Acitivyt关闭后,该线程依然在工作,但是与开启它的Activity失去联系。也就是说此时的这个线程处于失去管理的状态。但是使用Service,则可以对后台运行的线程有效地管理。)

3、为什么直接不使用后台线程而使用Service?

1、Service可以放在独立的进程中,所以更安全;

2、使用Service可以依赖现有的binder机制,不需要在应用层面上处理线程同步的繁杂工作;

3、系统可以重新启动异常死去的Service。

[align=left]4、Service 与 Activity 的相同点与不同点:[/align]

不同点:Activity是与用户交互的组件,即可以看到UI界面,而Service是在后台运行、无需界面;

相同点:使用Activity 时我们需要在配置文件中声明<activity>标签,同样的使用Service 也需要在配置文件中声明<service>标签。都具有一定的生命周期。

[align=left](二)、服务的分类:[/align]
[align=left]1、本地服务Local Service:[/align]
[align=left]Local Service 用于应用程序内部。用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。[/align]

启动service有两种方法:

Context.startService()和Context.bindService
服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可
以启动Service,但是它们的使用场合有所不同。
1、使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。
使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止。
2、采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,
接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并
不会导致多次创建服务,但会导致多次调用onStart()方法。
采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用
onDestroy()方法。

1)、 Context.startService()
调用者与服务之间没有关联,即使调用者退出,服务仍可运行
2)、 Context.bindService()
调用者与服务绑定在一起,调用者一旦退出,服务也就终止

A、根据触发方式将本地服务分为:启动服务Started
Service和绑定服务Bound Service。【重点】

Started Service:被启动的服务

被启动的服务是由其它组件调用startService()方法而启动的,该方法会导致被启动服务的生命周期方法onStartCommand()被回调。当服务是被启动状态后,其生命周期与启动它的组件无关,即使启动服务的组件(Activity,BroadcastReceiver)已经被销毁,该服务还可以在后台无限期运行。除非调用stopSelf()或stopService()来停止该服务。

Bound Service:被绑定的服务

绑定服务是允许其它应用程序绑定并且与之交互的Service的实现类。为了提供绑定,必须实现onBind()回调方法。该方法返回IBinder对象,它定义了服务类与Activity交互的程序接口。
Activity通过bindService()方法绑定到服务类,同时Activity必须提供ServiceConnection接口的实现类,它监视Activity与服务类之间的连接。在重写ServiceConnection接口的onServiceConnected()方法时,实现了将服务类顺利赋值到了Activity中,实现了在Activity中使用该服务类并执行其中的方法。

B、根据onStartCommand()回调方法的返回值,将Started Service分为
onStartCommand()方法有三种返回值:

START_STICKY(常量值:1):sticky的意思是“粘性的”。使用这个返回值时,我们启动的服务跟应用程序"粘"在一起,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务。当再次启动服务时,传入的第一个参数将为null;
START_NOT_STICKY(常量值:2):“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。
START_REDELIVER_INTENT(常量值:3):重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

【备注:】
以上三种情况,可以理解为发生车祸后的人:

START_STICKY:(常量值:1)车祸后自己苏醒,但是失忆;
START_NOT_STICKY:(常量值:2)车祸后再也没有苏醒;
START_REDELIVER_INTENT:(常量值:3)车祸后自己苏醒,依然保持记忆。

[align=left]2、远程服务Remote Service: [/align]
[align=left]Remote Service 用于android系统内部的应用程序之间。可以定义接口并把接口暴露出来,以便其他应用进行操作。可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。[/align]

(三)、Service的生命周期:



[align=left]1、Started Service的生命周期:[/align]

onCreate():创建服务

onStartCommand():服务开始运行(在2.0以前版本中,使用onStart()回调方法)

onDestroy() :服务被停止

[align=left]【详细说明:】[/align]

在程序中调用:context.startService() 会触发执行Service生命周期中的onCreate()、onStartCommand()回调方法,此时服务就开始正式运行;
如果Service还没有运行,则android先调用onCreate()然后调用onStartCommand();如果Service已经运行,则只调用onStartCommand(),所以一个Service的onStartCommand方法可能会重复调用多次;
如果在程序中调用:context.stopService()会触发执行Service生命周期中的onDestroy()回调方法,会让服务停止;
stopService()的时候直接onDestroy,如果是调用者自己直接退出而没有调用stopService()的话,Service会一直在后台运行。该Service的调用者再启动该Service后可以通过stopService关闭Service;stopSelf()
所以StartService的生命周期为:onCreate --> onStartCommand(可多次调用) --> onDestroy。

[align=left] [/align]
[align=left]2、Bound Service的生命周期:[/align]

onCreate():创建服务

onBind():绑定服务,服务开始运行

onUnbind():取消绑定
onDestroy() :服务被停止

[align=left]【详细说明:】[/align]

在程序中调用:context.bindService()会触发执行Service生命周期中的on Create()、onBind()回调方法,此时服务开始运行;

onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。此后调用者(Context,例如Activity)会和Service绑定在一起;
如果调用Service的调用者Context退出了,那么会依次调用Service生命周期中的onUnbind()、onDestroy()回调方法,会让服务停止;
所以BindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。

[align=left] 【备注:】[/align]

Service是不能自己启动的,只有通过 Context 对象调用startService() 和bindService() 方法来启动。

在Service每一次的开启关闭过程中,只有onStartCommand()可被多次调用(通过多次startService调用),其他onCreate()、onBind()、onUnbind()、onDestory()在一个生命周期中只能被调用一次。

Service可以在和多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在后头的。

[align=left]二、本地Service:[/align]

[align=left](一)、Started Service启动MediaPlayer播放音乐:[/align]
[align=left]1、操作步骤:[/align]

1、写xml布局文件;

2、写MainActivity文件,通过按钮点击事件启动Service;

3、写继承于Service的StartService类文件:重写onCreate()/onStartCommand()/onDestroy()回调方法。

[align=left]2、XML布局文件核心代码:[/align]

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical">

<Button

android:id="@+id/button_main_play"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="clickButton"

android:text="播放音乐"/>

<Button

android:id="@+id/button_main_pause"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="clickButton"

android:text="暂停音乐"/>

<Button

android:id="@+id/button_main_stop"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="clickButton"

android:text="停止音乐"/>

<Button

android:id="@+id/button_main_exit"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="clickButton"

android:text="关闭当前窗体"/>

<Button

android:id="@+id/button_main_stopservice"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="clickButton"

android:text="停止服务"/>

</LinearLayout>


[align=left]3、MainActivty核心代码:[/align]

publicclass MainActivity extends Activity {

privatestaticfinal String TAG = "MainActivity";

private Intent intent = null;

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

Log.i(TAG, "==onCreate执行");

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

intent = new Intent(this, StartServicePlayMusic.class);

}

@Override

protectedvoid onDestroy() {

Log.i("MainActivty", "==onDestroy()");

super.onDestroy();

if (intent != null) {

// 停止服务可以通过stopService(intent)来停止,也可以intent到Service程序中,通过stopSelf()来停止。

stopService(intent);

}

}

publicvoid clickButton(View view) {

int type = 0;

switch (view.getId()) {

case R.id.button_main_play:

type = 1;

break;

case R.id.button_main_pause:

type = 2;

break;

case R.id.button_main_stop:

type = 3;

break;

case R.id.button_main_exit:

finish();

break;

case R.id.button_main_stopservice:

// 停止服务可以通过stopService(intent)来停止,也可以intent到Service程序中,通过stopSelf()来停止

// stopService(intent);

// finish();

type = 4;

break;

}

Bundle bundle = new Bundle();

bundle.putInt("type", type);

intent.putExtras(bundle);

startService(intent);

}

}


[align=left]4、StartServicePlayMusic核心代码:[/align]

publicclass StartServicePlayMusic extends Service {

privatestaticfinal String TAG = "StartServicePlayMusic";

private MediaPlayer mediaPlayer;

@Override

public IBinder onBind(Intent intent) {

Log.i(TAG, "==onBind执行");

returnnull;

}

@Override

publicvoid onCreate() {

Log.i(TAG, "==onCreate执行");

super.onCreate();

if (mediaPlayer == null) {

mediaPlayer = MediaPlayer.create(this, R.raw.hitta);

mediaPlayer.setLooping(false);

}

}

@Override

publicint onStartCommand(Intent intent, int flags, int startId) {

Log.i(TAG, "==onStartCommand执行");

if (intent != null) {

Bundle bundle = intent.getExtras();

int type = bundle.getInt("type");

switch (type) {

case 1:

play();

break;

case 2:

pause();

break;

case 3:

stop();

break;

case 4:

stopSelf();

break;

}

}
returnSTART_STICKY;
}

@Override

publicvoid onDestroy() {

Log.i(TAG, "==onDestroy执行");

super.onDestroy();

if (mediaPlayer != null) {

mediaPlayer.stop();

mediaPlayer.release();

}

}

publicvoid play() {

if (!mediaPlayer.isPlaying()) {

mediaPlayer.start();

}

}

publicvoid pause() {

if (mediaPlayer.isPlaying()) {

mediaPlayer.pause();

}

}

publicvoid stop() {

if (mediaPlayer != null) {

mediaPlayer.stop();

}

}

}


[align=left]5、Manifest清单配置文件核心代码:[/align]

<service

android:name=".StartServicePlayMusic">

<intent-filter>

<actionandroid:name="com.steven.startservice.playmusic"/>

</intent-filter>

</service>


6、Started Service总结:

Activity页面中需要startService(intent) 和 stopService(intent)两个方法来启动Service和停止Service;

继承于Service类的自定义子类——MyStartService类中,生命周期回调方法有:onCreate() 、onStartCommand() 、onDestroy();
如果停止服务,可以在Activity中调用stopService(intent),也可以intent到Service中执行stopSelf()方法;
执行停止服务方法,会回调Service生命周期中的onDestroy()方法;
如果希望关闭Activity窗体,服务也停止,那么在Activity的onDestroy()方法中执行stopService()方法。如果希望关闭窗体后,服务还继续,那么Activity的onDestroy()中不执行停止服务即可;
在StartService中不会回调onBind()方法;
在停止服务后,如果再次点击“播放”,可以重新启动StartService。

[align=left]7、IntentService与Service:[/align]

不管是何种Service,它默认都是在应用程序的主线程(亦即UI线程)中运行的。所以,如果你的Service将要运行非常耗时或者可能被阻塞的操作时,你的应用程序将会被挂起,甚至会出现ANR错误。为了避免这一问题,你应该在Service中重新启动一个新的线程来进行这些操作。现有两种方法大家参考:

[align=left]① 直接在Service的onStartCommand()方法中新建一个线程来执行;[/align]

[align=left]② Android SDK 中为我们提供了一个现成的Service类来实现这个功能,它就是IntentService,它主要负责以下几个方面:[/align]

Creates a default worker thread that executes all intents delivered to onStartCommand() separate from your application's main thread.

生成一个默认的且与主线程互相独立的工作者线程来执行所有传送至 onStartCommand() 方法的Intetnt

Creates a work queue that passes one intent at a time to your onHandleIntent() implementation, so you never have to worry about multi-threading.

生成一个工作队列来传送Intent对象给你的onHandleIntent()方法,同一时刻只传送一个Intent对象,这样一来,你就不必担心多线程的问题。

Stops the service after all start requests have been handled, so you never have to call stopSelf().

在所有的请求(Intent)都被执行完以后会自动停止服务,所以,你不需要自己去调用stopSelf()方法来停止该服务

Provides default implementation of onBind() that returns null.

提供了一个onBind()方法的默认实现,它返回null

Provides a default implementation of onStartCommand() that sends the intent to the work queue and then to your onHandleIntent() implementation

提供了一个onStartCommand()方法的默认实现,它将Intent先传送至工作队列,然后从工作队列中每次取出一个传送至onHandleIntent()方法,在该方法中对Intent对相应的处理

[align=left]IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程。[/align]
[align=left]这里就给我们提供了一个思路,如果有耗时的操作可以在Service里面开启新线程,也可以使用IntentService来处理耗时操作。 但你若是想在Service中让多个线程并发的话,就得使用第一种方法,在Service内部起多个线程,但是这样的话,你可要处理好线程的同步。[/align]

[align=left](1)、Service实现加载图片的核心代码:[/align]

publicclass DownloadService extends IntentService {

privatestaticfinal String TAG = "DownloadService";

private String urlString = "https://www.google.com.hk/images/srpr/logo11w.png";

private NotificationCompat.Builder builder = null;

private NotificationManager manager = null;

public DownloadService() {

super("");

}

@Override

protectedvoid onHandleIntent(Intent intent) {

manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

builder = new NotificationCompat.Builder(getApplicationContext());

builder.setSmallIcon(R.drawable.ic_launcher);

builder.setContentTitle("提示:");

builder.setContentText("图片加载完成,请点击查看!");

builder.setTicker("图片加载完成");

builder.setAutoCancel(true);

Intent intent2 = new Intent(getApplicationContext(), MainActivity.class);

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

PendingIntent pIntent = PendingIntent.getActivity(

getApplicationContext(), 0, intent2,

PendingIntent.FLAG_ONE_SHOT);

builder.setContentIntent(pIntent);

byte[] data = HttpClientHelper.loadByteFromURL(urlString);

boolean flag = SDCardHelper.saveFileToSDCard(data, "Download",

"logo11w.png");

if (flag) {

manager.notify(1, builder.build());

}

}

}


[align=left](2)、IntentService实现加载图片的核心代码:[/align]

publicclass DownloadService extends Service {

privatestaticfinal String TAG = "DownloadService";

private String urlString = "https://www.google.com.hk/images/srpr/logo11w.png";

private NotificationCompat.Builder builder = null;

private NotificationManager manager = null;

@Override

public IBinder onBind(Intent intent) {

returnnull;

}

@Override

publicvoid onCreate() {

super.onCreate();

manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

builder = new NotificationCompat.Builder(getApplicationContext());

builder.setSmallIcon(R.drawable.ic_launcher);

builder.setContentTitle("提示:");

builder.setContentText("图片加载完成,请点击查看!");

builder.setTicker("图片加载完成");

builder.setAutoCancel(true);

Intent intent = new Intent(getApplicationContext(), MainActivity.class);

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

PendingIntent pIntent = PendingIntent

.getActivity(getApplicationContext(), 0, intent,

PendingIntent.FLAG_ONE_SHOT);

builder.setContentIntent(pIntent);

}

@Override

publicint onStartCommand(Intent intent, int flags, int startId) {

new Thread(new Runnable() {

@Override

publicvoid run() {

byte[] data = HttpClientHelper.loadByteFromURL(urlString);

boolean flag = SDCardHelper.saveFileToSDCard(data, "Download",

"logo11w.png");

if (flag) {

manager.notify(1, builder.build());

stopSelf();

}

}

}).start();

returnSTART_STICKY;

}

@Override

publicvoid onDestroy() {

super.onDestroy();

}

}


[align=left](二)、Bound Service启动MediaPlayer播放音乐:[/align]
[align=left]1、操作步骤:[/align]

1、写xml布局文件;

2、写MainActivity文件,构建ServiceConnection对象,重写其中的抽象方法onServiceDisconnected()和onServiceConnected();
3、写继承于Service的BindService类文件,定义继承于Binder的内部类MyBinder,在其中定义方法getService();
4、BindService类中重写onCreate()方法、重写onBind()回调方法,onBind()方法返回MyBinder对象,重写onDestroy()方法;

2、XML布局文件:同上

3、MainActivty核心代码:

publicclass MainActivity extends Activity {

privatestaticfinal String TAG = "MainActivity";
private Intent intent;

private ServiceConnection conn = null;

private BindServicePlayMusic musicService;

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

Log.i(TAG, "==onCreate执行");
super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// 启动服务有多种写法:

// 可以通过new Intent(action字符串)来实现;

// intent = new Intent("com.steven.bindservice.playmusic");

intent = new Intent(this, BindServicePlayMusic.class);

conn = new ServiceConnection() {

@Override

publicvoid onServiceDisconnected(ComponentName name) {

musicService = null;
}

@Override

publicvoid onServiceConnected(ComponentName name, IBinder service) {

musicService = ((BindServicePlayMusic.MyBinder) service)

.getService();

if (musicService != null) {

musicService.play();

}

}

};

}

publicvoid clickButton(View view) {

switch (view.getId()) {

case R.id.button_main_play:
if (musicService == null) {

bindService(intent, conn, Context.BIND_AUTO_CREATE);

} else {

musicService.play();

}

break;
case R.id.button_main_pause:
if (musicService != null) {

musicService.pause();

}

break;
case R.id.button_main_stop:
if (musicService != null) {

musicService.stop();

}

break;
case R.id.button_main_exit:
finish();

break;
case R.id.button_main_stopservice:
// BindService中stopService(intent)不起作用,要通过undbindService来停止服务

// stopService(intent);

// musicService = null的目的是如果停止服务后,再次”播放“,可以正常执行。

// 如果不将musicService设置为null,再次播放时,将直接执行musicService.play(),而不执行bindService(),那么会导致异常

musicService = null;

unbindService(conn);

break;
}

}

}


[align=left]4、BindServicePlayMusic核心代码:[/align]

publicclass BindServicePlayMusic extends Service {

privatestaticfinal String TAG = "BindServicePlayMusic";

private MediaPlayer mediaPlayer;

private IBinder binder = null;

@Override

publicvoid onCreate() {

Log.i(TAG, "==onCreate执行");

super.onCreate();

if (mediaPlayer == null) {

mediaPlayer = MediaPlayer.create(this, R.raw.heavencity);

mediaPlayer.setLooping(false);

}

binder = new MyBinder();

}

class MyBinder extends Binder {

public BindServicePlayMusic getService() {

return BindServicePlayMusic.this;

}

};

@Override

public IBinder onBind(Intent intent) {

Log.i(TAG, "==onBind执行");

play();

returnbinder;

}

@Override

publicboolean onUnbind(Intent intent) {

Log.i(TAG, "==onUnbind执行");

returnsuper.onUnbind(intent);

}

@Override

publicvoid onDestroy() {

Log.i(TAG, "==onDestroy执行");

super.onDestroy();

if (mediaPlayer != null) {

mediaPlayer.stop();

mediaPlayer.release();

}

}

publicvoid play() {

if (!mediaPlayer.isPlaying()) {

mediaPlayer.start();

}

}

publicvoid pause() {

if (mediaPlayer.isPlaying()) {

mediaPlayer.pause();

}

}

publicvoid stop() {

if (mediaPlayer != null) {

mediaPlayer.stop();

}

}

}


[align=left]5、Manifest清单配置文件核心代码:[/align]

<service

android:name=".BindServicePlayMusic">

<intent-filter>

<actionandroid:name=“com.steven.bindservice.playmusic"/>

</intent-filter>

</service>


6、Bound Service总结:

三、 拓展知识(进程和生命周期):
Android操作系统尝试尽可能长时间保持应用的进程,但当可用内存很低时要移走一部分进程。哪些程序可以运行,哪些要被销毁?答案是:重要级别低的进程可能被淘汰。
按照重要性排列,一共可以分成5级:

1、前台运行进程:
用户此时需要处理和显示的进程。符合下列条件任何一个,这个进程就被认为是前台运行进程。

与用户正发生交互;

它控制一个与用户交互的必须的基本的服务;

一个正在调用生命周期回调方法的service(如onCreate()、onStar()、onDestroy());

一个正在运行onReceive()方法的广播接收对象。

销毁前台运行进程是系统万不得已的、最后的选择——当内存不够系统继续运行下去时,杀掉一些前台进程来保证能够响应用户的需求。
2、可用进程:
一个可用进程没有任何前台组件,但它仍然可以影响到用户的界面。下面情况发生时,可以称该进程为可用进程。
它是一个非前台的activity,但对用户仍然可用(onPause()方法已经被调用)。例如:前台的activity是一个允许上一个activity可见的对话框。也就是说当前activity中是一个对话框,对话框之外的地方能看到前一个activity的界面。

3、服务进程:
服务进程是一个通过调用startService()方法启动的服务,并且不属于前两种情况。尽管服务进程没有直接被用户看到,但他们确实是用户所关心的,比如后台播放音乐或网络下载数据,所以系统保证他们的运行。

4、后台进程:
一个后台进程就是非当前正在运行的activity(activity的onStop()方法已经被调用),他们不会对用户体验造成直接的影响,当没有足够内存来运行前台可见程序时,他们将会被终止。
通常,后台进程会有很多个在运行,LRU最近使用程序列表来保证经常运行的activity能最后一个被终止。

5、空线程:
一个空线程没有运行任何可用应用程序,保留他们的唯一原因是为了设立一个缓存机制,来加快组件启动的时间。系统经常杀死这些内存来平衡系统的整个系统的资源,进程缓存和基本核心缓存之间的资源。

6、ANR:Application NotResponding,五秒

在Android中,活动管理器和窗口管理器这两个系统服务负责监视应用程序的响应。当出现下列情况时,Android就会显示ANR对话框了:

  对输入事件(如按键、触摸屏事件)的响应超过5秒

  意向接受器(intentReceiver)超过10秒钟仍未执行完毕

  Android应用程序完全运行在一个独立的线程中(例如main)。这就意味着,任何在主线程中运行的,需要消耗大量时间的操作都会引发ANR。因为此时,你的应用程序已经没有机会去响应输入事件和意向广播(Intentbroadcast)。

  因此,任何运行在主线程中的方法,都要尽可能的只做少量的工作。特别是活动生命周期中的重要方法如onCreate()和 onResume()等更应如此。潜在的比较耗时的操作,如访问网络和数据库;或者是开销很大的计算,比如改变位图的大小,需要在一个单独的子线程中完成(或者是使用异步请求,如数据库操作)。但这并不意味着你的主线程需要进入阻塞状态已等待子线程结束 -- 也不需要调用Therad.wait()或者Thread.sleep()方法。取而代之的是,主线程为子线程提供一个句柄(Handler),让子线程在即将结束的时候调用它(xing:可以参看Snake的例子,这种方法与以前我们所接触的有所不同)。使用这种方法涉及你的应用程序,能够保证你的程序对输入保持良好的响应,从而避免因为输入事件超过5秒钟不被处理而产生的ANR。这种实践需要应用到所有显示用户界面的线程,因为他们都面临着同样的超时问题。

7、 ANR如何来避免:

Android应用程序通常是运行在一个单独的线程(例如,main)里。这意味着你的应用程序所做的事情如果在主线程里占用了太长的时间的话,就会引发ANR对话框,因为你的应用程序并没有给自己机会来处理输入事件或者Intent广播。因此,运行在主线程里的任何方法都尽可能少做事情。特别是,Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请求的方式)来完成。主线程应该为子线程提供一个Handler,以便完成时能够提交给主线程。以这种方式设计你的应用程序,将能保证你的主线程保持对输入的响应性并能避免由于5秒输入事件的超时引发的ANR对话框。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: