当前位置: 代码迷 >> Android >> android 过程/线程管理(三)-Thread,Looper / HandlerThread / IntentService
  详细解决方案

android 过程/线程管理(三)-Thread,Looper / HandlerThread / IntentService

热度:742   发布时间:2016-04-27 23:39:42.0
android 进程/线程管理(三)----Thread,Looper / HandlerThread / IntentService

Thread,Looper的组合是非常常见的组合方式。

Looper可以是和线程绑定的,或者是main looper的一个引用。

下面看看具体app层的使用。

首先定义thread:

package com.joyfulmath.androidstudy.thread;import com.joyfulmath.androidstudy.TraceLog;import android.os.Bundle;import android.os.Handler;import android.os.Looper;import android.os.Message;public class MyLoopThread extends Thread {            private Looper myLooper = null;    private MyHandler mHandler = null;    public MyLoopThread()    {        super();    }        @Override    public void run() {        TraceLog.i("MyLoopThread looper prepare");        Looper.prepare();//        myLooper = Looper.getMainLooper(); /*using this can be set as main handler*/        myLooper = Looper.myLooper();        mHandler =  new MyHandler(myLooper);        TraceLog.i("MyLoopThread looper loop");        Looper.loop();    }            public void doAction(int index,String params)    {        if(index>0 && index <=3)        {            Message msg = mHandler.obtainMessage(index);            Bundle bundle = new Bundle();            bundle.putString("key", params);            msg.setData(bundle);            mHandler.sendMessage(msg);        }        else        {            TraceLog.w(index+"");        }    }        public static  class MyHandler extends Handler{                public MyHandler()        {            super();        }                public MyHandler(Looper loop)        {            super(loop);        }                /*make sure that the looper is main or not         *so you can update UI or send main handler to do it.          * */        @Override        public void handleMessage(Message msg) {            Bundle bundle = msg.getData();            String params = bundle.getString("key");            TraceLog.i(params);            switch(msg.what)            {            case ThreadConstant.INDEX_1:                TraceLog.d("INDEX_1");                break;            case ThreadConstant.INDEX_2:                TraceLog.d("INDEX_2");                break;            case ThreadConstant.INDEX_3:                TraceLog.d("INDEX_3");                break;                }        }    }}

上面这个MyLoopThread类把,hangler,looper,thread融合在一起了,我们看看关键的地方:

    @Override    public void run() {        TraceLog.i("MyLoopThread looper prepare");        Looper.prepare();//        myLooper = Looper.getMainLooper(); /*using this can be set as main handler*/        myLooper = Looper.myLooper();        mHandler =  new MyHandler(myLooper);        TraceLog.i("MyLoopThread looper loop");        Looper.loop();    }

 

如上,Thread只在说一件是,消息循环。而且可以发送消息到主线程来处理。

如果MyLoopThread里面定义两个handler,会不会有冲突呢?

我们用代码试试看。

我们修改下run以及添加doaction2:

@Override    public void run() {        TraceLog.i("MyLoopThread looper prepare");        Looper.prepare();//        myLooper = Looper.getMainLooper(); /*using this can be set as main handler*/        myLooper = Looper.myLooper();        mHandler =  new MyHandler(myLooper);        mHandler2 = new Handler(myLooper){            @Override            public void handleMessage(Message msg) {                Bundle bundle = msg.getData();                String params = bundle.getString("key");                TraceLog.i("Handler2 "+params);                switch(msg.what)                {                case ThreadConstant.INDEX_1:                    TraceLog.d("Handler2 INDEX_1");                    break;                case ThreadConstant.INDEX_2:                    TraceLog.d("Handler2 INDEX_2");                    break;                case ThreadConstant.INDEX_3:                    TraceLog.d("Handler2 INDEX_3");                    break;                    }            }                                };        TraceLog.i("MyLoopThread looper loop");        Looper.loop();    }
    public void doAction2(int index,String params)    {        if(index>0 && index <=3)        {            Message msg = mHandler2.obtainMessage(index);            Bundle bundle = new Bundle();            bundle.putString("key", params);            msg.setData(bundle);            mHandler2.sendMessage(msg);        }        else        {            TraceLog.w(index+"");        }    }
08-03 17:04:40.679: I/MyLoopThread(25483): run: MyLoopThread looper prepare [at (MyLoopThread.java:22)]08-03 17:04:40.679: I/MyLoopThread(25483): run: MyLoopThread looper loop [at (MyLoopThread.java:50)]08-03 17:04:40.769: I/Timeline(25483): Timeline: Activity_idle id: [email protected] time:14167575908-03 17:04:42.709: I/MyLoopThread$MyHandler(25483): handleMessage: time millseconds one [at (MyLoopThread.java:107)]08-03 17:04:42.709: D/MyLoopThread$MyHandler(25483): handleMessage: INDEX_2 [at (MyLoopThread.java:114)]08-03 17:04:47.299: I/MyLoopThread$1(25483): handleMessage: Handler2 time millseconds two [at (MyLoopThread.java:33)]08-03 17:04:47.299: D/MyLoopThread$1(25483): handleMessage: Handler2 INDEX_2 [at (MyLoopThread.java:40)]08-03 17:04:52.829: I/MyLoopThread$MyHandler(25483): handleMessage: time millseconds one [at (MyLoopThread.java:107)]08-03 17:04:52.829: D/MyLoopThread$MyHandler(25483): handleMessage: INDEX_3 [at (MyLoopThread.java:117)]08-03 17:04:53.479: I/MyLoopThread$MyHandler(25483): handleMessage: time millseconds one [at (MyLoopThread.java:107)]08-03 17:04:53.479: D/MyLoopThread$MyHandler(25483): handleMessage: INDEX_3 [at (MyLoopThread.java:117)]08-03 17:04:54.909: I/MyLoopThread$1(25483): handleMessage: Handler2 time millseconds two [at (MyLoopThread.java:33)]08-03 17:04:54.909: D/MyLoopThread$1(25483): handleMessage: Handler2 INDEX_1 [at (MyLoopThread.java:37)]08-03 17:04:56.309: I/MyLoopThread$1(25483): handleMessage: Handler2 time millseconds two [at (MyLoopThread.java:33)]08-03 17:04:56.309: D/MyLoopThread$1(25483): handleMessage: Handler2 INDEX_3 [at (MyLoopThread.java:43)]

查看消息可以看到, handler很好的处理了消息,没有出现错乱的问题。

我们知道,对于每个thread,looper,messagequeue都是唯一的,那为什么没有出错呢?

我们看看之前在《android 进程/线程管理(一)----消息机制的框架》http://www.cnblogs.com/deman/p/4688054.html

中的looper.loop()

里面有一句:

msg.target.dispatchMessage(msg);

是的,这就是分发和处理消息。而target就是我们的handler。

 

HandlerThread:

对于上面的例子,google提供了一个更方便的解决方案:HandlerThread。

下面是HandlerThread的源码:

@Override    public void run() {        mTid = Process.myTid();        Looper.prepare();        synchronized (this) {            mLooper = Looper.myLooper();            notifyAll();        }        Process.setThreadPriority(mPriority);        onLooperPrepared();        Looper.loop();        mTid = -1;    }

可以看到,handlerThread自己把looper给启动了。

下面是使用handlerthread的代码,比thread,looper更为简单。

package com.joyfulmath.androidstudy.thread;import com.joyfulmath.androidstudy.TraceLog;import android.os.Bundle;import android.os.Handler;import android.os.HandlerThread;import android.os.Looper;import android.os.Message;public class MyHandlerThread extends HandlerThread{    MyHandler myHandler = null;        public MyHandlerThread(String name) {        super(name);    }                @Override    protected void onLooperPrepared() {        super.onLooperPrepared();        myHandler = new MyHandler(getLooper());    }    public void doAction(int index,String params)    {        if(index>0 && index <=3)        {            Message msg = myHandler.obtainMessage(index);            Bundle bundle = new Bundle();            bundle.putString("key", params);            msg.setData(bundle);            myHandler.sendMessage(msg);        }        else        {            TraceLog.w(index+"");        }    }    public static  class MyHandler extends Handler{                public MyHandler()        {            super();        }                public MyHandler(Looper loop)        {            super(loop);        }                /*make sure that the looper is main or not         *so you can update UI or send main handler to do it.          * */        @Override        public void handleMessage(Message msg) {            Bundle bundle = msg.getData();            String params = bundle.getString("key");            TraceLog.i(params);            switch(msg.what)            {            case ThreadConstant.INDEX_1:                TraceLog.d("INDEX_1");                break;            case ThreadConstant.INDEX_2:                TraceLog.d("INDEX_2");                break;            case ThreadConstant.INDEX_3:                TraceLog.d("INDEX_3");                break;                }        }    }}
    private void initView() {        ...                btnStart3 = (Button) findViewById(R.id.thread_start_id3);        btnStart3.setOnClickListener(new OnClickListener() {                        @Override            public void onClick(View v) {                myHandlerThread.doAction((int)(Math.random()*3)+1, "handlerthread time millseconds");            }        });    }

以上是启动handlerthread的代码。

 

IntentService:

我们可以看看源码:

intentservice 本质上就是 service + handlerthread的组成方式!

public abstract class IntentService extends Service {    private volatile Looper mServiceLooper;    private volatile ServiceHandler mServiceHandler;    private String mName;    private boolean mRedelivery;    private final class ServiceHandler extends Handler {        public ServiceHandler(Looper looper) {            super(looper);        }        @Override        public void handleMessage(Message msg) {            onHandleIntent((Intent)msg.obj);            stopSelf(msg.arg1);        }    }    /**     * Creates an IntentService.  Invoked by your subclass's constructor.     *     * @param name Used to name the worker thread, important only for debugging.     */    public IntentService(String name) {        super();        mName = name;    }    /**     * Sets intent redelivery preferences.  Usually called from the constructor     * with your preferred semantics.     *     * <p>If enabled is true,     * {@link #onStartCommand(Intent, int, int)} will return     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before     * {@link #onHandleIntent(Intent)} returns, the process will be restarted     * and the intent redelivered.  If multiple Intents have been sent, only     * the most recent one is guaranteed to be redelivered.     *     * <p>If enabled is false (the default),     * {@link #onStartCommand(Intent, int, int)} will return     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent     * dies along with it.     */    public void setIntentRedelivery(boolean enabled) {        mRedelivery = enabled;    }    @Override    public void onCreate() {        // TODO: It would be nice to have an option to hold a partial wakelock        // during processing, and to have a static startService(Context, Intent)        // method that would launch the service & hand off a wakelock.        super.onCreate();        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");        thread.start();        mServiceLooper = thread.getLooper();        mServiceHandler = new ServiceHandler(mServiceLooper);    }    @Override    public void onStart(Intent intent, int startId) {        Message msg = mServiceHandler.obtainMessage();        msg.arg1 = startId;        msg.obj = intent;        mServiceHandler.sendMessage(msg);    }    /**     * You should not override this method for your IntentService. Instead,     * override {@link #onHandleIntent}, which the system calls when the IntentService     * receives a start request.     * @see android.app.Service#onStartCommand     */    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        onStart(intent, startId);        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;    }    @Override    public void onDestroy() {        mServiceLooper.quit();    }    /**     * Unless you provide binding for your service, you don't need to implement this     * method, because the default implementation returns null.      * @see android.app.Service#onBind     */    @Override    public IBinder onBind(Intent intent) {        return null;    }    /**     * This method is invoked on the worker thread with a request to process.     * Only one Intent is processed at a time, but the processing happens on a     * worker thread that runs independently from other application logic.     * So, if this code takes a long time, it will hold up other requests to     * the same IntentService, but it will not hold up anything else.     * When all requests have been handled, the IntentService stops itself,     * so you should not call {@link #stopSelf}.     *     * @param intent The value passed to {@link     *               android.content.Context#startService(Intent)}.     */    protected abstract void onHandleIntent(Intent intent);}
IntentService

我们首先看onCreate:

    public void onCreate() {        // TODO: It would be nice to have an option to hold a partial wakelock        // during processing, and to have a static startService(Context, Intent)        // method that would launch the service & hand off a wakelock.        super.onCreate();        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");        thread.start();        mServiceLooper = thread.getLooper();        mServiceHandler = new ServiceHandler(mServiceLooper);    }

开启了一个handlerthread,并且初始化mServiceHandler,

mServiceHandler就是一个普通的handler,只是把消息处理给了onHandleIntent

        public void handleMessage(Message msg) {            onHandleIntent((Intent)msg.obj);            stopSelf(msg.arg1);        }

所以intentservice实例就需要实现onHandleIntent方法,来处理消息。

一下是intentservice使用的一个demo:

package com.joyfulmath.androidstudy.thread;import com.joyfulmath.androidstudy.TraceLog;import android.app.IntentService;import android.content.Intent;public class MyIntentService extends IntentService {    public MyIntentService() {        super("MyIntentService");    }                @Override    public void onCreate() {        super.onCreate();        TraceLog.i();    }    @Override    protected void onHandleIntent(Intent intent) {        TraceLog.i();        doAction(intent);    }    @Override    public void onDestroy() {        super.onDestroy();        TraceLog.i();    }        private void doAction(Intent intent)    {        String params = intent.getStringExtra("key");        TraceLog.i(params);        int index = intent.getIntExtra("index", -1);        TraceLog.i(index+"");    }}
MyIntentService

可以看下log:

导出的log,没有tid,所以上传了图片。可以看到onHandleIntent运行在工作线程里面。

IntentService会在处理完了以后,直接destory掉。

 

  相关解决方案