Android第一行代码(十二)多线程编程

线程的基本用法:

定义一个线程只需要新建一个类继承自Thread,然后重新父类的run()方法,并在里面编写耗时逻辑即可

class MyThread extends Thread{
    @Override
    public void run(){
        //处理具体的逻辑
    }
}

然后启用这个线程,只需要调用该类的start方法即可:

new MyThread().start()

但是使用继承的方式耦合性有点高,更多时候选择使用实现Runable接口的方式来定义一个线程

class MyThread implemens Runnable {
    @Override
    public void run(){
        //处理具体逻辑
    }
}

使用这种写法,启动线程是:

MyThread myThread = new MyThread();
new Thread(myThread).start();

Android是不允许在子线程中进行UI操作的,我们可以利用Android提供的异步消息机制,来解决在子线程中进行UI操作的问题。

public class MainActivity extends AppCompatActivity {

    public  static final int UPDATE_TEXT = 1;

    private TextView text;

    //消息接收处理的handler
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
              
            switch (msg.what){
                case UPDATE_TEXT:
                    Log.d("MainActivity","test");

                    //在这里进行UI操作
                    Log.d("MainActivity",""+msg.arg1);
                    text.setText("Nice to meet you");
                    break;
                default:
                    break;
            }
        }
    };

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

        text = (TextView)findViewById(R.id.text);
        Button changeText = (Button)findViewById(R.id.change_text);
        changeText.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //在子线程里发送更新文字的message
                        Message message = new Message();
                        message.what = UPDATE_TEXT;
                        message.arg1 = 1;
                        handler.sendMessage(message);
                    }
                }).start();
            }
        });
    }
}

解析异步消息处理机制:

Android的异步消息处理主要由4个部分组成:Message、Handler、MessageQueue和Looper

  1. Message
    Message 是在线程之间传递的消息,可在内部携带少量的信息,用于不同线程之间交换数据。
    有what、arg1、arg2来携带一些整形数据,使用obj字段携带一个Object对象
  2. Handler
    Handler 顾名思义也就是处理者的意思,它主要是用于发送和处理消息。
    发送消息一般使用Handler的sendMessage()方法;处理消息使用Handler的 handleMessage()方法
  3. MessageQueue
    MessageQueue是消息队列的意思,它主要是用于存放所有通过Handler发送的消息。这部分消息会一直存放在消息队列中,等待被处理。每个线程中只会有一个Message对象。
  4. Looper
    Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无线循环当中,然后每当发现MessageQueue中存在一条消息,就会将它取出,并传递到Handler的handleMessage()方法当中
Android第一行代码(十二)多线程编程_第1张图片
异步消息处理流程.png

使用AsyncTask

由于AsyncTask是一个抽象类,所以要使用它,就必须创建一个子类去继承它。在继承时,可以为AsyncTask类指定3个泛型参数,这3个参数的用途如下:

  1. Params
    在执行AsyncTask时需要传入的参数,可用于在后台任务中使用
  2. Progress
    后台任务执行时,如果需要在界面上显示当前进度,则使用这里指定的泛型作为进度单位
  3. Result
    当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型

使用AsyncTask还经常需要重写以下4个方法:

  1. onPreExecute()
    在后台任务开始执行之前调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框

  2. doInBackground(Params...)
    这个方法中所有的代码都在子线程执行,应该在这里处理所有的耗时任务。在这个方法中是不能进行UI操作的,只能调用publishProgress(Progress...)方法将数值传递出去,并触发 onProgressUpdate(Progress...)方法

  3. onProgressUpdate(Progress...)
    当在后台任务中调用了publishProgress(Progress...)方法后,onProgressUpdate(Progress...)方法就会很快被调用,该方法中携带的参数就是在后台任务中传递过来的,在这个方法中可以对UI进行操作。

  4. onPostExecute(Result)
    后台任务执行完毕并通过return语句进行返回时,这个方法就很快被调用,返回的数据就会作为参数传递到此方法之中,可以利用返回的数据来进行一些UI操作。

    public class DownloadTask extends AsyncTask {
    ProgressDialog progressDialog = new ProgressDialog();

     @Override
     protected void onPreExecute() {
         progressDialog.show(); //显示进度对话框
     }
    
     @Override
     protected Boolean doInBackground(Void... params) {
         try {
             while (true) {
                 int downloadPercent = doDownload();
                 //此处调用publishProgress()方法,会触发 onProgressUpdate()方法
                 publishProgress(downloadPercent);
                 if (downloadPercent >= 100) {
                     break;
                 }
             }
         }catch(Exception e){
             return false;
         }
             return  true;
    
         }
     }
    
     @Override
     protected void onProgressUpdate(Integer... values) {
         //在这里进行UI操作,更新进度条
         progressDialog.setMessage("Downloaded " + values[0] + "%");
     }
    
     @Override
     protected void onPostExecute(Boolean result) {
         progressDialog.dismiss();
         //在这里提示下载结果
         if(result) {
             Toast.makeText(context, "Download successed", Toast.LENGTH_SHORT).show();
         }else {
             Toast.makeText(context, "Download faild", Toast.LENGTH_SHORT).show();
         }
     }
    

    }

启用这个任务,只需要

new DownloadTask().execute();

简单来说,使用AsyncTask的诀窍就是,在onPreExecute()方法中进行初始化工作,在doInBackground()方法中执行具体的耗时任务,在onProgressUpdate()方法中进行UI操作,在onPostExecute()方法中执行一些任务的收尾工作。
而调用publishProgress()方法,能够将数据从后台传递到主线程,触发onProgressUpdate(Progress...)方法

你可能感兴趣的:(Android第一行代码(十二)多线程编程)