Service(服务)
本篇内容整理自郭霖的 《第一行代码》
文章目录
- 服务是 Android 中实现程序后台运行的解决方案,适合执行不需要和用户交互且长期运行的任务。
- 应用进程被杀掉,所依赖该进程的服务也终止。
- 服务不会自动开启线程,默认运行在主线程。
- 服务内部创建子线程,并实现业务处理。
Android 多线程编程
- 耗时操作放在子线程运行,否则主线程会被阻塞
线程的基本用法
1.实现Runnable接口实现
class MyThread implements Runnable{
public void run(){
//处理具体的业务逻辑
}
}
MyThread myThread = new MyThread();
new Thread(myThread).start();
2.匿名类写法(常用)
new Thread(new Runnable(){
public void run(){
//处理具体的业务逻辑
}
}).start();
在子线程中更新UI
Android UI 是线程不安全的,要更新UI,必须在主线程当中
- 很简单,异步处理机制可以解决子线程中进行UI操作的问题
public static final int UPDATE_TEXT = 1;
public Handler handler = new Handler(){
public void handleMessage(Message msg){
switch(msg.what){
case UPDATE_TEXT:
//在这里进行UI操作
break;
default:
break;
}
}
};
public void onClick(){
new Thread(new Runnable(){
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message); // 将 Message 对象发出去
}).start();
}
运用 Message 把消息传递出去交由 handleMessage 来处理业务逻辑
解析异步消息处理机制
- 很简单,Android 中异步消息处理主要由四个部分组成:
- Message
- Message 是线程之间传递的消息,它可以携带少量的信息在线程之间交换数据
例如:arg1、arg2 字段携带整型数据;obj 字段携带一个 Object 对象;what 字段携带…
- Handler
- Handler(处理者)主要是用于发送和处理消息的。
发送:sendMessage()
处理:handleMessage()
- Handler(处理者)主要是用于发送和处理消息的。
- MessageQueue
- 消息队列,存放 Handler 发送的消息。
- 消息会一直存放在 MessageQueue 中等待被处理
- 每个线程只会有一个 MessageQueue 对象
- Looper
- 管理 MessageQueue 。调用 Looper 的 loop() 方法后,就会进入一个无限循环,只要 MessageQueue 中存在一条消息,就会将它取出并传递到 handleMessage() 中处理。
- 每个线程只有一个 Looper 对象
使用AsyncTask
- 借助 AsyncTask 也可以很简单地从子线程切换到主程序(背后的实现原理也是基于异步消息处理机制,android 已经封装好了)
AsyncTask 泛型三参数:
第一:Params
在执行 AsyncTask 时使用;在后台任务中使用
第二:Progress
后台任务执行时需要在界面显示当前进度时使用;作为进度单位
第三:Result
后台任务执行完毕,需要对结果进行返回时使用;作为返回值类型
class DownloadTask extends AsyncTask<Void, Integer, Boolean>{
// void 不需要传入参数给后台任务;Integer 整型数据来作为进度显示单位; Boolean 布尔型数据来反馈执行结果
}
- 重写 AsyncTask 中的方法,完成对任务的定制。常用四个方法:
- onPreExecute()
- 后台任务开始执行前调用
- 用于界面初始化操作。 eg:显示进度条对话框
- doInBackground(
Params
…)
- 这个方法的代码会在子线程中运行,这儿处理耗时任务。
- 任务完成 return AsyncTask 泛型第三个参数类型的结果,为空不返回。
- 不可以进行UI操作。如果需要 UI 操作调用 publishProgress(Progress…) 方法
- onProgressUpdate(
Progress
…)
- 后台任务调用 publishProgress(Progress…) ,这个方法就被调用。
- 参数由后台任务传进
- 在此方法中更新 UI
- onPostExecute(
Result
)
- 后台任务通过 return 返回时,此方法被调用
- 利用返回的数据进行 UI 操作
class DownloadTask extends AsyncTask<Void, Integer, Boolean>{
// 后台任务执行前
protected void onPreExecute(){
progressDialog.show(); //显示进度对话框
}
// 后台任务执行中(此方法即在子线程中跑)
protected Boolean doInBackground(Void... params){
try{
int downloadPercent = doDownload(); //虚构方法
publishProgress(downloadPercent);
if(downloadPercent >= 100){
break;
}
}catch(Exception e){
return false;
}
return true;
}
// 后台任务调用 publishProgress()时
protected void onProgressUpdate(Integer... values){
progressDialog.setMessage("Downloaded" + values[0] + "%");//更新下载进度
}
// 后台任务通过 return 时
protected void onPostExecute(Boolean result){
progressDialog.dismiss();//关闭对话框
if(result){
Toast.makeText(context, "Download succeeded", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(context, "Download failed", Toast.LENGTH_SHORT).show();
}
}
}
//启动
new DownloadTask().execute();
AsyncTask 诀窍:在
doInBackground()
中执行具体耗时任务,在onProgressUpdate()
中进行UI操作,在onPostExecute()
中执行一些任务收尾工作
服务的基本用法
定义一个服务
1、新建一个 MyService 类,继承 Service
onBind()
方法是 Service 唯一的抽象方法,必须在子类中实现
public class MyService extends Service{
@Override
public IBinder onBind(Intent intent){
return null;
}
}
2、服务常用的三个方法
onCreate()
- 服务创建时候调用(仅创建那一次)
onStartCommand(Intent intent, int flags, int startId)
- 每次启动服务时调用
onDestroy()
- 服务销毁的时调用
3、在 AndroidManifest.xml 中注册服务
<application
....>
<service android:name=".MyService">
</service>
</application>
启动和停止服务
- 借助 Intent 实现
public void onClick(View v){
switch(v.getId()){
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;
default:
break;
}
}
活动和服务进行通信
onBind()
活动(Activity)指挥服务(Service)去干什么
活动开启、查看服务下载功能的例子:
服务(Service)
public class MyService extends Service{
// (2)实例化内部类
private DownloadBinder mBinder = new DownloadBinder();
// (1)创建内部类
class DownloadBinder extends Binder{
public void startDownload(){
//执行下载逻辑
}
public int getProgress(){
//执行查看下载状态逻辑
}
// (3)返回内部类实例
@Override
pubilc IBinder onBind(Intent intent){
return mBinder;
}
}
}
活动(Activity)
private MyService.DownloadBinder downloadBinder; // 下载服务
//创建匿名类。重写解除绑定时调用的 onServiceDisconnected() 方法,绑定时调用的 ServiceConnected() 方法
private ServiceConnection connection = new ServiceConnection(){
@Override
public void onServiceDisconnected(ComponentName name){
// 解除绑定的时候调用
}
@Override
public void ServiceConnected(ComponentName name, IBinder service){
//绑定时调用
downloadBinder = (MyService.DownloadBinder) service;
downloadBinder.startDownload();
downloadBinder.getProgress();
}
};
@Override
public void onClick(View v){
switch(v.getId()){
case R.id.bind_service:
Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务
break;
case R.id.unbind_service:
unbindService(connection); //解绑服务
break;
default:
break;
}
}
服务的生命周期
- 不管你调用了多少次 startService() 方法,只需要调用一次 stopService() 或 stopSelf() 方法,服务就会停止下来。
- 服务没创建过,onCreate() 方法优先于任何方法执行。
- 执行了 stopService() 和 unbindService() 都会调用 onDestroy() 方法。一个服务同时调用了 startService() 和 bindService() 要销毁服务必须同时调用stopService() 和 unbindService() 服务才会执行 onDestroy()。
- 开启服务且绑定了服务,必须关闭且解绑才能销毁服务
服务的更多技巧
使用前台服务
public class MyService extends Service{
...
@Override
public void onCreate(){
...
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);
...
}
...
}
没有调用 NotificationManage 的 notify() 来将通知显示出来,而是调用了startForegrounnd( 第一:id, 第二:Notification对象 ),调用此方法就会让服务变成一个前台服务并在系统状态栏显示出来。
使用IntentService
- 如果在服务里处理耗时操作会出现 ANR(Application Not Responding)情况。因此可以借助 Android 的多线程技术,即标准的服务形式如下:
public class MyService extends Service{
@Override
public IBinder onBind(Intent intent){
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId){
new Thread(new Runnable(){
@Override
public void run(){
//处理具体逻辑
stopSelf(); //此服务开启后会一直处于运行状态。要想让它执行完毕后自动停止应进行此操作
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
}
- 总会有程序员忘记开启线程,并调用 stopSelf() 方法,因此 Android 提供了一个 IntentService类 来创建一个异步的,会自动停止的服务
1、服务 Service
public class MyIntentService extends IntentService{
public MyIntentService(){
super("MyIntentService"); // 调用父类的有参构造函数
}
@Override
protected void onHandleIntent(Intent intent){
//处理一些具体的逻辑,而且不用担心ANR的问题。此方法已经在子线程中运行了
}
@Override
public void onDestroy(){
//这个服务在运行结束后会自动停止
super.onDestroy();
}
}
2、活动 Activity
Intent intentService = new Intent(this, MyIntentService.class);
startService(intentService);
3、AndroidManifest 注册
<service android:name=".MyIntentService"></service>