美文网首页
Android Thread单例+Handle单例 实现异步任务

Android Thread单例+Handle单例 实现异步任务

作者: GODANDDEVIL | 来源:发表于2020-03-07 11:14 被阅读0次

1、先写布局,布局代码activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context=".MainActivity">

    <Button
        android:layout_centerInParent="true"
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点我加载"
        android:onClick="click"/>

    <TextView
        android:id="@+id/text"
        android:layout_below="@+id/button"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="还没开始加载!" />

    <ProgressBar
        android:layout_below="@+id/text"
        android:id="@+id/progress_bar"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:progress="0"
        android:max="100"
        style="?android:attr/progressBarStyleHorizontal"/>

    <Button
        android:layout_below="@+id/progress_bar"
        android:layout_centerInParent="true"
        android:id="@+id/cancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="cancel"
        android:onClick="click"/>
</RelativeLayout>

2、Thread+Handler实现异步,我用到两种方法,第一种方法是单例类结合接口回调的方式实现,第二种是静态内部类加弱引用实现。
第一种方法,单例结合接口回调:
(1)封装一个Handler的单例类MyHandler,并定义InMyHandler接口回调:

/**
 * Handler单例的封装
 */
public class CustomHandler extends Handler {
    private CustomHandler(){}
    private static class CustomHandlerHolder{
        private static final CustomHandler INSTANCE = new CustomHandler();
    }
    public static CustomHandler getInstance(){
        return CustomHandlerHolder.INSTANCE;
    }//返回线程安全的单例

    @Override
    public void handleMessage(Message message){//重写handleMessage方法
        super.handleMessage(message);
        if (inCustomHandler == null) return;
        inCustomHandler.InHandleMessage(message);//调用接口方法
    }

    private static InCustomHandler inCustomHandler;//定义接口变量
    public interface InCustomHandler{//定义接口
        void InHandleMessage(Message message);//定义接口方法
    }
    public void setInCustomHandler(InCustomHandler inCustomHandler){//注册接口的方法
        CustomHandler.inCustomHandler = inCustomHandler;//接口的引用指向它的实例化对象,传入的参数inCustomHandler为实现该接口的类的实例化对象
    }
    public void removeInCustomHandler(){//取消注册接口的方法
        CustomHandler.inCustomHandler = null;//inCustomHandler置为null,inCustomHandler将不再持有外部类引用
    }
}

(2)封装一个Thread的单例类MyThread并实现Runnable接口,定义InMyHandler接口回调:

/**
 * Thread单例的封装
 */
public class MyThread extends Thread implements Runnable {
    private MyThread(){}
    private static class MyThreadHolder{
        private static final MyThread INSTANCE = new MyThread();
    }
    static MyThread getInstance(){//返回线程安全的单例
        return MyThreadHolder.INSTANCE;
    }

    @Override
    public void run(){//重写run()方法
        if (inMyThread!=null){
            inMyThread.run();//调用接口方法
        }
    }

    private static InMyThread inMyThread;//定义接口变量
    public interface InMyThread{//定义接口
        void run();//定义接口方法
    }
    void setInMyThread(InMyThread inMyThread){//注册接口的方法
        MyThread.inMyThread = inMyThread;//接口的引用指向它的实例化对象,传入的参数inMyHandler为实现该接口的类的实例化对象
    }
    void removeInMyThread(){//取消注册接口的方法
        MyThread.inMyThread = null;//inMyThread置为null,inMyHandler将不再持有外部类引用
    }

}

(3)在MainActivity.Java中使用:

import android.os.Bundle;
import android.os.Message;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

public class ThreadActivity extends FatherActivity implements MyHandler.InMyHandler,MyThread.InMyThread{//实现InMyHandler跟InMyThread接口
    //显示进度的文本
    TextView text;
    //进度条
    ProgressBar progressBar;

    //加载按钮在进度过程中的点击次数,防止没加载完再次点击了加载按钮
    int tag;
    //为Thread设置终止标志位
    boolean isStop;

    //定义全局MyHandler变量
    MyHandler myHandler;
    //定义全局MyThread变量
    MyThread myThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread);
        //获取控件
        text = findViewById(R.id.text);
        progressBar = findViewById(R.id.progress_bar);

        tag = 0;
        isStop = false;

        //实例化MyHandler对象并注册InMyHandler接口
        myHandler = MyHandler.getInstance();
        myHandler.setInMyHandler(this);
        //实例化MyThread对象并注册InMyThread接口
        myThread = MyThread.getInstance();
        myThread.setInMyThread(this);
    }

    /**
     * 异步多线程:Thread+Handler
     */
    //实现InMyHandler的接口方法
    @Override
    public void InHandleMessage(Message message){
        //执行逻辑
        progressBar.setProgress(message.what);
        if (message.arg1==101){
            if (message.what==100){
                text.setText("加载完毕");
            }else {
                text.setText("loading..." + message.what + "%");
            }
        }else if (message.arg1==102){
            text.setText("已取消");
        }
    }
    //实现InMyThread的接口方法
    @Override
    public void run(){
        //执行逻辑
        try {
            int count = 0;
            int length = 1;
            while (count<100) {
                if (isStop){//点击了取消按钮,改变了标志位的值,终止当前线程
                    count = 100;//直接将count设置成100,跳出循环
                    if (myHandler!=null){
                        sendMessage(0,102);
                    }
                }else {
                    count += length;
                    // 模拟耗时任务
                    myThread.sleep(500);
                    if (myHandler!=null){
                        sendMessage(count,101);
                    }
                }
            }
            if (count==100){//重置tap和isStop
                tag = 0;
                isStop = false;
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //myHandler发送message
    void sendMessage(int what, int arg1){
        Message message = new Message();
        message.what = what;
        message.arg1 = arg1;
        myHandler.sendMessage(message);
    }

    //点击事件
    public void click(View view){
        switch (view.getId()){
            case R.id.button:
                tag++;
                if (tag<2){
                    myThread.start();//启动线程
                }
                break;
            case R.id.cancel:
                if (tag!=0){//只有当点击了加载按钮,取消按钮才生效
                    isStop = true;
                }
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        isStop = true;//置为true使得Thread终止,避免内存泄漏(必要)
        myHandler.removeInMyHandler();//myHandler取消注册接口,避免内存泄漏(必要)
        myThread.removeInMyThread();//myThread取消注册接口,避免内存泄漏(必要)
//        myHandler.removeCallbacksAndMessages(null);//销毁移除所有消息,避免内存泄露,参数null代表移除所有回调跟消息

    }


}

这里说说大概思路:
(1)MainActivity分别实现InMyHandler接口和InMyThread接口
(2)分别声明两个单例对象
(3)分别实例化两个单例对象,并注册接口
(4)实现接口回调的方法
(5)启动线程
(6)最后,要特别注意的,在Activity销毁时需要将isStop置为true来终止当前线程,另外还要取消两个接口的注册,否则线程和接口会持有当前Activity的引用,使Activity不能够被回收造成内存泄漏。

注意:handler在Activity中是一个内部类并且持有activity的引用,如果activity被销毁,但是handler还在执行,那么在垃圾回收的时候就无法回收activity,就会造成内存泄漏。(在java中非静态内部类和匿名内部类都会隐式持有当前类的外部引用,由于Handler是非静态内部类所以其持有当前Activity的隐式引用,如果Handler没有被释放,其所持有的外部引用也就是Activity也不可能被释放,当一个对象不需要再使用了,本来该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏)

3、Thread+Handler实现异步的第二种方法,是静态内部类加弱引用实现,下面看MainActivity.java代码:

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.lang.ref.WeakReference;

public class ThreadActivity extends FatherActivity{
    //显示进度的文本
    TextView text;
    //进度条
    ProgressBar progressBar;

    //加载按钮在进度过程中的点击次数,防止没加载完再次点击了加载按钮
    int tag;
    //为Thread设置终止标志位
    boolean isStop;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread);
        //获取控件
        text = findViewById(R.id.text);
        progressBar = findViewById(R.id.progress_bar);

        tag = 0;
        isStop = false;

    }

    /**
     * 异步多线程:Thread+Handler
     */
    //myHandler发送message
    void sendMessage(int what, int arg1){
        Message message = new Message();
        message.what = what;
        message.arg1 = arg1;
        myHandler.sendMessage(message);
    }

    MyHandler myHandler = new MyHandler(this);//MyHandler实例对象
    static class MyHandler extends Handler {//MyHandler静态内部类
        WeakReference<Context> weakReference;//弱引用对象
        MyHandler(Context context) {
            weakReference = new WeakReference<>(context);
        }
        @Override
        public void handleMessage(Message msg) {
            ThreadActivity threadActivity = (ThreadActivity) weakReference.get();
            if (threadActivity != null) {
                threadActivity.progressBar.setProgress(msg.what);
                if (msg.arg1==101){
                    if (msg.what==100){
                        threadActivity.text.setText("加载完毕");
                    }else {
                        threadActivity.text.setText("loading..." + msg.what + "%");
                    }
                }else if (msg.arg1==102){
                    threadActivity.text.setText("已取消");
                }
            }
        }
    }

    MyRunnable myRunnable = new MyRunnable(this);//MyRunnable实例对象
    static class MyRunnable extends Thread implements Runnable{//MyRunnable静态内部类
        WeakReference<Context> weakReference;//弱引用对象
        MyRunnable(Context context){
            weakReference = new WeakReference<>(context);
        }
        @Override
        public void run() {
            ThreadActivity threadActivity = (ThreadActivity)weakReference.get();
            if (threadActivity!=null){
                try {
                    int count = 0;
                    int length = 1;
                    while (count<100) {
                        if (threadActivity.isStop){//点击了取消按钮,改变了标志位的值,终止当前线程
                            count = 100;
                            threadActivity.sendMessage(0,102);
                        }else {
                            count += length;
                            // 模拟耗时任务
                            Thread.sleep(500);
                            threadActivity.sendMessage(count,101);
                        }
                    }
                    if (count==100){//重置tap和isStop
                        threadActivity.tag = 0;
                        threadActivity.isStop = false;
                    }
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //点击事件
    public void click(View view){
        switch (view.getId()){
            case R.id.button:
                tag++;
                if (tag<2){
                    myRunnable.start();//启动线程
                }
                break;
            case R.id.cancel:
                if (tag!=0){//只有当点击了加载按钮,取消按钮才生效
                    isStop = true;
                }
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        isStop = true;//置为true使得Thread终止

    }


}

静态的内部类是随着类的加载而加载的,不会持有外部类的引用,同时根据WeakReference弱引用的特点,在GC回收时能回收弱引用对象。
.get()方法是判断这个对象是否被回收,对象如果存在才能做后面的操作。另外有时候,我们需要在Activity的onDestroy()或者onStop()中调用myHandler.removeCallbacksAndMessages(null);来移除所有消息和Runnable,参数null代表删除所有的消息和回调。

异步消息机制
异步消息处理由 4 个部分组成。
1、 Message
Message 可以在线程之间传递消息。可以在它的内部携带少量数据,用于在不同线程之间进行数据交换。除了 what 字段,还可以使用 arg1 和 arg2 来携带整型数据,使用 obj 来携带 Object 数据。

2、 Handler
Handler 用于发送(sendMessage 系列方法)与处理消息(handleMessage 方法)。

3、MessageQueue
MessageQueue 用于存放所有通过 Handler 发送的消息 。 这部分消息会一直存放在消息队列中,直到被处理 。 每个线程中只会有一个 MessageQueue 对象 。

4、 Looper
Looper 用于管理 MessageQueue 队列,调用 Looper.loop() 方法之后,就会进入无限循环中,每当发现 MessageQueue 存在一条消息,就会将它取出,并传递到 Handler 的 handleMessage() 方法中。每个线程中只会有一个 Looper 对象。

异步消息处理流程

  1. 在主线程中创建 Handler 对象,并重写 handleMessage() 方法。
  2. 子线程进行 UI 操作时,创建 Message 对象,通过 Handler 发送这条消息。
  3. Looper 从 MessageQueue 中取出待处理消息。
  4. 最后分发回 Handler 的 handleMessage() 方法中。
    其中前两步是代码可见的

参考:https://www.jianshu.com/u/383970bef0a0

相关文章

  • Android Thread单例+Handle单例 实现异步任务

    1、先写布局,布局代码activity_main.xml: 2、Thread+Handler实现异步,我用到两种方...

  • 【设计模式】单例模式

    单例模式 常用单例模式: 懒汉单例模式: 静态内部类单例模式: Android Application 中使用单例模式:

  • LayoutInflater源码分析

    在《(-)Android中的单例模式》分析中,我们分析了Android中单例模式的实现,且以LayoutInfla...

  • iOS 单例

    单例模式实现不能使用继承 定义单例实现 简写 定义单例实现宏

  • Android设计模式总结

    单例模式:饿汉单例模式://饿汉单例模式 懒汉单例模式: Double CheckLock(DCL)实现单例 Bu...

  • iOS 单例模式 - 单例对象销毁【GCD】

    单例对象的创建方式 单例.h 文件的实现 单例的.m 文件的实现 单例对象的销毁【GCD创建的方式】 使用单例对象...

  • iOS 单例模式 - 单例对象销毁【@synchronized】

    单例对象的创建方式 单例.h 文件的实现 单例.m 文件的实现 单例对象的销毁【@synchronized创建方式...

  • 单例模式(二)

    单例模式在Android源码中的应用 除了之前说的几种单例的实现方式之外还可以使用容器来实现。 在Android的...

  • 单例模式和GCD单例实现

    1、传统单例模式2、GCD单例模式3、用宏实现GCD单例模式4、用宏实现GCD单例模式,名称随类名变化而变化 单例...

  • python面试题-2018.1.30

    问题:如何实现单例模式? 通过new方法来实现单例模式。 变体: 通过装饰器来实现单例模式 通过元类来创建单例模式...

网友评论

      本文标题:Android Thread单例+Handle单例 实现异步任务

      本文链接:https://www.haomeiwen.com/subject/rwdgrhtx.html