Android 服务的学习
服务(Service)
服务是为了实现Android程序后台运行的方案。服务不是运行在一个独立的进程中,而是在创建服务的应用程序进程中,所以服务的这段代码默认运行在主线程中的,需要我们多线程编程手动创建,否则有可能会出现阻塞主线程的情况。
线程基本用法
方1:
Class MyThread extends Thread {
@Override
public void run() {
//耗时的逻辑
}
}
启动线程:new MyThread().start();
方2:
class MyThread implements Runnable {
@Override
public void run() {
//耗时的逻辑
}
}
启动线程:
new Thread(myThread).start();```
## 异步消息处理机制
Android的UI是线程不安全的,如果我们需要在子线程中去执行一些耗时的操作,然后依据操作的结果去更新UI控件,单纯使用上面的线程是行不通的:

为了解决这个问题可以使用Android提供的异步消息处理机制。
###使用方法
先重写Handler的handleMessage()方法:
``` Java
public static final int UPDATE_TEXT = 1;
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_TEXT:
textView.setText("Nice to meet you");
break;
default:
break;
}
}
};
然后在run方法中使用handler发送这个message
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message);
}
}).start();
异步消息处理机制

- MessageQueue是一个Message消息队列,每个线程只有一个
- Looper 执行的是在一个死循环里检查MessageQueue里面是否有message,每次取出一个message便传给handler的handleMessage(),每个线程只有一个
- message 在线程之间传递的消息
- Handler 就是发送,处理message的一个管理者
Android中为了更方便使用子线程对UI的操作还提供了一个AsyncTask抽象类,AsyncTask使用很简单,但是很容易出现内存泄漏的问题,有关AsyncTask内存泄漏的问题改天重写一个博客,此处标记一下防止我犯懒
服务的生命周期

官方图中可以看到服务的启动有两种途径。一种是启动服务,一种是绑定服务,服务可以同时以两种状态运行,即可以绑定已经通过启动服务方式运行的服务。
特别注意的是通过startService()启动的服务会无限期运行下去,即使调用这个方法的组件已经被销毁也不受影响,所以要关闭服务一定要通过服务自身调用stopSelf()或者stopService(),当服务停止后并且没有其他的组件绑定在这个服务的时候转到onDestroy()中,一定要注意即使服务已经调用上面的停止方法,如果没有将所有的组件解绑是不会销毁的。
当所有组件通过调用unbindService()解绑后才会调用onUnbind()方法。如果仅是通过bindService()来创建服务,当所有组件解绑后会自行调用onDestroy().
有关服务被回收的时机
当内存过低必须回收系统资源的时候会强制停止,或者服务运行了很长时间导致优先级变低也可能会终止,如果是前台服务(使用通知栏)则几乎永远不会终止,被终止的服务当资源可用后系统会重启服务(取决于onStartCommand()的返回值)
创建启动服务
当我们通过
startService(startIntent);```启动服务后onStartCommand()方法一并执行,这个intent便传到了onStartCommand()中。所以在下面的示例代码中onStartCommand()里面主要做的工作就是将每个intent里面的信息添加到Message中,然后发往我们的异步消息处理机制中去处理特定的逻辑。一定要注意的是每次我们通过onStartCommand()启动后都应该使用stopSelf()停止服务,当面临多任务请求的时候可以像官方代码那样分别在stopSelf()中传递我们服务的id。
因为服务很可能会阻碍我们的主线程,所以官方示例代码直接就提供了结合线程的启动服务示例,需要了解上面的异步消息处理机制:
``` Java
public class HelloService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
@Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
创建绑定服务
绑定后的服务主要通过IBinder接口来进行组件与服务的通信,主要就是继承Binder类,然后在组件中获取这个类的实例即可,实际上绑定服务还要考虑到重新绑定以及执行onUnbind()的时机等等问题,等我实际遇到这部分问题时候再写。
public class MyService extends Service {
private DownloadBinder mBinder = new DownloadBinder();
private static final String TAG = "MyService";
public MyService() {
}
class DownloadBinder extends Binder {
public void startDownload() {
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
前台使用服务
1.创建一个通知栏
2.调用startForeground(ONGOING_NOTIFICATION_ID, notification);第一个参数是我们的服务id,第二个参数是我们的创建的通知栏
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);
posted on 2018-03-18 11:37 BlaBlaLogic 阅读(121) 评论(0) 收藏 举报
浙公网安备 33010602011771号