在安卓开发中常常会有处理大量数据,进行网络连接等比较耗时的操作,而如果把这些操作都放到主线程(UI线程)中的话,就会造成卡顿现象,影响程序的正常运行和用户的良好体验,此时就要用到异步操作,安卓开发中主要有两种异步操作的方法,Handler和Asynctask
Handler实例:
package com.example.admin.handlermodel; import android.app.ProgressDialog; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.widget.ProgressBar; import java.util.Timer; import java.util.TimerTask; public class MainActivity extends AppCompatActivity { Handler handler01=new Handler(); ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); progressBar= (ProgressBar) findViewById(R.id.progressbar); //sendmessage用法 /* final Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { if (msg.what==123){ progressBar.setProgress((Integer) msg.obj); } } }; new Timer().schedule(new TimerTask() { @Override public void run() { p++; if (p>100){ p=0; } Message message=new Message(); message.what=123; message.obj=p; handler.sendMessage(message); } },0,200);*/ //post用法 handler01.post(runnable); } Runnable runnable=new Runnable() { @Override public void run() { p++; handler01.postDelayed(this,100); progressBar.setProgress(p); } }; int p=0; }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <ProgressBar android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/progressbar" style="@android:style/Widget.ProgressBar.Horizontal" /> </RelativeLayout>
Asynctask实例:
package com.example.admin.asynctask; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private static final String TAG = "ASYNC_TASK"; MyTask myTask; Button start; Button cancel; ProgressBar progressBar; TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); start = (Button) findViewById(R.id.btnstart); cancel = (Button) findViewById(R.id.btncancel); textView = (TextView) findViewById(R.id.text); cancel.setEnabled(false); progressBar = (ProgressBar) findViewById(R.id.pba); start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { myTask = new MyTask();//注意每次需new一个实例,新建的任务只能执行一次,否则会出现异常 myTask.execute("开始工作");//doInBackground()开始执行 start.setEnabled(false); cancel.setEnabled(true); } }); cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { myTask.cancel(true);//取消任务,onCancelled()方法被调用 cancel.setEnabled(false); start.setEnabled(true); } }); } private class MyTask extends AsyncTask<String, Integer, String> { /* 第一个参数是execult()函数的参数类型传递到doInBackground()中,相当于初始量, 第二个是 doInBackground()中 publishProgress(count)的count的类型,相当于中间量,传递给onProgressUpdate() 第三个是doInBackground()和的返回值类型,传递到onCancelled()和onPostExecute()中,相当于结果*/ @Override protected void onPreExecute() {//此方法用于执行后台任务前做一些UI操作 Toast.makeText(MainActivity.this, "onPreExecult is called", Toast.LENGTH_SHORT).show(); textView.setText("loading......"); } @Override //此方法内部执行一些较为复杂和费事的任务,不能在此方法内修改UI protected String doInBackground(String... params) { Log.e(TAG, "doInBackGround is called"); int count = 0; while (count <= 100) { count++; //调用onProgressUpdate()函数,进行即使更改进度 publishProgress(count); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } return "加载完成!"; } @Override protected void onProgressUpdate(Integer... values) {//用于更新进度,在此方法内对UI进行即时更新 super.onProgressUpdate(values[0]); progressBar.setProgress(values[0]); textView.setText("loading..." + values[0] + "%"); } @Override protected void onCancelled(String s) {//任务被取消时执行 Toast.makeText(MainActivity.this, "onCanceled is called", Toast.LENGTH_SHORT).show(); textView.setText("canceled"); progressBar.setProgress(0); cancel.setEnabled(false); start.setEnabled(true); } } }
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <!-- 依次定义6个TextView,先定义的TextView位于底层 后定义的TextView位于上层 --> <TextView android:id="@+id/view01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="160pt" android:height="160pt" android:background="#f00"/> <TextView android:id="@+id/view02" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="140pt" android:height="140pt" android:background="#0f0"/> <TextView android:id="@+id/view03" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="120pt" android:height="120pt" android:background="#00f"/> <TextView android:id="@+id/view04" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="100pt" android:height="100pt" android:background="#ff0"/> <TextView android:id="@+id/view05" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="80pt" android:height="80pt" android:background="#f0f"/> <TextView android:id="@+id/view06" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:width="60pt" android:height="60pt" android:background="#0ff"/> </FrameLayout>
AsyncTask实现的原理和适用的优缺点
AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.
使用的优点:
简单,快捷
过程可控
使用的缺点:
在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.
Handler异步实现的原理和适用的优缺点
在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)运行并生成Message-Looper获取Message并传递给HandlerHandler逐个获取Looper中的Message,并进行UI变更。
使用的优点:
结构清晰,功能定义明确
对于多个后台任务时,简单,清晰
使用的缺点:
在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)
Android为了降低这个开发难度,提供了AsyncTask。AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。
AsyncTask直接继承于Object类,位置为android.os.AsyncTask。要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个)。
AsyncTask定义了三种泛型类型 Params,Progress和Result。
- Params 启动任务执行的输入参数,比如HTTP请求的URL。
- Progress 后台任务执行的百分比。
- Result 后台执行任务最终返回的结果,比如String。
使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法:
- doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
- onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回
有必要的话你还得重写以下这三个方法,但不是必须的:
- onProgressUpdate(Progress…) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
- onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
- onCancelled() 用户调用取消时,要做的操作
使用AsyncTask类,以下是几条必须遵守的准则:
- Task的实例必须在UI thread中创建;
- execute方法必须在UI thread中调用;
- 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
- 该task只能被执行一次,否则多次调用时将会出现异常;