Android 入门(九)Handler

363 阅读2分钟

要求:会使用Handler,知道looper的概念

创建 Handler 实例

创建实例有三种方式

// 1. 匿名内部类
// 如果匿名内部类持有外部类的引用,会造成内存泄漏
private Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_DOWNLOAD_FAIL:
                mTipText.setText("Download Failed");
                break;
            case MSG_DOWNLOAD_START:
                mTipText.setText("Download Start");
                break;
            case MSG_DOWNLOAD_SUCCESS:
                mTipText.setText("Download Success");
                break;
        }
    }
};

// 2. 实现 Handler 类
// 如果直接在 Activity 创建内部类也是会引起内存泄漏的,所以使用静态内部类,不会持有外部类的引用
public static class MyHandler extends Handler {
    // 使用弱引用来持有外部类对象,避免造成内存泄漏
    final WeakReference<MainActivity> mActivityWeakReference;
    public MyHandler(MainActivity activity) {
        mActivityWeakReference = new WeakReference<>(activity);
    }
    @Override
    public void handleMessage(Message msg) {
        MainActivity activity = mActivityWeakReference.get();
        switch (msg.what) {
            case MSG_DOWNLOAD_FAIL:
                activity.mTipText.setText("Download Failed");
                break;
            case MSG_DOWNLOAD_START:
                activity.mTipText.setText("Download Start");
                break;
            case MSG_DOWNLOAD_SUCCESS:
                activity.mTipText.setText("Download Success");
                break;
        }
    }
}

//3.callback方式
Handler callbackHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        //更新UI等操作
        return true;
    }
});

如果在主线程中实例化 MyHandler 类,Loop 已经创建在 Activity 被创建之前就创建好了。 如果在子线程中实例化 MyHandler 类,Loop 还没被创建,如果直接使用 MyHandler 对象就会报错,

throw new RuntimeException("Only one Looper may be created per thread")

这时候只需要在实例化 MyHandler 前,手动调用 Looper.prepare() 创建对象。

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

发送消息

发送消息有 2 种方法

// 1. sendMessage 方法
class MyThread extends Thread {
    @Override
    public void run() {
        Looper.myLooper();
        isDownloading = true;
        //发送空消息,其实就是发送了一个只携带了 what 字段的 Message
        mHandler.sendEmptyMessage(MSG_DOWNLOAD_START);
        try {
            // 模拟下载三秒
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Message message = new Message();
        // 必须的字段,用来区分不同的 Message
        message.what = MSG_DOWNLOAD_SUCCESS;
        // 可以传递两个 int 数据
        message.arg1 = 1;
        message.arg2 = 2;
        // 可以传递一个对象
        message.obj = new Object();
        mHandler.sendMessage(message);
        isDownloading = false;
        
        // 另一种方式
        // obtainMessage 其实就是填充 Message 的步骤
        // sendToTarget 就是执行 sendMessage
        //mHandler.obtainMessage(MSG_DOWNLOAD_SUCCESS, 1, 2).sendToTarget();
    }
}
// 2. post 方法
class MyPostThread extends Thread {
    @Override
    public void run() {
        isDownloading = true;
        Log.d(TAG, "run: Thread = " + Thread.currentThread().getId() +
                ", name = " + Thread.currentThread().getName());
        /*mHandler.post(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "run: Thread = " + Thread.currentThread().getId() +
                        ", name = " + Thread.currentThread().getName());
                // 更新 UI
                mTipText.setText("Download Start");
            }
        });*/
        // runOnUiThread 就是执行 Handler 的 post() 方法
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "run: Thread = " + Thread.currentThread().getId() +
                        ", name = " + Thread.currentThread().getName());
                // 更新 UI
                mTipText.setText("Download Start");
            }
        });
        try {
            // 模拟下载三秒
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "run: Thread = " + Thread.currentThread().getId() +
                        ", name = " + Thread.currentThread().getName());
                // 更新 UI
                mTipText.setText("Download Success");
            }
        });
        isDownloading = false;
    }
}