《第一行代码》阅读笔记(三十一)——多线程

Android的多线程和Java的多线程差距并不大。

创建线程的方法

  1. 继承Thread
public class MyThread extends Thread {
    @Override
    public void run() {
        //需要处理的逻辑
    }
}

new MyThread().start();
使用的时候直接实例化,然后start就行了。

2.实现Runnable

public class MyThread implements Runnable {
    @Override
    public void run() {
        //需要处理的逻辑
    }
}
MyThread thread = new MyThread();
        new Thread(thread).start();

使用的时候需要实例化MyThread,然后作为参数传入Thread,然后start即可

  1. 匿名类
new Thread(new Runnable() {
            @Override
            public void run() {
                //需要处理的逻辑
            }
        }).start();

这种最常用

Demo

首先就是一个错误案例,在子线程中更新UI会报以下错误 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

解决的办法就是Handler。具体的解释书中已经详细介绍了。而且在前面的章节,笔者补充了progressdialog控件的用法中也提到了。

参考代码如下

package com.firstcode.androidthreadtest;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    public static final int UPDATE_TEXT = 1;
    private TextView textView;

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

        Button button = findViewById(R.id.change_text);
        textView = findViewById(R.id.text);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message message = new Message();
                        message.what = UPDATE_TEXT;
                        handler.sendMessage(message);
                    }
                }).start();
            }
        });

    }

    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler() {

        public void handleMessage(Message message) {
            switch (message.what) {
                case UPDATE_TEXT:
                    textView.setText("Nice to meet you");
                    break;
                default:
                    break;
            }
        }
    };
}

异步消息处理机制

  1. Message
    简单来说就是一个信息传递的媒介,Message的what字段可以传递数据,除此之外还可以使用arg1和arg2字
    段来携带一些整型数据,使用obj字段携带一个0bject对象。

  2. Handler
    是对消息的管理,从sendMessage发出,在通过handleMessage接收。一来一回就把操作带回主线程了。

  3. MessageQueue
    消息队列,所有的Message都存放在其中。每个线程只有一个MessageQueue对象

  4. Looper
    其中的loop()方法会无限循环,从MessageQueue中寻找Message,然后传到Handler

整个流程如下

首先应该实例化一个Handler,然后设定好需要接收信息内容,这里是使用的handleMessage()方法。然后在子线程中使用实力出来的Handler发送Message,使用的是sendMessage方法。之后信息就被存到MessageQueue中。最后Looper无限循环,取出Message和handleMessage中的匹配,然后进行操作。

AsyncTask

  1. 参数
  • Params。在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
  • Progress。后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
  • Result。当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
public class DownloadTask extends AsyncTask<Void, Integer, Boolean> {
...
}

这里我们把AsyncTask的第一个泛型参数指定为Void,表示在执行AsyncTask的时候不需 要传入参数给后台任务。第二个泛型参数指定为Integer,表示使用整型数据来作为进度显示单位。第三个泛型参数指定为Boolean,则表示使用布尔型数据来反馈执行结果。

  1. 方法

书中的方法都是简写,所以在这里就不粘代码了。简单表达一些笔者的看法。

    @Override
    protected void onPreExecute() {
    }

会在子线程任务开始执行前执行,就是进行一些简单的初始化操作。例如进度条对话框的展示。

    @Override
    protected Boolean doInBackground(Void... voids) {
    }

这里就是子线程任务的方法,也就是耗时任务,整个方法都会在子线程里面运行,然后返回值就是操作则结果。如果AsyncTask第三个参数传入的是void,就不需要返回结果。当然,既然是子线程,就不能对UI进行操作,如果需要更新UI,就需要使用publishProgress();

    @Override
    protected void onProgressUpdate(Integer... values) {
    }

如果在doInBackground中调用了publishProgress,立马就是调用onProgressUpdate,在这里可以对UI进行修改。

    @Override
    protected void onPostExecute(Boolean aBoolean) {
    }

return语句执行后,返回的数据会被传入这个函数,可以进行一些时候事后操作。

原文地址:https://www.cnblogs.com/zllk/p/13424536.html