Android 线程通信,初见

Android 主线程与子线程之间的通信,子线程与子线程之间的通信

1.主线程发消息,子线程执行操作

其实一般情况下,主线程执行完所有必备逻辑后,再直接new Thread().start();(注意,没考虑内存泄漏),因为我们一般没有必要让子线程一直卡在某一步,等待消息后才执行,如果子线程不卡着,子线程执行完后自动结束。当然,新start的Thread我们要确定它什么时间执行还是比较麻烦的。但真的需要主线程发消息,子线程收到消息后执行操作,可以使用下面这个方法。

//先创建一个子线程
HandlerThread handlerThread = new HandlerThread("name");//没看过源码,不知道参数具体作用,只知道是名字,类型为String
handlerThread.start();//记得要开始线程
/**
 * 注意,下面这才是重点(忽略我不规范的注释)
 * handler的handleMessage(Message msg)方法在哪一个线程执行,与handler在哪一个线程new没有关系,只与它所绑定的Looper有关,
 * 而Looper又与所在的线程绑定(一一对应),所以handler相当于与Looper身后的线程绑定。handler不带Looper参数的构造方法默认
 * 与当前线程的Looper绑定,主线程默认配置Looper,而子线程需要调用Looper.prepare()后才被系统配置,因此子线程中handler的初
 * 始化要放在Looper.prepare()和Looper.loop()(这是一个死循环)之间,基础不够扎实,还不知道找子线程中使用loop(),会不会造
 * 成内存泄漏
 */
Handler mHandler = new Handler(handlerThread.getLooper(), new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        //这部分的操作都是在子线程中执行的
        return false;
    }
});

当然,也可以自定义一个thread类,提供一个接口出来,接口方法可以根据自身需求定义,thread里的run方法里是个死循环,然后主线程调用接口了,子线程才执行后面的操作(非常不推荐)

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    MyThread myThread = new MyThread();
    OnMessageArrivedListener onMessageArrivedListener = myThread.getOnMessageArrivedListener();
    new Thread(myThread).start();
    //根据自己的时机调用
    onMessageArrivedListener.onMessageArrived();
}

class MyThread implements Runnable{
    
    private boolean hasArrived = false;
    private OnMessageArrivedListener onMessageArrivedListener = new OnMessageArrivedListener() {
        @Override
        public void onMessageArrived() {
            hasArrived = true;
        }
    };
    public OnMessageArrivedListener getOnMessageArrivedListener(){
        return onMessageArrivedListener;
    }
    
    @Override
    public void run(){
        while(!hasArrived){}
        //下面执行子线程操作
    }
}

interface OnMessageArrivedListener{
    void onMessageArrived();
}

可不可以用在主线程里使用的handler发送消息,自定义的子线程收到消息后再执行后续的操作呢?可以,就是有一点麻烦,需要在子线程拥有自身的Looper后,才可以,这就很麻烦了,尽管子线程可以直接把Looper或者handler开放出来,但主线程却不知何时才能使用它,这个强烈不建议使用。

2.子线程发消息,主线程执行操作

这个是最简单,也是用的最多的

我们可以在主线程创建一个全局的或者final修饰的handler对象,初始化之后,再调用newThread().start();然后在子线程中直接使用handler就可以了,非常简单方便

private Handler mHandler;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            //这里的操作在主线程执行
            return false;
        }
    });
    new Thread(new Runnable() {
        @Override
        public void run() {
            mHandler.sendEmptyMessage(1);
        }
    }).start();
}

还有一种方式,就是在子线程里创建handler对象,前面说过,handler里handleMessage在哪个线程执行与在哪new无关,这种方式同样十分简单方便

new Thread(new Runnable() {
    @Override
    public void run() {
        Handler handler = new Handler(getMainLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                //这里的操作在主线程执行
                return false;
            }
        });
    }
}).start();

3.子线程与子线程之间通信

扫描二维码关注公众号,回复: 9659698 查看本文章

个人建议是用主线程做中间媒介,一个子线程执行完了,发消息给主线程,主线程收到消息后再创建下一个子线程,相当于间接地实现了子线程与子线程之间的通信

如果你觉得这个不满意,我自己还想了一种方法,不过这方法我自己个人都不建议,建议去其他博客找更好的方法

这个方法跟之前提的也差不多,就是,两个子线程都引用同一个接口对象,在收消息的子线程创建接口实例对象,发消息的子线程执行完操作后调用这个接口的方法,方法根据自己需求定义,收消息的子线程因为引用相同的接口实例对象,从而达到获取消息的目的

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    GetMessageThread getMessageThread = new GetMessageThread();
    SendMessageThread sendMessageThread = new SendMessageThread();
    //此时他们还只是个孩子。。。他们还只是一个类对象,还不是子线程
    sendMessageThread.setOnMessageArrivedListener(getMessageThread.getOnMessageArrivedListener());
    //执行完下面的代码他们就是了,注意顺序,尽管可能没什么用
    new Thread(getMessageThread).start();
    new Thread(sendMessageThread).start();
}

interface OnMessageArrivedListener{
    void onMessageArrived(Object object);//所有都是自定义,可根据需求修改,返回值类型也是自定义
}

class GetMessageThread implements Runnable{
    private boolean isOk = false;
    private OnMessageArrivedListener onMessageArrivedListener = new OnMessageArrivedListener() {
        @Override
        public void onMessageArrived(Object object) {
            //根据收到的消息决定isOk的值
            //如
            isOk = true;
        }
    };

    //返回接口对象给发消息的子线程
    public OnMessageArrivedListener getOnMessageArrivedListener(){
        return onMessageArrivedListener;
    }

    @Override
    public void run(){
        while (true){
            if(isOk){
                //执行操作
                break;
            }
        }
    }
}

class SendMessageThread implements Runnable{
    private OnMessageArrivedListener onMessageArrivedListener;
    public void setOnMessageArrivedListener(OnMessageArrivedListener onMessageArrivedListener){
        this.onMessageArrivedListener = onMessageArrivedListener;
    }
    
    @Override
    public void run(){
        //执行操作,根据需要的时机调用接口方法
        Object o = new Object();//自己决定传什么
        while(true){
            if(onMessageArrivedListener != null){
                onMessageArrivedListener.onMessageArrived(o);
                break;
            }
        }
    }
}

这个方法因为我自身计算机系统基础不是很扎实,我自己都不知道会不会造成死锁,设计师说,这真的是糟糕透了!所以我也强烈不推荐这个方法

2019/5/8 留言:
没有修改博文,但还是要特别说一下,一定一定不要随随便便就用new Thread(),麻烦给Thread传一个名字啊,new Thread(CustonName)就好了,出现泄漏至少还能定位到哪里出的问题,不然你看到的只有Thread-1,Thread-2。。。

其实如果觉得比较麻烦,不妨试一下三方库EventBus,还是挺好用的,消息几乎哪里都可以达到

发布了24 篇原创文章 · 获赞 2 · 访问量 3686

猜你喜欢

转载自blog.csdn.net/ALee_130158/article/details/82466555