Android中的UI是线程不安全的,也就是说,如果要更新应用程序里的UI 元素,则必须在主线程中进行,否则就会出现异常。在这里介绍两个方法来解决这个问题

解析异步处理机制

Android中的异步消息处理主要分为四个部分,Message、Handler、MessageQueue、Looper。
1.Message 是在线程之间传递的消息,它可以在内部携带少量的消息,用于在不同线程之间交换数据。
2.Handler 顾名思义就是处理者的意思,它主要是用来发送和处理消息的。
3.MessageQueue 是消息队列的意思,它主要是用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程只有一个消息队列对象。
4.Looper 是每个线程中消息队列的管家,调用其loop()方法后,就会进入到一个无限循环中,然后每发现消息队列中有一条消息,就会将它取出,并传递到Handler的handleMessage()方法中,每个线程也只会有一个Looper对象。
定义一个点击事件,使得点击时,服务可以改变UI中的内容

package com.example.administrator.myhandlerapplication;import android.app.Activity;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {    public static final int UPDATE_TIME=1;    private int count=60;    private Button mButton;    private Button mButtonMainsend;    private TextView mTextView;  //定义一个内部类Handle    private Handler handler=new Handler(){        public void handleMessage(Message msg){            switch (msg.what){                case UPDATE_TIME                                       //在这里进行UI操作                   String time= (String) msg.obj;                    mButton.setText(time);                    if (count>0){                        try {                            Thread.sleep(1000);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        //这里还可以简单的使用,对UI的操作在这里写,点击事件只需要发送一个空消息,然后在这里类似递归调用发送空消息,然后在这里对UI一次又一次的操作。即把count--放在handler中。                        //handler.sendEmptyMessage(UPDATE_TIME);                    }                    break;                default:                    break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mButton= (Button) findViewById(R.id.button_time);        mButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new MyThread().start();                new Thread(new Runnable() {                    @Override                    public void run() {                        while (count>0){                            count--;                            try {                                Thread.sleep(1000);                            } catch (InterruptedException e) {                                e.printStackTrace();                            }                            Message message=handler.obtainMessage();   //new Message();                            message.obj=count+"秒";                            message.what=UPDATE_TIME;            //发送Message对象                            handler.sendMessage(message);                        }                    }                }).start();            }        });    }}

先定义一个整型常量用来表示更新UI 中的内容的一个操作,然后新建一个Handler对象,并重写父类的handleMessage方法,然后对Message进行处理
这里是由子线程发送消息,由主线程来作相应处理,还可以通过主线程发送消息,然后子线程做相应处理,但是不常用。这里只是举例说明。

package com.example.administrator.myhandlerapplication;import android.app.Activity;import android.os.Handler;import android.os.Looper;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {    public static final int UPDATE_TIME=1;    private int count=60;    private Button mButton;    private Button mButtonMainsend;    private TextView mTextView;    //private Handler handler;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mButton= (Button) findViewById(R.id.button_time);        mButtonMainsend= (Button) findViewById(R.id.button_mainsend);        mButtonMainsend.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {            //这个点击事件用来表示主线程发送消息,只是发送的是空消息,表示不进行任何操作                handler.sendEmptyMessage(UPDATE_TIME);            }        });        mButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {//这个按钮点击事件用来启动子线程。                new MyThread().start();    }    //这是子线程,等待接受主线程发送的消息,使用log打印来显示。    class MyThread extends Thread{        @Override        public void run() {            //super.run();            Looper.prepare();           handler=new Handler(){               @Override               public void handleMessage(Message msg) {                   Log.d("11111111111111", "接收到主线程发来的消息");               }           };            Looper.loop();        }    }}

在主线程中已经将Looper全部封装好所以不需要定义。而在子线程中需要将接收消息写在Looper的prepare()方法和loop()之间。

使用AsyncTask

Android还提供了AsyncTask抽象类来实现子类对UI进行操作。其实这个类实现原理也是基于消息处理机制,只是做了封装而已,通过几个方法来实现。
AsyncTask是一个抽象类,所以使用时需要创建一个子类去继承,继承时需要制定三个泛性值参数。
第一个参数Params ,在执行AsyncTask时需要传入的参数,可用于在后台任务中使用
第二个参数Progress ,在后台执行任务时,如果需要在界面上显示当前的进度,使用这里制定的泛型作为进度单位
第三个参数Result ,当任务执行完毕后如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。

继承自AsyncTask的类还需要重写其方法,其中经常需要重写的有四个方法
1.onPreExecute() 在后台任务开始执行之前调用,用于进行一些界面上的初始化操作。
2.doInBackground这个方法中的代码都会在子线程中运行,需要在这里处理所有的耗时操作任务。任务完后之后通过return语句来讲任务的执行结果返回,如果AsyncTask的第三个泛型制定的是Void,可以不返回任务执行结果。需要注意的是,在这个方法中是不可以进行UI操作的,如果需要更新UI 元素,可以调用publishProgress()方法来完成
3.onProgressUpdate(Integer… values)当后台任务调用了publishProgress()方法后,这个方法就会很快被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。
4.onPostExecute(String s)当后台任务执行完毕并通过return语句进行返回时调用这个方法,返回的数据作为参数传递到这个方法中,可以利用返回的数据进行UI操作。

首先,定义一个按钮和一个进度条,通过按钮的点击事件启动后台服务,后台服务将信息发送回来显示到进度条上

 "@+id/progressBar"        android:layout_width="match_parent"        android:layout_height="wrap_content"        style="@style/Widget.AppCompat.ProgressBar.Horizontal"/>    

在MainActivity中声明一个类继承自AsyncTask并重写其方法,然后在按钮的点击事件中得到该类的一个对象,并可传参数给后台服务。

package com.example.administrator.masynctask;import android.app.Activity;import android.os.AsyncTask;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.Button;import android.widget.ProgressBar;public class MainActivity extends Activity {    private int count=0;    private Button mButtonStart;    private ProgressBar mProgressBar;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mButtonStart= (Button) findViewById(R.id.button_sync);        mProgressBar= (ProgressBar) findViewById(R.id.progressBar);        mButtonStart.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {            //得到一个AsyncTask的对象,这里需要传参数,所以为空                MyAsyncTask myAsyncTask=new MyAsyncTask();                myAsyncTask.execute();            }        });    }    class MyAsyncTask extends AsyncTask{        @Override        protected String doInBackground(Void... params) {        //进行后台操作            while (count<101){                count++;                publishProgress(count);                try {                    Thread.sleep(200);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            return "下载完成";        }        @Override        protected void onPostExecute(String s) {            super.onPostExecute(s);            //利用doInBackground(Void... params)完成之后返回的值对UI 进行操作            mButtonStart.setText(s);        }        @Override        protected void onProgressUpdate(Integer... values) {            super.onProgressUpdate(values);            //利用doInBackground(Void... params)中publishProgress(count)传过来的值对UI中的进度条进行操作            mProgressBar.setProgress(values[0]);        }    }}

更多相关文章

  1. Qt on Android:添加分享功能
  2. android 面试题经典
  3. Android(安卓)Framework 框架系列之 PhoneWindowManager
  4. 教你如何在 Android(安卓)使用多线程下载文件
  5. Android(安卓)Handler 消息传递机制
  6. Android(安卓)多线程编程:IntentService & HandlerThread
  7. Android(安卓)ANR (转)
  8. 浅谈Java中Collections.sort对List排序的两种方法
  9. Python list sort方法的具体使用

随机推荐

  1. android input系统如何导入kl文件
  2. android 添加sensor 权限
  3. [Android实例] android多点触摸demo .
  4. android中检查是否联网code
  5. android socket 百度地图 实时定位
  6. Android程序开发:简单电话拨号器
  7. Android(安卓)实现图片闪烁效果
  8. Android(安卓)实现多个输入框的对话框
  9. Android(安卓)sdk manager 下载安装中的
  10. Android(安卓)safe mode