Handler Messenger 使用

                            Handler Messenger 使用

Android中如果所有的线程都可以更新UI那么会造成同步问题,因为UI的访问不是同步的,所以如果所有的线程都更新UI就会造成数据混乱,不为UI加锁进行同步的原因是这样会造成性能问题,所有的线程都想更新UI,造成大量的线程等待,影响性能。所以在android中只允许主线程更新UI,并且主线程也最好应该只做更新UI的事情。同时在主线程中执行耗时的操作会引发主线程阻塞,引发ANR问题,基于此Android才有了Handler,Message的技术。在主线程中启动子线程执行耗时的操作,然后将结果返回给主线程更新UI。以下将介绍Android中的Handler,Messager,Loader,AsyncTask

  1. Handler

通过Hander可以实现在子线程和主线程之间的通信。实现子线程执行结果的返回给主线程,用以更新UI,因为主线程需要子线程的执行结果,所以才需要通过handler的方式获取执行结果,如果主线程不需要和子线程进行通信,那主线程只需要启动一个子线程执行任务就可以,就不需要handler。

首先看一下handler的用法:通过一个 线程更新Button的显示

package com.example.myapplication;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Handler handler  = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            btn.setText("5s啦");
        }
    };

    Button btn = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        btn = findViewById(R.id.button);
        Thread t = new Thread(){
            @Override
            public void run() {
                super.run();

                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                Message  ms = Message.obtain();
                handler.sendMessage(ms);
            }
        };
        t.start();

    }
}

 

在子线程中使用Handler之前,我们需要先调用一个Looper.prepare()方法,之后还要调用Looper.loop().首先我们看一下Looper.perpare()方法.

 public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

可以看到调用Looper.prepae()方法最终,new了一个Looper对象,添加到一个名为sThreadLocal的ThreadLocal对象中,该ThreadLocal对象是一个静态的对象。通过Looper的构造方法可以看到,生成了一个MessageQueue,以及获得了当前的线程,通过这样将当前的线程和这个Looper对象关联起来。mQueue就是接受handler发送消息的队列。

 private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

接着我们看Looper.loop()方法

public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        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);
                }
            }
            if (slowDispatchThresholdMs > 0) {
                final long time = end - start;
                if (time > slowDispatchThresholdMs) {
                    Slog.w(TAG, "Dispatch took " + time + "ms on "
                            + Thread.currentThread().getName() + ", h=" +
                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);
                }
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }

在loop()方法中首先获取了,在prepare()方法中生成的Looper对象,以及QueueMessage对象,接着就进入一个死循环。

在循环中不断的从QueueMessage队列中获取Message,然后调用Message对象中target对象的dispatchMessage方法。

那么 Message对象中的target对象时什么呢,我们知道Message对象时通过handler的sendMessage方法发送的,所以我们

查看handler的sendMessage方法

 public final boolean sendMessage(Message msg) {
        return sendMessageDelayed(msg, 0);
 }


 public final boolean sendMessageDelayed(Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
 }


 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);
    }


private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

可以看到在enqueMessage方法中当前的Handler对象被赋值给Message的target属性,这样保证了,Message只能由发送他的

Handler进行处理。

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

在dispatchMessage方法中首先判断callback是一个Runnable对象,Runnable是通过handler的post方法传递进去的。即执行这个Runnable任务。mCallback对象时通过构造方法传入的Callback对象。如果在生成Handler对象的时候不传入参数,则就会执行我们在生成Handler的时候重写的handlerMessage方法。

2. Messager

Messager常用语服务端和客户端之间进行通信。所以首先需要一个Service服务。在服务中生成一个Messager对象,并传进去一个Handler对象,这个Handler对象将会捕获客户端传递进来的Message,然后进行相应的处理。Messenger有两个构造方法。都是需要传递一个参数的,通过采用第一种传递一个Handler对象,这个handler对象负责处理接收到的Message消息。

   /**
     * Create a new Messenger pointing to the given Handler.  Any Message
     * objects sent through this Messenger will appear in the Handler as if
     * {@link Handler#sendMessage(Message) Handler.sendMessage(Message)} had
     * been called directly.
     * 
     * @param target The Handler that will receive sent messages.
     */
    public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }
    
   /**
     * Create a Messenger from a raw IBinder, which had previously been
     * retrieved with {@link #getBinder}.
     * 
     * @param target The IBinder this Messenger should communicate with.
     */
    public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }

我们先创建一个Service服务,在这个服务中我们从客户端接收一个Message,然后打印一行log,显示Message中的消息。

package com.example.myapplication2;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.support.annotation.Nullable;
import android.util.Log;

public class MyService extends Service {


    private Messenger msg = new Messenger(new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg != null && msg.obj != null){
                Log.d("service",(String)msg.obj);
            }
        }
    });

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return msg.getBinder();
    }
}

接着我们在写一个Activity客户端,布局是一个EditText供用户输入,和一个Button点击发送。

package com.example.myapplication2;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class Client extends Activity {

    Button btn;
    EditText et;
    Messenger msg;

    ServiceConnection sc = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            msg = new Messenger(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.sendmsg);

        btn = findViewById(R.id.send);
        et = findViewById(R.id.edit);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String text = et.getText().toString();
                Message  m = Message.obtain();
                m.obj = text;
                try {
                    msg.send(m);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        Intent intent = new Intent(Client.this,MyService.class);
        bindService(intent,sc, Context.BIND_AUTO_CREATE);
    }
}

现在只能是client向Service发信息,Service负责相应,现在我们实现Service向服务端发送消息,客户端收到消息后,弹出一个Dialog.要想实现Service向客户端发送消息,我们就需要要在Service中获取客户端定义的Messenger对象,用它发送消息,这样客户端才能够接收到。怎么做呢,其实在客户端发送消息的时候,Message对象有一个replyTo的字段,这是一个Messenger类型的对象,这个字段就可以将客户端的Messenger对象带给Service,我们只需要在获取Message对象时,将客户端的Messenger对象赋值给Message的replyTo字段。

package com.example.myapplication2;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class Client extends Activity {

    Button btn;
    EditText et;
    Messenger msg;

    Messenger clinetMsg = new Messenger(new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            if(msg != null && msg.obj != null){

                AlertDialog.Builder b = new AlertDialog.Builder(Client.this);
                b.setTitle("Service say");
                b.setMessage((String)msg.obj);
                b.setPositiveButton("ok",null);
                b.create().show();
            }

        }
    });
    
    ServiceConnection sc = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            msg = new Messenger(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.sendmsg);

        btn = findViewById(R.id.send);
        et = findViewById(R.id.edit);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String text = et.getText().toString();
                Message  m = Message.obtain();
                m.obj = text;
                m.replyTo = clinetMsg;
                try {
                    msg.send(m);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
        Intent intent = new Intent(Client.this,MyService.class);
        bindService(intent,sc, Context.BIND_AUTO_CREATE);

    }
}

在服务 端我们只需要获取Message中的replyTo字段用它发送数据给客户端。

package com.example.myapplication2;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

public class MyService extends Service {


    Messenger clientMsg ;
    private Messenger msg = new Messenger(new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg != null && msg.obj != null){

                clientMsg = msg.replyTo;
                Message m = Message.obtain();
                m.obj = "Service have received";
                try {
                    clientMsg.send(m);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                Log.d("service",(String)msg.obj);
            }
        }
    });

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return msg.getBinder();
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值