前言
AsyncTask是我们经常使用的一个异步类,是Android已经封装好了的,废话补多少,先来简单使用一下。
其实我们大部分使用它的时候都是应用在下载的时候,显示一个进度框,那我们就来试下吧:
使用步骤:
1、先把布局什么的都弄好:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true">
<Button
android:id="@+id/btn_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下载图片"/>
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="准备加载。。。"/>
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:progress="0"
android:max="100"
style="?android:attr/progressBarStyleHorizontal"/>
<Button
android:id="@+id/btn_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消下载"/>
</LinearLayout>
</RelativeLayout>
然后Activity中findViewById:
public class MainActivity extends AppCompatActivity {
Button downBtn;
Button cancelBtn;
TextView text;
ProgressBar progressBar;
MyTask myTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
downBtn = (Button) findViewById(R.id.btn_down);
cancelBtn = (Button) findViewById(R.id.btn_cancel);
text = (TextView) findViewById(R.id.text);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
myTask = new MyTask();
2、重点来了,自定义一个MyTask继承AsyncTask:
AsyncTask的参数不一定会被使用,不使用的可用void代替,参数为3种泛型:
- 第一个参数是开始异步任务时传入的,对应execute()中传入的参数,比如一些网络请求的url
- 第二个参数是任务执行过程中,返回的进度值
- 第三个参数是任务执行完成后,返回的一个值,与doInBackground()返回值一致
下面看一下代码:
private class MyTask extends AsyncTask<String,Integer,String> {
/**
* 方法1:执行线程前的操作
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
text.setText("加载中");
}
/**
* 方法2:执行耗时操作
*/
@Override
protected String doInBackground(String... strings) {
try {
int count = 0;
int length = 1;
while (count < 99) {
count += length;
//将实时的数值通过publicProgress传入onProgressUpdate
publishProgress(count);
Thread.sleep(20);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
/**
* 方法3:在主线程显示任务进度
*/
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressBar.setProgress(values[0]);
text.setText("下载中……" + values[0] + "%");
}
/**
* 方法4:最终任务结束,接受结果
*/
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
text.setText("下载完成");
}
/**
* 方法5:将任务设置为取消状态
*/
@Override
protected void onCancelled() {
super.onCancelled();
text.setText("已取消");
progressBar.setProgress(0);
}
}
方法1:onPreExecute()、在任务执行前调用,其实也可以把设置进度条的操作放到这里
方法2:doInBackground()、执行耗时的任务,比如后台下载任务,并且下载的进度可以通过publishProgress()方法,在此方 法中传入一个数值,来表示进度,最后在onProgressUpdate当中进行回调,也就是这两个方法中的参数是一样的
方法3:onProgressUpdate()、在此方法中可以将进度值显示在界面上
方法4:onPostExecute()、在此方法中将最终的结果返回,并进行UI操作
方法5:onCancelled()、将任务设置为取消状态
一些规则:
- 使用AsyncTask的时候,最少得重写doInBackground()和onPostExecute()这两个方法
- Task的实例必须在UI线程中创建
- execute的方法必须在UI线程中调用
- AsyncTask中的那几个方法不必手动调用
- 对于特别耗时的任务建议使用线程池
- 一个AsyncTask任务只能执行一次,这个要记清楚
- 存在内存泄漏的情况,解决方法在onDestroy()中调用cancel()方法
- Activity重新创建时,比如屏幕旋转后线程执行结果会丢失,解决方法为Activity恢复时重启任务线程
总结
AsyncTask的简单使用和注意事项大体写了下,然后下一步要再了解一下AsyncTask的源码。先写到这。。。