异步任务AsyncTask

来源:互联网 发布:知肤泉水光面膜怎么用 编辑:程序博客网 时间:2024/05/16 10:31
为什么需要异步任务?
1.Android单线程模式,意思是只有主线程(UI线程)才能对UI进行更新操作,而其他的线程是不能操作UI。这样就保证饿了一个UI的稳定性,和准确性。
2.耗时操作放在非主线程中进行操作
AsyncTask为什么会有?
1.可以在子线程中进行UI的更新。
2.封装,简化了异步操作
构建AsyncTask子类的参数
AsyncTask<Params,Progress,Result>是一个抽象类,通常用于被继承,其中的三个泛型参数分别代表:
Params:启动任务时输入的参数类型
Progress:后台任务执行中返回进度值的类型
Resule:后台执行任务完成后返回的结果类型
构建AsyncTask子类的回调方法
doInBackground:必须重写,异步执行后台线程将要完成的任务。所有耗时的操作都在这里执行
onPreExecute:执行后台耗时操作前被调用,通常用户完成一些初始化的操作就在这里执行
onPostExecute:当doInBackground()完成后,系统会自动调用onPostExecute()方法,并将doInBackground方法中的返回值传递给该方法
onProgressUpdate:在doInBackground()方法中调用publicProgress()方法更新任务的执行进度后,会触发该方法。我们通过这个方法可以很清楚的知道当前耗时操作的一个完成进度。
简单实现,了解AsyncTask的执行
1.我们需要新建一个MyAsyncTask:
package com.example.songz.asynctasktest;import android.os.AsyncTask;import android.util.Log;/** * Created by SongZ on 2016/4/10. */public class MyAsyncTask extends AsyncTask<Void,Void,Void> {@Overrideprotected void onProgressUpdate(Void... values) {super.onProgressUpdate(values);        Log.d("szx","onProgressUpdate");    }@Overrideprotected void onPreExecute() {super.onPreExecute();        Log.d("szx","onPreExecute");    }@Overrideprotected void onPostExecute(Void aVoid) {super.onPostExecute(aVoid);        Log.d("szx","onPostExecute");    }@Overrideprotected Void doInBackground(Void... params) {        Log.d("szx","doInBackground");        publishProgress();return null;    }}


2.然后到MainActivity中进行启动:
MyAsyncTask task = new MyAsyncTask();task.execute();


3.结果显示:
创建UI
异步处理-->下载图像
UI线程-->设置图像
1.首先我们新建一个布局名字叫做image:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:padding="16dp"android:layout_height="match_parent">    <ImageViewandroid:id="@+id/image"android:layout_width="match_parent"android:layout_height="match_parent"/>    <ProgressBarandroid:visibility="gone"android:id="@+id/progressbar"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"/></RelativeLayout>


2.然后新建一个class名字叫做ImageTest:
public class ImageTest extends Activity {private ImageView imageView;private ProgressBar progressBar;private static String URL="http://img.my.csdn.net/uploads/201504/12/1428806103_9476.png";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);        setContentView(R.layout.image);imageView = (ImageView) findViewById(R.id.image);progressBar = (ProgressBar) findViewById(R.id.progressbar);    }}


创建AsyncTask
在上面的ImageTest代码中添加
class MySyncTask extends AsyncTask<String,Void,Bitmap>{//1.URL类型,2.进度值类型 3.返回值类型@Overrideprotected void onPreExecute() {super.onPreExecute();    }@Overrideprotected void onPostExecute(Bitmap bitmap) {super.onPostExecute(bitmap);    }@Overrideprotected void onProgressUpdate(Void... values) {super.onProgressUpdate(values);    }@Overrideprotected Bitmap doInBackground(String... params) {        String url =params[0];//doInBackground它传递进来的是一个可变长数组,也就是说在execute方法中可以传递不止一个参数进来,那么这些参数以此对应的就是我们params这个数组,因为我们传进来的参数只有一个,所以就是第0个,就可以取出对应的URLBitmap bitmap = null;        URLConnection connection;//定义网络连接对象InputStream is;//用于获取数据的输入流try {//将url解析成bitmapconnection =new URL(url).openConnection();//获取网络连接对象is =connection.getInputStream();//获取输入流BufferedInputStream bis = new BufferedInputStream(is);            bitmap = BitmapFactory.decodeStream(bis);//将输入流解析成bitmapis.close();//先打开的后关闭bis.close();        } catch (IOException e) {            e.printStackTrace();        }return bitmap;    }}


2.总结逻辑:
1.获取传递进来的参数,也就是params[0];
2.通过decodeStream解析输入流
3.将bitmap作为返回值返回给后面调用的方法
与UI线程通信
1.在上面代码中添加
@Overrideprotected void onPreExecute() {super.onPreExecute();//这时候吧隐藏的progressbar显示出来,提示用户等待progressBar.setVisibility(View.VISIBLE);}@Overrideprotected void onPostExecute(Bitmap bitmap) {super.onPostExecute(bitmap);//操作UI,设置图像progressBar.setVisibility(View.GONE);imageView.setImageBitmap(bitmap);}


2.然后设置传递进去的参数
//设置传递进去的参数new MySyncTask().execute(URL);


3.然后在activity_main.xml中添加按钮点击事件
<Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="Hello World!"android:onClick="loadImage"/>


4.然后再到MainActivity中进行事件的实现
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    MyAsyncTask task = new MyAsyncTask();    task.execute();}public void loadImage(View view){    startActivity(new Intent(this,ImageTest.class));}


模拟进度条
通过AsyncTask来模拟进度条的更新
1.首先还是需要新建一个类,叫做ProgressBarTest
package com.example.songz.asynctasktest;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.widget.ProgressBar;/** * Created by SongZ on 2016/4/10. */public class ProgressBarTest extends Activity {private ProgressBar progressBar;private MyAsyncTask1 myAsyncTask;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);        setContentView(R.layout.progressbar);progressBar = (ProgressBar) findViewById(R.id.pg);myAsyncTask = new MyAsyncTask1();myAsyncTask.execute();    }class MyAsyncTask1 extends AsyncTask<Void,Integer, Void>{@Overrideprotected void onPreExecute() {super.onPreExecute();        }@Overrideprotected void onPostExecute(Void aVoid) {super.onPostExecute(aVoid);        }@Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);//获取进度更新值progressBar.setProgress(values[0]);        }@Overrideprotected Void doInBackground(Void... params) {//模拟进度更新for (int i = 0;i<100;i++)            {                publishProgress(i);try {                    Thread.sleep(3000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }return null;        }    }}


2.然后还需要设计一个布局,里面的ProgressBar需要是水平方向的。
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:padding="16dp"android:layout_height="match_parent">    <ProgressBarstyle="?android:attr/progressBarStyleHorizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/pg"android:layout_centerVertical="true"android:layout_centerHorizontal="true" /></RelativeLayout>


3. 然后需要到AndroidManifest,xml文件中进行注册,然后再到MainActivity.java中进行一个点击事件的实现
public void loadProgressBaar(View view){    startActivity(new Intent(this,ProgressBarTest.class));}


但是这里你会发现,如果我们每一次进入都需要等待上一个进度条完成之后才可以,这是为什么?因为AsyncTask的底层是通过线程池来进行实现的,如果一个线程没有执行完毕,那么后面的线程是没有办法进行的,必须要等到上一个线程执行完毕才可以执行。那么需要怎么实现呢?很简单,我们知道Activity的生命周期,那么让AsyncTask和他保持一致就可以了。
protected void onPause() {super.onPause();if (myAsyncTask!=null && myAsyncTask.getStatus() == AsyncTask.Status.RUNNING)//不为空,而且Running{//cancel方法只是将对应的AsyncTask标记为cancel状态,并不是真正的取消线程的执行myAsyncTask.cancel(true);//然后这里并没有将线程停止掉}}protected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);if (isCancelled())    {return;    }//获取进度更新值progressBar.setProgress(values[0]);}//只有doInBackground才是运行在其他线程protected Void doInBackground(Void... params) {//模拟进度更新for (int i = 0;i<100;i++)    {if (isCancelled())        {break;        }        publishProgress(i);try {            Thread.sleep(3000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }return null;}


1 0
原创粉丝点击