Android 应用开发<四> Service

2018/08/17 Android App

Android Service

Android 多线程机制

异步消息处理机制使用

Message、Handler、MessageQueue、Looper,相关源码路径在 frameworks/base/core/java/android/os/

示例代码(主线程中使用 Handler)

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView text;
    public static final int UPDATE_TXT = 1;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case UPDATE_TXT:
                    text.setText("haha");
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text = (TextView) findViewById(R.id.text);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(this);


    }

    @Override
    public void onClick(View v){
        switch (v.getId()){
            case R.id.button:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                    //这里不使用 new Message 方式进行创建一个 Message。
                        Message message = Message.obtain();
                        message.what = UPDATE_TXT;
                        handler.sendMessage(message);
                        //text.setText("haha");
                    }
                }).start();
                break;
            default:
                break;
        }
    }

}

大致小结一下,说了那么多相信大家已经对 Handler 的作用比较熟悉了,其实也是一个线程间通信的机制,主要用于在子线程中对 UI 进行实时更新,因为我们都知道 UI 操作一般都是线程不安全的,一些耗时操作应该放在子线程中进行处理,而 UI 更新代码必须放置在主线程中。使用方法还是很简单 new Thread()创建线程,线程中做的操作:(1)填充 Message (2)调用 handler 的 sendMessage 函数给 handleMessage 函数进行处理。使用起来还是很方便的,但是作为从底层爬上来的码农,总觉得不够味,MessageQueue 在哪?Looper 在哪?下面就来简要分析一下整个流程。

异步消息处理分析

  • Handler 的构造函数 frameworks/base/core/java/android/os/Handler.java,获取 Looper 对象,从 Looper 中读取 mQueue(MessageQueue)
    public Handler() {
        this(null, false);
    }
    .......
    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    ......
  • 问题来了,上面的代码中 Handler 的构造函数里面有取出 Looper 对象,那 Looper 是什么时候创建的呢?这里直接给出答案了,如果在创建 Handler 的时候是放在主线程中,activity 会自动帮你创建一个 looper 对象,代码路径 frameworks/base/core/java/android/app/ActivityThread.java中会创建 Looper 对象,这里就不再深入分析了,直接给出 Looper 的构造函数。
public static void main(String[] args) {
    ...
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    ...
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}
    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
  • Looper.loop()函数会创建一个死循环,queue.next() 取出 MessageQueue 中的数据,再调用 dispatchMessage 进行对 Message 进行处理的操作
          for (;;) {
              Message msg = queue.next(); // might block
              if (msg == null) {
                  // No message indicates that the message queue is quitting.
                  return;
              }
    
              // This must be in a local variable, in case a UI event sets the logger
              final Printer logging = me.mLogging;
              if (logging != null) {
                  logging.println(">>>>> Dispatching to " + msg.target + " " +
                          msg.callback + ": " + msg.what);
              }
    
              final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
    
              final long traceTag = me.mTraceTag;
              if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                  Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
              }
              final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
              final long end;
              try {
                  msg.target.dispatchMessage(msg);
                  end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
              } finally {
                  if (traceTag != 0) {
                      Trace.traceEnd(traceTag);
                  }
              }
    
  • Message 的构造函数,代码路径 frameworks/base/core/java/android/os/Message.java,这里不直接 new 的原因注释也说的很明白,从global pool 中取出 Message ,避免内存申请释放问题.
    /**
     * Return a new Message instance from the global pool. Allows us to
     * avoid allocating new objects in many cases.
     */
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }
  • handler 的 sendMessage 方法,最后会调用 sendMessageAtTime 方法,这里先获取 mQueue(在之前调用 Handler 构造函数的时候,从Looper获取的),之后调用 enqueueMessage 将 msg 入栈,enqueueMessage 最后会调用 frameworks/base/core/java/android/os/MessageQueue.java里面的
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
  • 最后再来看一下 Handler 的 handleMessage 方法,Handler 类中的函数是一个空函数,所以需要在子类中实现 handleMessage 用于处理 Message。
  • 关于在子线程中创建 Handler 就需要自己手动去创建 looper,下面给出的是示例代码,相关操作和在主线程中创建是类似的,只是 Looper 的创建不在是由Android帮你创建,而是自己手动去创建了。
/**
  * Class used to run a message loop for a thread.  Threads by default do
  * not have a message loop associated with them; to create one, call
  * {@link #prepare} in the thread that is to run the loop, and then
  * {@link #loop} to have it process messages until the loop is stopped.
  *
  * <p>Most interaction with a message loop is through the
  * {@link Handler} class.
  *
  * <p>This is a typical example of the implementation of a Looper thread,
  * using the separation of {@link #prepare} and {@link #loop} to create an
  * initial Handler to communicate with the Looper.
  *
  * <pre>
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }</pre>
  */

AsyncTask

本质使用的还是异步消息来实现的一种多线程通信机制,在使用 AsyncTask 时,需要实现 AsyncTask 这个抽象类。需要重写的方法:onPreExecute、doInBackgroud、onProgressUpdate、onPostExecute

服务的基本用法

继承类 Service。我们需要重写 onCreate、onStartCommand、onDestory、onBinder(唯一一个抽象方法,必须实现)

代码示例

public class MyService extends Service {
    private DownloadBinder mBinder = new DownloadBinder();
    class DownloadBinder extends Binder{
        public void startDownload(){
            Log.d("MyService","startdownload");

        }
        public int getProgress(){
            Log.d("MyService","getProgress");
            return 0;
        }
    }
    @Override
    public IBinder onBind(Intent intent){
        return mBinder;
    }
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

借助 Intent 在 activity 中启动 service

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private MyService.DownloadBinder downloadBinder;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            downloadBinder = (MyService.DownloadBinder)service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startService = (Button) findViewById(R.id.start_Service);
        Button stopService  = (Button) findViewById(R.id.stop_Service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        Button bindService = (Button)findViewById(R.id.bind_service);
        Button unbindService = (Button) findViewById(R.id.unbind_service);
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.start_Service:
                Intent startIntent = new Intent(this,MyService.this);
                startService(startIntent);
                break;
            case R.id.stop_Service:
                Intent stopIntent = new Intent(this,MyService.this);
                stopService(stopIntent);
                break;
            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;

        }
    }
}

onCreate 方法和 onStartCommand 有什么区别呢?其实 onCreate 方法只在 service 第一次启动时调用,之后多次启动服务只会调用 onStartCommand

bindService 浅谈

给一张调用流程图,其实底层用的还是 Binder 机制来实现的,内容较多这里就不展开分析了,推荐一个 blog ,对 framework 调用流程分析的已经挺详细了– Service 进阶

IntentService

在 service 中处理耗时操作可能会导致 app 无响应,所以在 service 中必须采用多线程技术,在执行完 service 操作后,咱们不能让 service 一直调用吧?所以需要显式调用 stopService 或者 stopSelf,Android 为了更方便实现多线程的管理,又实现了 IntentService ,耗时的服务处理操作放在 onHandleIntent 函数中进行就可以了,相比之前自己实现多线程,显然是方便了很多。

Search

    Table of Contents