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控件,单纯使用上面的线程是行不通的:
![eInfo.png](https://upload-images.jianshu.io/upload_images/9071113-0ed9c0cb1ee583ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
为了解决这个问题可以使用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();

异步消息处理机制

handler

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

服务的生命周期

service_lifecycle.png

官方图中可以看到服务的启动有两种途径。一种是启动服务,一种是绑定服务,服务可以同时以两种状态运行,即可以绑定已经通过启动服务方式运行的服务。
特别注意的是通过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)    收藏  举报

导航