Android学习之异步操作处理机制

通过这篇文章你能学习到什么?

  1. 通过子线程更新UI组件:handler
  2. AsyncTask

首先我们介绍handler。

一、异步消息处理的主要组成部分

  1. Messger

    在线程之间传递消息,而且其内部携带少量信息。用于在不同的线程之间交换数据。

  2. Handler

    用于发送和处理信息。一般发送信息使用其handler.sendmessger()方法,经过一系列的处理以后,最后会发送到handler的handleMessger()方法中。

  3. MessgerQueue

    用于存放所有handler发送的信息。这些信息会一直存放在队列中,等待被处理。

  4. Looper

    looper相当于messgerQueue的管家。每当messgerQueue中存在一条信息时,就会调用looper中的loop()方法,将信息取出。并传递到handle的handleMessger()方法中。

二、代码演示

我们主要想实现通过点击按钮,改变TextView中的显示内容。
首先我们在xml文件中创建一个button以及一个textview。(代码较为简单,就不展示了)
然后修改MainActiviy:

public class MainActivity extends AppCompatActivity {

    public static final int UPDATE_text = 1; //设置一个标识符

    private TextView textView;

    @SuppressLint("HandlerLeak")
    Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what){
                case UPDATE_text:
                    textView.setText("nihaoshijie"); //改变Ui组件内容
                    break;
            }
        }
    };

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

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { //设置一个点击事件
            @Override
            public void onClick(View v) {
                new Thread(){  //设置一个子线程
                    @Override
                    public void run() {
                        Message message = new Message(); //设置一个messger对象
                        message.what = UPDATE_text;
                        handler.sendMessage(message);  //发送数据
                    }
                }.start();
            }
        });
    }
}

具体的代码如上图图所示,下面我们来根据代码分析下其异步处理的主要思路。

三、思路分析

首先我们需要明白一个点:

Android不推荐在子线程中直接更新UI组件,可能会出现不可知的错误。

而我们用handler异步处理机制。先在主线程中创建一个handler对象,并重写其handleMessger方法。然后当子线程中需要对UI进行处理的时候,就会创建一个messger对象,并通过handler将其发送出去。之后这条信息就会被添加到MessgerQueue的队列中等待被处理。而Looper会一直不断的尝试从MessgerQueue取出待处理信息,最后分发到Handler的handleMessger()方法中。由于handler是在主线程中创建的,所以handleMessger方法也在主线程中运行。这样就能安心的对ui进行操作啦。

下面我们来介绍AsyncTask

一、基本使用

首先我们需要为AsyncTask类指定三个泛型参数

  1. Params

    在执行AsyncTask需要传递的参数,可用于在后台任务使用。

  2. Progress

    后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。

  3. Result

    当任务执行完成以后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。

重写几个方法

  1. onPreExecute()

    这个方法在后台任务开始执行之前调用,用于进行一些界面上的初始化操作。

  2. doInBackground()

    这个方法中的所有代码都会在子线程中运行,我们应该在这个去处理所有的耗时任务。

  3. onProgressUpdate()

    这个方法可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。

  4. onPostExecute()

    当后台任务执行完毕并且用过return语句进行返回的时候,这个方法就会被调用。返回的数据会作为参数传递到此方法中,可以利用一些返回的数据进行一些UI操作。

二、具体代码演示

我们来制作一个倒计时的程序:

首先xml文件代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/et"
        android:layout_width="match_parent"
        android:layout_height="50dp" />
    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="倒计时"
        android:textSize="30sp"
        android:layout_gravity="center"
        />
    <Button
        android:id="@+id/bt"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="开始倒计时"
        android:textSize="20sp"/>

</LinearLayout>

然后是MainActivity中的代码:

public class MainActivity extends AppCompatActivity {

    private EditText et;
    private TextView tv;
    private Button bt;

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

        bindID();

        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int time = Integer.parseInt(et.getText().toString());
                new MyTask().execute(time);
            }
        });

    }

    private void bindID() {

        et = findViewById(R.id.et);
        tv = findViewById(R.id.tv);
        bt = findViewById(R.id.bt);
    }

    @SuppressLint("StaticFieldLeak")
    class MyTask extends AsyncTask<Integer,Integer,String> {
        @Override
        protected String doInBackground(Integer... integers) {
            for (int i=integers[0];i>0;i--){
                try {
                    Thread.sleep(1000);
                    publishProgress(i);//调用onProgressUpdate方法
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return "计时结束";
        }

        @SuppressLint("SetTextI18n")
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            tv.setText(values[0]+"");
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            tv.setText(s);
        }
    }
}

整体的代码逻辑还是比较简单的,主要是使用一下AsyncTask这个方法。

那么对于Android的异步消息处理机制就说到这里了。本来想加上一个RxJava的开源框架,但是篇幅有限。下次有机会再说~

猜你喜欢

转载自blog.csdn.net/qq_45637283/article/details/106568950