码迷,mamicode.com
首页 > 其他好文 > 详细

AsyncTask解析(上)——原理分析与超简单demo实现

时间:2016-04-26 21:10:19      阅读:290      评论:0      收藏:0      [点我收藏+]

标签:

最近因为在做项目的过程中经常需要进行网络传输,所以打算把几个常用的网络通信框架和GitHub上面的开源框架梳理一遍,本文简单介绍了AsyncTask工作原理以及一个十分简单的应用demo。

当然,了解一个组件,最好是先从Android API文档入手。

那么首先我们来看一下AsyncTask的继承结构:

 技术分享

可以看到,AsyncTask跟Handler一样,是直接从Object类继承的,属于安卓系统包里的基本组件。

再来看看文档中对AsyncTask给出的描述:

 技术分享

从中我们可以得到3个比较重要的信息点:

1、AsyncTask与handler一样,都是为了防止线程阻塞而用于执行简单的异步处理的类。

2、比起Handler实现异步的过程:需要使用到Handler, Looper, Message,Thread四个对象,并需要通过主线程启动Thread(子线程)运行并生成Message-àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。AsyncTask的实现过程更为简单,只有4个步骤,分别为onpreexecute,doInBackground,onProgressUpdate和onpostexecute。

3、AsyncTask是被设计成处理异步操作的一个辅助类而不是一个通用的线程框架,应该被用于一些简单的通信异步处理的情况中(最多几秒钟),如果要保持长时间的通信线程运行(比如文件传输之类的),最好不要使用AsyncTask!


AsyncTask的实现步骤:

这里参考了:http://www.cnblogs.com/devinzhang/archive/2012/02/13/2350070.html的博文,归纳得十分透彻精辟,值得牢记。

1、首先我们可以通过实现一个类继承AsyncTask来实现异步加载数据,如下所示:

public class TestAsyncTask  extends AsyncTask<String, Integer, String>

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">       其中,AsyncTask定义了三种泛型类型:Params,Progress和Result。Params :启动任务执行的输入参数,比如HTTP请求的URL。Progress :后台任务执行的百分比。Result 后台执行任务最终返回的结果,这里用到的是String。</span>

2、实现这个异步加载类必须要有以下两个方法:


        doInBackground(Params…) :在后台执行,比较耗时的操作都可以放在这里。但是不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。

        onPostExecute(Result):  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回。


3、有必要的话你还得重写以下这三个方法,但不是必须的:        


       onProgressUpdate(Progress…) :  可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。        

       onPreExecute()   :     这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。       

        onCancelled()  :           用户调用取消时,要做的操作


4、使用AsyncTask类,以下是几条必须遵守的准则:        

       Task的实例必须在UI thread中创建;        

       execute方法必须在UI thread中调用;        

       不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;        

       该task只能被执行一次,否则多次调用时将会出现异常;

AsyncTask实现执行过程源码分析:

TestAsyncTask  testAsyncTask = (TestAsyncTask) new TestAsyncTask(TestAsyAty.this,textView,progressBar).execute("");
首先,例如我们在Activity中调用自定义的AsyncTask实现异步操作,先要执行execute()方法执行这个异步任务。

@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}
可以看到,在execute方法的源码内部,会执行一个executeOnExecutor()方法用以return一个AsyncTask的实例:

@MainThread
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params) {
    if (mStatus != Status.PENDING) {
        switch (mStatus) {
            case RUNNING:
                throw new IllegalStateException("Cannot execute task:"
                        + " the task is already running.");
            case FINISHED:
                throw new IllegalStateException("Cannot execute task:"
                        + " the task has already been executed "
                        + "(a task can be executed only once)");
        }
    }

    mStatus = Status.RUNNING;

    onPreExecute();

    mWorker.mParams = params;
    exec.execute(mFuture);

    return this;
}
在这个方法中,改变了参数变量,返回了上文中调用的AsyncTask的实例,还可以看到关键的一点是执行了onPreExecute()方法,于是跳转到onPreExecute()方法:

/**
 * Runs on the UI thread before {@link #doInBackground}.
 *
 * @see #onPostExecute
 * @see #doInBackground
 */
@MainThread
protected void onPreExecute() {
}
注释已经很明确了,在doInBackground()方法之前执行,那么跳转到doInBackground():

/**
 * Override this method to perform a computation on a background thread. The
 * specified parameters are the parameters passed to {@link #execute}
 * by the caller of this task.
 *
 * This method can call {@link #publishProgress} to publish updates
 * on the UI thread.
 *
 * @param params The parameters of the task.
 *
 * @return A result, defined by the subclass of this task.
 *
 * @see #onPreExecute()
 * @see #onPostExecute
 * @see #publishProgress
 */
@WorkerThread
protected abstract Result doInBackground(Params... params);
可以通过重写该方法执行异步任务操作(执行网络请求什么的可以放doInBackground()里面)。在该方法中可以调用publishProgress()方法实现对进度条的更新,增加用户体验度。

在方法之后,执行的自然是onProgressUpdate()方法进行对UI的更新操作:

/**
 * Runs on the UI thread after {@link #publishProgress} is invoked.
 * The specified values are the values passed to {@link #publishProgress}.
 *
 * @param values The values indicating progress.
 *
 * @see #publishProgress
 * @see #doInBackground
 */
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onProgressUpdate(Progress... values) {
}

现在回到doInBackground()方法,虽然注释中并没有给出下一个要执行的方法,不过通过阅读上文,冰雪聪明の你应该已经想到了:在执行完异步操作之后,下一步自然是要更新UI,执行onPostExecute(Result)方法了:

/**
 * <p>Runs on the UI thread after {@link #doInBackground}. The
 * specified result is the value returned by {@link #doInBackground}.</p>
 * 
 * <p>This method won‘t be invoked if the task was cancelled.</p>
 *
 * @param result The result of the operation computed by {@link #doInBackground}.
 *
 * @see #onPreExecute
 * @see #doInBackground
 * @see #onCancelled(Object) 
 */
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onPostExecute(Result result) {
}

可以看到该方法确实是在doInbackground()方法之后调用的,接受到的result也是doInbackground()的返回值,还有一个要注意的点:如果异步任务呗取消(用户调用onCancelled()方法),那么onPostExecute()方法是不会被执行的!

整体流程结构图如下所示(画的比较简陋,轻喷。。):


AsyncTask简单Demo实现:

下面给出一个比较简单的Demo实现,通过异步操作调用百度的身份证查询API接口查询个人资料数据(result是json数据,这里就不解析了= =)。

注释比较详细这里就不赘述了大家看源码吧(づ ̄ 3 ̄)づ:

TestAsyAty.java

public class TestAsyAty extends Activity {
    TestAsyncTask testAsyncTask;
    ProgressBar progressBar;
    TextView showtv;
    public static final String API_KEY = "f31209d4d0c59c0fb4dcca8b9282f2f9";
    public String path = "http://apis.baidu.com/apistore/idservice/id";
    String httpArg = "id=420984198704207896";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.testasy);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        progressBar.setMax(100);
        showtv = (TextView) findViewById(R.id.textView);
        progressBar.setMax(100);
        testAsyncTask = new TestAsyncTask(showtv,progressBar,httpArg);
        testAsyncTask.execute();
    }
}

TestAsyncTask.java

public class TestAsyncTask  extends AsyncTask<String, Integer, String>
{
    String httpUrl = "http://apis.baidu.com/apistore/idservice/id";
    String httpArg ;
    TextView tv;
    ProgressBar bar;
    public TestAsyncTask(TextView tv,ProgressBar bar,String httpArg) {
        super();
        this.tv = tv;
        this.bar = bar;
        this.httpArg = httpArg;
    }

    /**
     * 这里的String参数对应AsyncTask中的第一个参数
     * 这里的String返回值对应AsyncTask的第三个参数
     * 该方法并不运行在UI线程当中,主要用于异步操作,所有在该方法中不能对UI当中的空间进行设置和修改
     * 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作
     * @param params
     * @return
     */
    @Override
    protected String doInBackground(String... params) {
        BufferedReader reader = null;
        String result = null;
        StringBuffer sbf = new StringBuffer();
        httpUrl = httpUrl + "?" + httpArg;

        try {
            URL url = new URL(httpUrl);
            HttpURLConnection connection = (HttpURLConnection) url
                    .openConnection();
            connection.setRequestMethod("GET");
            connection.setRequestProperty("apikey",  "f31209d4d0c59c0fb4dcca8b9282f2f9");
            connection.connect();
            InputStream is = connection.getInputStream();
            reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            String strRead = null;
            while ((strRead = reader.readLine()) != null) {
                sbf.append(strRead);
                sbf.append("\r\n");
            }
            reader.close();
            result = sbf.toString();
            if (result != null) {
                publishProgress(100);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)
     * 在doInBackground方法执行结束之后在运行
     * 并且运行在UI线程当中 可以对UI空间进行设置
     */
    @Override
    protected void onPostExecute(String s) {
        tv.setText(s);
    }

    //该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置
    @Override
    protected void onPreExecute() {
        tv.setText("开始执行异步线程");
    }

    /**
     * 这里的Intege参数对应AsyncTask中的第二个参数
     * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
     * onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        int v = values[0];
        bar.setProgress(v);
    }
}

运行效果:

技术分享

解析什么的就自己做辣~\(≧▽≦)/~~

下篇文章: AsyncTask解析(下)——实现自定义AsyncTask网络传输工具类封装

实现了自定义AsyncTask的封装以及实现细节,可以点进去看看哟QAQ

继续努力~~~好好学习~~~!!!求关注!!!求互粉!!!!!!


 




AsyncTask解析(上)——原理分析与超简单demo实现

标签:

原文地址:http://blog.csdn.net/qq_22770457/article/details/51235077

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!