Android~AsyncTask异步操作DEMO学习解析

来源:互联网 发布:mac怎么安装mpv 编辑:程序博客网 时间:2024/05/21 14:04

大家好,今天我给大家介绍AsyncTask异步类的具体使用;AsyncTask是Android系统提供的轻量级的异步操作类,处理耗时操作任务在非UI线程中,提供回调接口,在回调接口中我们可以再UI线程中更新界面或执行UI线程中可操作的任务。

使用AsyncTask异步类我们先了解重写该类我们必须要重写该类的哪些方法?

doInBackground(Void... params);在非UI线程中执行处理耗时任务操作。

onPreExecute();异步类AsyncTask执行doInBackground方法之前,也就是在非UI线程执行之前,需要执行的方法。

onPostExecute(Void... params);异步类AsyncTask执行doInBackground方法之后,回调在UI线程中需要执行的方法。

onProgressUpdate(Void... params);异步类AsyncTask类在doInBackground方法执行过程中,需要更新UI线程中界面或者数据,我们需要调用publishProgress(Void... params)方法来执行可在UI线程中执行的此方法。

那么好了,现在我就用写一个DEMO,具体介绍该类的使用分析。

1)新建一个Android应用工程asynctask,应用结构如下:


2)我们在activity_home.xml设置一个Button按钮,作用就是进入进度条界面,具体代码如下:


3)我们在HomeActivity类中编写按钮的点击事件逻辑处理,具体代码如下:

package com.example.asynctask;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.view.View;public class HomeActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_home);}public void inprogress(View v){startActivity(new Intent(this, ProgressActivity.class));}}
4)我们编写ProgressActivity.java类的代码,首先该类对应的布局文件是activity_progress.xml,布局文件中只是有一个ProgressBar控件,具体代码如下:

<?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"    android:padding="10dp" >    <ProgressBar        android:id="@+id/progressBar1"        style="?android:attr/progressBarStyleHorizontal"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_centerHorizontal="true"        android:layout_centerVertical="true" /></RelativeLayout>
5)我们编写ProgressActivity.java类的代码,这里才是核心,具体代码如下:

package com.example.asynctask;import java.security.PublicKey;import android.app.Activity;import android.os.AsyncTask;import android.os.Bundle;import android.view.View;import android.widget.ProgressBar;import android.widget.Toast;public class ProgressActivity extends Activity{private ProgressBar mProgressBar;private MyAsyncTask task;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_progress);mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);}@Overrideprotected void onResume() {super.onResume();task = new MyAsyncTask();task.execute();}class MyAsyncTask extends AsyncTask<Void, Integer, Void>{/** * 在执行耗时操作之前调用此方法 */@Overrideprotected void onPreExecute() {super.onPreExecute();mProgressBar.setVisibility(View.VISIBLE);Toast.makeText(ProgressActivity.this, "进度条开始", Toast.LENGTH_LONG).show();}/** * 在非UI线程中执行耗时操作 */@Overrideprotected Void doInBackground(Void... params) {for (int i = 0; i < 100; i++) {publishProgress(i);//更新UI线程进度条进度情况。try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}}return null;}/** * 在执行耗时操作之后调用此方法 */@Overrideprotected void onPostExecute(Void result) {super.onPostExecute(result);mProgressBar.setVisibility(View.INVISIBLE);Toast.makeText(ProgressActivity.this, "进度条完毕", Toast.LENGTH_LONG).show();}/** * 在doInBackground非UI线程中执行耗时操作时候,调用publishProgress方法的时候才会调用该方法。 */@Overrideprotected void onProgressUpdate(Integer... values) {super.onProgressUpdate(values);mProgressBar.setProgress(values[0]);}}}
截止到此我们就可以算是告一段落了,那么我们开始用运行程序,程序运行非常完美!

但是当我们点击按钮进入,马上点击硬件返回,在点击按钮进入,马上点击硬件返回,在点击按钮进入,会发现等待比较长的时间进度条才开始显示运行,大家敲击代码到此运行一下,看看我说的情况是否存在呢!?

在我们异步类执行的过程,其实是放在一个异步池中了,它们是按照顺序执行的,如果其中一个没有执行完毕的话,那么我们后面的异步类只能等待!在我们点击硬件返回,在点击按钮的同时,新建了一个异步类将异步类放入异步池中,但是上一次的异步类还没有执行完毕呢,所以它只能等待!

好了,我们现在知道了原因,那么我们如何更正!?

我的解决方案就是将异步类的生命周期和Activity类的生命周期绑定在一起,那么我们可以再onPause方法中调用task.cancel(true);

那么现在我们在运行程序按照刚才的操作运行一下,结果发现和刚才情况一样没有变化!我们已经将task取消了啊!怎么会不起作用呢?

那么这个时候我们就要去查看task.cancel(true);源码去了:

/**     * <p>Attempts to cancel execution of this task.  This attempt will     * fail if the task has already completed, already been cancelled,     * or could not be cancelled for some other reason. If successful,     * and this task has not started when <tt>cancel</tt> is called,     * this task should never run. If the task has already started,     * then the <tt>mayInterruptIfRunning</tt> parameter determines     * whether the thread executing this task should be interrupted in     * an attempt to stop the task.</p>     *      * <p>Calling this method will result in {@link #onCancelled(Object)} being     * invoked on the UI thread after {@link #doInBackground(Object[])}     * returns. Calling this method guarantees that {@link #onPostExecute(Object)}     * is never invoked. After invoking this method, you should check the     * value returned by {@link #isCancelled()} periodically from     * {@link #doInBackground(Object[])} to finish the task as early as     * possible.</p>     *     * @param mayInterruptIfRunning <tt>true</tt> if the thread executing this     *        task should be interrupted; otherwise, in-progress tasks are allowed     *        to complete.     *     * @return <tt>false</tt> if the task could not be cancelled,     *         typically because it has already completed normally;     *         <tt>true</tt> otherwise     *     * @see #isCancelled()     * @see #onCancelled(Object)     */    public final boolean cancel(boolean mayInterruptIfRunning) {        mCancelled.set(true);        return mFuture.cancel(mayInterruptIfRunning);    }
在源码中我们可以看到在该方法中并没有将异步类取消掉,只是设置了一个标志位,在给出的注释中我们发现有一个isCancelled()的方法,我们在查看其源码:

 /**     * Returns <tt>true</tt> if this task was cancelled before it completed     * normally. If you are calling {@link #cancel(boolean)} on the task,     * the value returned by this method should be checked periodically from     * {@link #doInBackground(Object[])} to end the task as soon as possible.     *     * @return <tt>true</tt> if task was cancelled before it completed     *     * @see #cancel(boolean)     */    public final boolean isCancelled() {        return mCancelled.get();    }
从这源码中我们看到只是返回刚才我们设置的标志位而已。

那么我们就可以在后台doInBackground,onPostExecute执行开始过程中我们调用isCancelled()方法,则相关代码修改后如下:

/** * 在执行耗时操作之前调用此方法 */@Overrideprotected void onPreExecute() {super.onPreExecute();mProgressBar.setVisibility(View.VISIBLE);Toast.makeText(ProgressActivity.this, "进度条开始", Toast.LENGTH_LONG).show();}/** * 在非UI线程中执行耗时操作 */@Overrideprotected Void doInBackground(Void... params) {for (int i = 0; i < 100; i++) {if(isCancelled()){break;}publishProgress(i);//更新UI线程进度条进度情况。try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}}return null;}/** * 在执行耗时操作之后调用此方法 */@Overrideprotected void onPostExecute(Void result) {super.onPostExecute(result);if(isCancelled()){return;}mProgressBar.setVisibility(View.INVISIBLE);Toast.makeText(ProgressActivity.this, "进度条完毕", Toast.LENGTH_LONG).show();}/** * 在doInBackground非UI线程中执行耗时操作时候,调用publishProgress方法的时候才会调用该方法。 */@Overrideprotected void onProgressUpdate(Integer... values) {if(isCancelled()){return;}super.onProgressUpdate(values);mProgressBar.setProgress(values[0]);}
现在我们运行的话,就应该不会出现任何的问题了。

好了就写到这里吧!有问题的话大家可以一起探讨啊! 谢谢!








0 0
原创粉丝点击