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


    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语句执行后,返回的数据会被传入这个函数,可以进行一些时候事后操作。

  • 相关阅读:
    硬件加速 Hardware Accelerated [MD]
    Redis 常见面试题(2020最新版)
    1秒时限情况下算法复杂度要求
    linux ikatago-server
    Linux踢出其他正在SSH登陆用户
    多个Git帐号的SSH key切换(不同网站的gitlab&github)
    RTL8201 替换适配国产JL11网卡
    网卡PHY 移植注意事项
    django shell执行命令来批量更新model 数据
    git 设置和取消socks5 代理
  • 原文地址:https://www.cnblogs.com/zllk/p/13424536.html
Copyright © 2020-2023  润新知