服务 android多线程编程 服务的基本用法 服务的生命周期 服务技巧
服务(Service): 在Android中实现程序后台运行的解决方案,本身的运行并不依赖于用户可视的UI界面。 适用:
- 并不依赖于用户可视的UI界面(不一定,前台Service就是与Notification界面结合使用的)
- 不需要和用户交互而且要求长时间运行 服务依赖于创建服务的所在的应用程序进程。(进程被杀死,依赖该进程的服务停止) 服务并不会自动开启线程,因此需要在Service内部创建子线程。
服务基本用法:
Service分类:
- Started Service:被一个组件调用startService()开启的Service。
- 扩展Service: 这是所有服务的基类。扩展这个类的时候,特别重要的一点是,需要创建一个新的线程来做服务任务,因为service默认是运行在你的主线程(UI线程)中的,它会使你的主线程运行缓慢。
- 扩展IntentService: service的子类,在一个工作线程(子线程)中处理所有的启动请求。需要是实现onHandlerIntent()方法,通过这个函数处理接受的每一个启动请求。 (Android提供的便于创建异步,能自动停止的service)
service的onStartCommand()方法被调,根据传递intent开启Service,拥有一个独立于开始它的组件(不是进程)的生命周期。 默认service运行在声明它的应用的同一个进程里面,而且在应用的主线程里面。 - Bound Service: 与Activity相绑定的service。
定义一个服务:
- AndroidManifest.xml 注册:Service属于四大组件之一,无论是Started Service和Bound Service,都有Service基类继承而来,都需要在AndroidManifest.xml中声明.
<service android:enabled=["true" | "false"]
android:exported=["true" | "false"] //是否能被其他程序组件调用或交互
android:icon="drawable resource"
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:name="string" //Service类名
android:permission="string" //权限声明
android:process="string" > //设置具体的进程名称
. . .
</service>
- 完成Service类的继承,自定义MyService类,重写相应办法:
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) { //绑定方法,唯一抽象方法
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d("MyService" , "in onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyService", "in onStartCommand");
return super.onStartCommand(intent,flags,startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyService", "in onDestroy");
}
}
onCreate(…),onStartCommand(…),onDestroy()为Service相应生命周期阶段的回调函数. onBind(…)函数是Service基类中的唯一抽象方法,子类都必须重写实现,对于Bound Service,其返回值才具有意义。
启动和停止服务: 通过startservice() stopservice(),传递intent,开启,停止相应服务。 在service内部任一位置,通过调用stopSelf()方法停止服务。
case R.id.start_service:
Intent startIntent = new Intent(this,MyService.class);
startService(startIntent);
break;
case R.id.stop_service:
Intent stopIntent = new Intent(this,MyService.class);
stopService(stopIntent);
break;
活动与服务进行通信(Bound Service): 通过扩展Binder类创建Bound Service的步骤如下:
- 在Service类中,创建一个Binder实例,包含客户端能调用的公共方法,返回当前服务对象,在onBind()方法中返回Binder实例
private DownloadBinder mBinder = new DownloadBinder();
class DownloadBinder extends Binder{
public void startDownload(){
Log.d("MyService","startDownload executed");
}
public int getProgress(){
Log.d("MyService","getProgress executed");
return 0;
}
}
...........................
@Override //返回实例
public IBinder onBind(Intent intent) {
return mBinder;
}
}
- 自定义的ServiceConnection中实现onServiceConnected(ComponentName name, IBinder binder)方法,获取Service端Binder实例,通过获取的Binder实例进行Service端其他公共方法的调用
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName namee) {
}
@Override
public void onServiceConnected(ComponentName name,IBinder service) {
downloadBinder = (MyService.DownloadBinder) service; //获取实例
downloadBinder.startDownload(); //完成对于公共方法的调用
downloadBinder.getProgress();
}
};
- 通过bindService(intent,connection,flag)方法,实现Activity与Service的通信。 intent : 连接相应的ActivityyuService connection:已完成重写onServiceConnected()方法的ServiceConnection内部类对象。 flag:关联模式,采用BIND_AUTO_CREATE即可。
Intent bindIntent = new Intent(this,MyService.class);
bindService(bindIntent,connection,BIND_ABOVE_CLIENT);
break;
- 通过调用unbindService()方法,解除绑定:
unbindService(connection);
服务的生命周期: 生命周期回调方法:
public class ExampleService extends Service {
int mStartMode; // indicates how to behave if the service is killed
IBinder mBinder; // interface for clients that bind
boolean mAllowRebind; // indicates whether onRebind should be used
@Override
public void onCreate() {
// The service is being created
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// The service is starting, due to a call to startService()
return mStartMode;
}
@Override
public IBinder onBind(Intent intent) {
// A client is binding to the service with bindService()
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
// All clients have unbound with unbindService()
return mAllowRebind;
}
@Override
public void onRebind(Intent intent) {
// A client is binding to the service with bindService(),
// after onUnbind() has already been called
}
@Override
public void onDestroy() {
// The service is no longer used and is being destroyed
}
}
注:
- onCreate()方法在service没有被创建的情况下,启动服务,才会被调用。
- onStartCommand()方法在每一次调用startService()方法时,都会被执行一次,但是并不会创建新的实例。
- 通过bindService()方法获取了持久连接,则必须调用unbindService()方法,解除绑定,才可以调用stopService()方法,结束服务。
前台服务: 由于Service的系统优先级比较低,在内存不足的情况下,可能被系统回收。为了避免被系统回收正在运行的Service,使Service可以一直保持运行状态——前台服务 前台服务将会在状态栏有一个正在运行的图标,类似于Notification效果。
实现:
- 构建Notification对象,对其显示方式进行设置
- PendingIntent的设置,实现对于点击意图的设置
- 通过startForeground(Id, notification); ID为通知的Id,notification为构建的Notification对象,将Service转变为前台服务。
Notification notification = new Notification(R.drawable.ic_launcher,
"Notification comes", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
notification.setLatestEventInfo(this, "This is title", "This is content",
pendingIntent);
startForeground(1, notification);
Android多线程基础:基本与java多线程编程使用相同的语法。
- 创建子线程:
class MyThread extends Thread{
@Override
public void run(){
//耗时逻辑
}
}
---------------------------------------------------
//使用实现Runnable接口定义线程 (耦合性高?)
class MyThread implements Runnable(){
@Override
public void run(){
//耗时逻辑
}
}
-----------------------------------------------------
//匿名类方式
new Thread (new Runnable(){
@Override
public void run(){
//耗时逻辑
}
}).start();
- 启动线程:
new Thread().start();
----------------------------------------------------------
MyThread myThread = new MyThread();
new Thread(myThread).start;
Android的UI操作属于线程不安全,即必须在主线程中进行对于UI的操作。 使用异步消息机制,在子线程中执行耗时操作,根据任务结果更新UI。 方法一:异步消息处理:Message,Handle,MessageQueue,Looper构成,详细解释。 基础练习 方法二:AsyncTask: Android提供的轻量级的异步类,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程. 同样基于异步消息处理机制,Android进行了较好的封装。 优点:
- 简单,快捷
- 过程可控
缺点:
- 在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个)。 AsyncTask定义了三种泛型类型 Params,Progress和Result。
- Params: 启动任务执行的输入参数,比如HTTP请求的URL。
- Progress: 后台任务执行的百分比。
- Result: 后台执行任务最终返回的结果,比如String。
最少写以下这两个方法:
- doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
- onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回。
补充方法:
- nProgressUpdate(Progress…) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
- onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
- onCancelled() 用户调用取消时,要做的操作
使用AsyncTask类,以下是几条必须遵守的准则:
- Task的实例必须在UI thread中创建;
- execute方法必须在UI thread中调用;
- 不可以手动调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法;
- 该task只能被执行一次,否则多次调用时将会出现异常; AsyncTask基础练习
IntentService: 由于Serice默认运行与主线程,在处理耗时逻辑情况下,可能出现ANR情况。 可以通过多线程编程,在Service的具体方法内开启线程,在子线程中处理耗时逻辑,通过stopSelf停止。
public itn onStartCommand(Intent intent,int flags,int startId){
new Thread(new Runnable() { //开启子线程
@Override
public void run() {
//耗时逻辑
stopSelf();
}
}).start();
return super.onStartCommand(intent,flags,startId);
}
}
InentService: 已由Android封装,自动开启线程,自动调用stopSelf()方法的InentService类。 IntentService通过worker thread处理每个Intent对象,执行完所有工作后自动停止Service。 实现:通过复写onHandleIntent()方法,构造。
- 创建一个与应用程序主线程分开worker thread用来处理所有通过传递过来的Intent请求
- 创建一个work queue,一次只传递一个intent到onHandleIntent()方法中,从而不用担心多线程带来的问题
- 当处理完所有请求后自动停止服务,而不需要我们自己调用stopSelf()方法
- 默认实现了onBind()方法,返回值为null
- 默认实现了onStartCommand()方法,这个方法将会把我们的intent放到work queue中,然后在onHandleIntent()中执行
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.d("MyIntentService", "Thread id is " + Thread.currentThread().getId());
} //耗时操作 在子线程中运行
@Override
public void onDestroy() {
super.onDestroy();
Log.d("MyIntentService", "onDestroy executed");
}
}
使用上与一般Service没有很大差别。
服务的最佳实践: 后台执行的定时任务 (通过定时任务,实现循环)