使用AsyncTask进行异步加载

对于异步加载在平常的开发中使用的最多的就是Thread+Handler来完成的,但在处理单个后台异步任务的时候使用Handler进行处理会显得代码比较多,而且结构比较复杂,当然这是相对于AsyncTask来讲的,但是在进行多个异步操作以及也涉及到UI的更新操作的时候使用AsyncTask就会变得复杂起来,对于异步加载方案的选择还是需要以及业务逻辑的复杂程度来决定。

为了进行更简单的异步操作,Google为我们提供了AsyncTask进行异步操作,当然底层也是Thread和Handler的封装。

下面看一下使用AsyncTask进行异步加载的步骤:

1.继承AsyncTask抽象类,实现下面的方法:

class MyAsyncTask extends AsyncTask<Void,Void,Void>{

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }
        @Override
        protected Void doInBackground() {

        }
        @Override
        protected void onProgressUpdate() {
            super.onProgressUpdate(values);
        }
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
        }
    }

在继承AsyncTask的时候需要传入三个泛型参数:

a: Params: 在执行AsyncTask时需要的参数,用于在后台任务中使用,作为doInBackground( )方法的参数传递进去

b: Progress: 后台任务执行的时候,如果需要在界面上显示进度,此处的反省执行的类型,为进度的单位,一般为Integer

c: Result: 当后台任务执行完毕后需要返回值的的类型

注: 如果不需要传递参数,或者不需要返回值,此处将泛型指定为Void即可

AsyncTask抽象类几个常用方法的介绍:

a: onPreExecute(): 此方法在后台任务开始之前调用,用于进行界面上的初始化操作,比如显示一个进度条的对话框

b: doInBackground(): 此方法中的代码在子线程执行,一般用于处理一些耗时操作。doInBackground中的参数在AsyncTask的实例调用execute( )方法的时候传入,当然传入参数的类型与Params的类型有关,如果Params的泛型设置为Void则不需要传递参数。还有一点需要注意的是,由于此方法是执行在子线程中的,因此不能在该方法中进行更新Ui的操作。

c: onProgressUpdate(): 在 doInBackground()方法中调用了 publishProgress()方法后,此方法将很快被调用,在这个方法 中可以进行更新UI的操作,根据 publishProgress()传入的参数进行Ui进度的更新。

d: onPostExecute(): 当doInBackground中的任务执行完毕并通过return 返回后,就会调用此方法,doInBackground()方法返回的数据会作为参数传递到onPostExecute()方法中,此时可以利用返回的结果进行Ui的操作,或者关闭对话框。

一个最简单的异步任务只需要实现 doInBackground() 和onPostExecute()即可。


2.创建AsyncTask实例,执行任务:

 MyAsyncTask myAsyncTask = new MyAsyncTask();
 myAsyncTask.execute();

当然这里的execute()方法需要传递参数的类型,是由Params的泛型决定,如果为Void则不需要传递参数。
需要注意的是,一个AsyncTask的实例,只能执行一次execute()方法,如果执行多次会出现下面的异常:

这里写图片描述

execute()方法的实现:

    //定义的关于任务运行状态的几个枚举类型
     public static enum Status {
        FINISHED,
        PENDING,
        RUNNING;

        private Status() {
        }
    }

    public final AsyncTask<Params, Progress, Result> execute(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;  
        sExecutor.execute(mFuture);  

        return this;  
    }  

通过查看源码之后也就明白了为什么一个实例的execute()只能执行一次。


下面通过一个从网络加载图片的例子来使用一下AsyncTask:

运行效果:

这里写图片描述

示例代码:

/**
 * 使用AsyncTask进行网络图片加载并显示到ImageView
 */
public class AsyncTaskActivity extends AppCompatActivity implements View.OnClickListener {

    private ImageView imageView;
    private EditText editText;
    private Button btnSubmit;
    private String mImageUrl;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ansy_task);
        InitUI();

        btnSubmit.setOnClickListener(this);


    }

    private void InitUI() {
        imageView = (ImageView) findViewById(R.id.imageView_net);
        editText = (EditText) findViewById(R.id.edt_img_url);
        btnSubmit = (Button) findViewById(R.id.btn_show);
    }

    @Override
    public void onClick(View view) {

        MyAsyncTask myAsyncTask = new MyAsyncTask();
        mImageUrl = editText.getText().toString();
        myAsyncTask.execute(mImageUrl);



    }

    /**
     * 继承 AsyncTask 抽象类三个泛型参数的作用
     * 1.Params: 在执行AsyncTask时需要的参数,用于在后台任务中使用 (doInBackground)
     * 2.Progress: 后台任务执行的时候,如果需要在界面上显示进度,此处的反省执行的类型,为进度的单位,一般为Integer
     * 3.Result: 当后台任务执行完毕后需要返回值的的类型
     *  如果不需要传递参数,或者不需要返回值,此处将泛型指定为Void即可
     */
    class MyAsyncTask extends AsyncTask<String,Integer,Bitmap>{

        /**
         * 此方法在后台任务开始之前调用,用于进行界面上的初始化操作,比如显示一个进度条的对话框
         */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            Log.i("wk","onPreExecute()方法执行了,此方法用于进行初始化相关的工作");

        }


        /**
         *此方法中的代码执行在子线程,用于处理一些耗时操作,
         * doInBackground(String... strings)中的参数在 execute(str)方法中传入。
         * 处理完后使用return返回处理结果
         *
         * 当需要反馈当前操作进度的时候,可以调用publishProgress()方法来完成,根据传递的参数,在onProgressUpdate()
         * 进行显示进度的状态。
         *
         * 注:由于代码运行在子线程,不能在这个方法中进行更新UI的操作。
         *
         * String ...属于不定参数,可以传递对个String对象
         * @param strings
         * @return
         */
        @Override
        protected Bitmap doInBackground(String... strings) {

            Log.i("wk","imageUrl:"+strings[0]);

            //调用此方法来触发 onProgressUpdate()方法的执行,传入参数进行进度的更新
            publishProgress(100);


            InputStream is = getStreamFromUrl(strings[0]);

            Bitmap bitmap = BitmapFactory.decodeStream(is);


            return bitmap;
        }


        /**
         * 在 doInBackground()方法中调用了 publishProgress()方法后,此方法将很快被调用,在这个方法
         * 中可以进行更新UI的操作,根据 publishProgress();传入的参数进行进度的更新
         * @param values
         */
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);

            Log.i("wk","当前进度:"+values[0]);
        }

        /**
         * 当后台任务执行完毕并通过return 返回后,就会调用此方法,doInBackground()方法返回的
         * 数据会作为参数传递到onPostExecute()方法,此时可以利用返回的结果进行Ui的操作,或者关闭对话框。
         * @param bitmap
         */
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);

            imageView.setImageBitmap(bitmap);
        }
    }

    /**
     *
     * 根据Image的URL获取流
     * @param string
     * @return
     */
    private InputStream getStreamFromUrl(String string) {

        try {
            URL url = new URL(string);

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            conn.setRequestMethod("GET");
            conn.setDoInput(true);
            InputStream inputStream = conn.getInputStream();

            if(inputStream!=null){


                return inputStream;
            }


        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }

        return null;

    }


}

^_^

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值