Android学习之进程与消息处理(二)

Android学习之消息处理

  1.1 Handler的基本概念
  Handler类是Android为开发者封装的一个能异步处理消息的辅助类。通过Handler能够很容易的处理消息的发送和接收处理。Handler运作的过程中包含了Android的消息机制。
  1.2 Handler的使用方法
  1.2.1 在Activity中使用Handler
  · 在主线程创建一个handler对象,并重写其HandlerMessage()方法;
  · 创建子线程对象,重写其run()方法:run方法中,定义Message对象,设定传递的数据,通过主线程创建的handler对象发送该Message对象;
  · 在Handler对象重写的handleMessage()方法中:接受子线程的Message对象并进行处理,Message对象中包含的数据,就是子线程传递的数据。

  ☆☆☆Android Studio实现在Activity中使用Handler
  1.打开Android Studio,新建工程后,在activity_main.xml中界添加一个按钮和一个TextView。


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="lession.example.com.androidlession2019522_3.MainActivity">
    
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <Button
            android:text="Handler的使用"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/button"
            android:textAllCaps="false"
            android:textColor="@android:color/holo_red_dark" />
            
        <TextView
            android:text="TextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/textView"
            android:textColor="@android:color/background_dark" />
            
    LinearLayout>
RelativeLayout>

  2.在MainActivity中,编写代码。

package lession.example.com.androidlession2019522_3;

import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    TextView tv;
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 1:
                    tv.setText("处理完毕");
            }
        }
    };
    private Thread mThread = new Thread(){
        @Override
        public void run() {
            super.run();
            SystemClock.sleep(2000);
            Message msg = new Message();
            msg.what = 1;
            msg.obj = "获取数据:";
            mHandler.sendMessage(msg);
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button bt = (Button) findViewById(R.id.button);
        tv = (TextView) findViewById(R.id.textView);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mThread.start();
            }
        });
    }
}

  运行结果:
  Android学习之进程与消息处理(二)_第1张图片

  1.2.2 在子线程中使用Handler
  · 在创建Handler之前,需要使用Lopper对象的prepare()方法:该方法可以获取到MessageQueue(消息队列)对象;
  · 实例化Handler对象,并重写其HandleMessage()方法:获取传递过来的信息,并进行处理;
  · 在实例化Handler对象后,使用Lopper对象的Loop()方法:该方法以死循环的方式,监控消息队列的变化,若有消息,则接收消息,并回调对应的HandleMessage()方法。

  ☆☆☆Android Studio实现在在子线程中使用Handler
  在上个实验的基础上修改,activity_main.xml文件中不变,在MainActivity中,编写代码。

package lession.example.com.androidlession2019522_3;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    Handler hinHandler;
    TextView tv;
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 1:
                    tv.setText("线程计算结果:"+msg.arg1);
            }
        }
    };
    
    private Thread mThread = new Thread(){
        @Override
        public void run() {
            Looper.prepare();
            hinHandler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what){
                        case 1:
                            int rz = msg.arg1+msg.arg2;
                            Message hinMsg = new Message();
                            hinMsg.what=1;hinMsg.arg1=rz;
                            mHandler.sendMessage(hinMsg);
                            break;
                    }
                }
            };
            Looper.loop();
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button bt = (Button) findViewById(R.id.button);
        tv = (TextView) findViewById(R.id.textView);
        mThread.start();
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg = new Message();
                msg.what = 1;
                msg.arg1 = 100;msg.arg2 = 200;
                hinHandler.sendMessage(msg);
            }
        });
    }
    
}

  运行结果:
  Android学习之进程与消息处理(二)_第2张图片
  1.2.3 主线程与子线程使用Handler的区别
  · 在主线程中,可以直接实例化Handler对象使用:在Activity的启动过程中,已经调用了Looper的相关方法;
  · 子线程是由用户设计的,因此相关方法的调用,需要用户实现:在实例化Handler对象前,调用Looper对象的prepare()方法,创建一个消息循环,用来获取消息;在实例化Handler对象后,调用Looper对象的loop()方法,启动消息循环,从消息队列中获取消息,Loop()会以死循环方式执行,其后的代码不会被执行。

  1.3 与消息处理相关的类:
  Message:Message是在线程之间传递的消息。
  它可以在内部携带少量的数据,用于线程之间交换数据,Message有四个常用的字段what字段:
  arg1字段,arg2字段:可以存储整数;
  obj字段:可以存储对象。
  Handler:它主要用于发送和处理消息。
  发送消息一般使用sendMessage()方法,而发出的消息最终会传递到Handler的handleMessage方法中。
  Message Queue:主要用于存放所有通过Handler发送的消息。
  消息会一直存在于消息队列中,等待被处理。
  Looper:Handler与MessageQueue之间的桥梁。
  Looper通过不停循环,发现Message Queue中存在新消息,就会将它取出并传递到Handler的handleMessage()方法中。
  ThreadLocal:Thread Local是一个线程内部的数据存储类。
  通过TreadLocal可以在指定线程中存储数据,数据存储以后,也只有在指定线程中可以获取到存储到数据。
  1.4 Android消息机制
  Android的消息机制就是通过Handler、Looper和消息队列来异步处理线程在执行的过程中所引起线程阻塞或线程不安全任务的机制。其中MessageQueue是消息能够异步执行的数据结构;Looper对象则充当的是取消息和分发消息以及回调消息处理函数的作用;Handler作用是发送要执行的消息到消息队列,以及在回调函数中具体处理这个消息。
  消息机制模型:
Android学习之进程与消息处理(二)_第3张图片
  1.5 Handler的具体使用场合
  · 将耗时的任务放到子线程中,避免阻塞主线程
  必须在主线程进行UI组件的更新,通过消息机制,将子线程的运行状态及结果反馈给主线程,在主线程中创建Handler,在子线程中发送消息。
  · 若子线程需要接收其他线程的消息
  需要在子线程中实例化Handler对象,同时需要使用Looper对象来获取和监听消息队列,实例化Handler对象,实现对消息的处理,Handler对象必须保证在该线程外也能访问,以便发送消息。

  2.1 AsyncTask的介绍
  使用Handler来进行异步消息的处理和耗时任务的操作,但是使用Handler的过程较为复杂,若其服务的对象不是频繁使用Handler对象来处理任务和消息,那么使用Handler就有点复杂。所以,Android 系统中还为我们提供了一个异步处理消息的任务类AsyncTask,它是一个轻量级的异步任务处理类。
  2.2 AsyncTask的使用
  · 1.创建一个类继承自AsyncTask;
  · 2.复写doInBackgoround()方法,在该方法中写后台执行任务的代码;
  · 3.在UI线程中创建实例并调用execute()方法,传入执行任务过程中要使用的参数,即doInBackground(Param … param)的参数。
  · 注意:在onPreExecute(),onPostExecute()可以访问UI 组件,doInBackgroud()中不能访问UI组件。
  2.3 AsyncTask
  AsyncTask是一个抽象类,继承该类需要指定如下三个泛型参数:
  Params:启动任务时输入的参数类型;
  Progress:后台任务执行中返回进度值的类型;
  Result:后台任务执行完成后返回结果的类型。
  2.4 AsyncTask类中的回调方法

      doInBackground() 
      //必须重写,后台线程的具体操作代码
      onPreExecute()
      //执行后台线程前被调用,用于进行初始化操作
      onPostExecute() 
      //当后台线程执行完成后,调用此方法,会将doInBackground()的返回的值传入此方法,可通过此方法进行UI的更新(该方法不在后台线程中)
      onProgressUpdate() 
      //获取任务的进度情况,需在doInBackground()方法中调用publishProgress()方法,更新任务执行进度后,将调用此方法

  为什么要在UI Thread中创建AsyncTask才能使用?
  上面讲到只有在UI Thread中才能访问UI组件,从Android源代码中可以看到AysncTask维护了一个Handler的子类和一个线程池对象,线程池对象用来执行耗时操作,Handler用来处理消息。因为Handler关联的Looper对象与Handler所在的线程是一样的,若AsyncTask不在UI Thread中创建,那么就没有Looper对象与Handler关联,就不能执行消息,在onPreExecute(),onPostExecute()就不能调用UI组件。

  ☆☆☆Android Studio实现AsyncTask的使用
  1.打开Android Studio,新建工程后,在activity_main.xml中界添加一个按钮和一个TextView。


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="lession.example.com.androidlessin2019522_4.MainActivity">
    
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <TextView
            android:text="TextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/textview"
            android:textColor="@android:color/holo_red_dark"
            android:gravity="center"
            android:textSize="20sp" />
            
        <Button
            android:text="获取时间"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/button"
            android:textSize="20sp"
            android:textColor="@android:color/black" />
            
    LinearLayout>
RelativeLayout>

  2.在MainActivity中,编写代码。

package lession.example.com.androidlessin2019522_4;

import android.os.AsyncTask;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.format.Time;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    TextView tv;
    class mcAsyncTask extends AsyncTask<String,Void,String>{
        @Override
        protected void onPreExecute() {
            tv.setText("开始获取时间...请等待");
        }
        
        @Override
        protected String doInBackground(String... params) {
            SystemClock.sleep(5000);
            Time mt = new Time();
            mt.setToNow();
            String mtSt = params[0]+mt.format("%Y-%m-%d %H:%M:%S");
            return mtSt;
        }
        
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
            tv.setText("获取的时间是:"+s);
        }
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final mcAsyncTask mATask = new mcAsyncTask();
        Button bt = (Button) findViewById(R.id.button);
        tv = (TextView) findViewById(R.id.textview);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mATask.execute("我的时间");
            }
        });
    }
}

  运行结果:
  Android学习之进程与消息处理(二)_第4张图片
  通过上面的学习,我们知道AsyncTask中其实是使用了Handler的消息处理机制来异步执行任务的,也就是说,AsyncTask是在Handler使用方式的一种封装,那么AsyncTask的灵活程度就会受到限制,但较Handler,其使用更为简单、安全、轻巧。Handler要比AsyncTask灵活,没有太多限制,一般使用在频繁执行任务和刷新操作中,较AsyncTask而言它更适合在一个大量耗时的任务场合中使用,但具有一定的线程不安全性。

  这就是消息处理的使用,如果转载以及CV操作,请务必注明出处,谢谢!

你可能感兴趣的:(Android学习之旅)