zoukankan      html  css  js  c++  java
  • Android笔记(三十六) AsyncTask是如何执行的?

          在上一个例子中,我们是在LoadImage的onPostExecute中修改的UI,不是说只允许在主线程中修改UI吗?我们看一下源代码是如何操作的。

          MainActicity.java

    package cn.lixyz.asynctest;
    
    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.ProgressBar;
    
    import java.io.BufferedInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.URL;
    import java.net.URLConnection;
    
    public class MainActivity extends Activity{
    
        private Button button;
        private ImageView imageView;
        private ProgressBar progressBar;
        private String URL="http://ww3.sinaimg.cn/bmiddle/612c96afjw1ewwftl3uqkj20u00koq48.jpg";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            setContentView(R.layout.activity_main);
    
            //获取组件
            button = (Button) findViewById(R.id.button);
            imageView = (ImageView) findViewById(R.id.imageView);
            progressBar = (ProgressBar) findViewById(R.id.progressBar);
    
            //给button设置点击事件,点击按钮,启动异步任务
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    new LoadImage().execute(URL);
                }
            });
    
    
        }
    
        class LoadImage extends AsyncTask<String,Void,Bitmap>{
    
    
            //开始执行耗时操作,连接网络获取图片,并且将Bitmap返回
            @Override
            protected Bitmap doInBackground(String... params) {
                String url = params[0];
                Bitmap bitmap = null;
                URLConnection connection;
                InputStream is;
                try {
                    connection = new URL(url).openConnection();
                    Thread.sleep(5000);
                    is = connection.getInputStream();
                    BufferedInputStream bis = new BufferedInputStream(is);
                    bitmap  = BitmapFactory.decodeStream(bis);
                    is.close();
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return bitmap;
            }
    
            //onPreExcute方法是在doInBackGround方法前执行,用于做一些初始化操作,这里将progressBar显示出来
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
                progressBar.setVisibility(View.VISIBLE);
            }
    
    
            //doInBackGround方法执行后,会自动执行该方法,获取到doInBackGround返回的对象,然后更改UI
            @Override
            protected void onPostExecute(Bitmap bitmap) {
                super.onPostExecute(bitmap);
                progressBar.setVisibility(View.GONE);
                imageView.setImageBitmap(bitmap);
            }
        }
    }
    View Code

          acticity_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="4">
            <ImageView
                android:id="@+id/imageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"/>
            <ProgressBar
                android:id="@+id/progressBar"
                android:visibility="gone"
                android:layout_centerInParent="true"
                style="@style/Widget.AppCompat.ProgressBar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </RelativeLayout>
    
    
        <Button
            android:id="@+id/button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="点击载入" />
    </LinearLayout>
    View Code

          先找到AsyncTask的构造函数:

        public AsyncTask() {
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
    
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    Result result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                    return postResult(result);
                }
            };
    
            mFuture = new FutureTask<Result>(mWorker) {
                @Override
                protected void done() {
                    try {
                        postResultIfNotInvoked(get());
                    } catch (InterruptedException e) {
                        android.util.Log.w(LOG_TAG, e);
                    } catch (ExecutionException e) {
                        throw new RuntimeException("An error occurred while executing doInBackground()",
                                e.getCause());
                    } catch (CancellationException e) {
                        postResultIfNotInvoked(null);
                    }
                }
            };
        }

          可以看到在AsyncTask的构造函数中,仅仅初始化了两个变量 mWorker 和 mFuture 

          接着启动AsyncTask,我们找到 execute 方法:

        @MainThread
        public final AsyncTask<Params, Progress, Result> execute(Params... params) {
            return executeOnExecutor(sDefaultExecutor, params);
        }

          可以看到,在 execute() 方法中,只执行了一个 executeOnExecutor() ,我们继续看executeOnExecutor方法:

        @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;
        }

          可以看到,在 executeOnExecutor() 方法中,先判断了AsyncTask的状态,如果是 RUNNING 或者是 FINISHED 的话,则会抛出 IllegalStateException 异常,如果不是,则将AsyncTask的状态设置为 RUNNING  ,然后执行 onPreExecute() 方法,我们再看这个方法:

        @MainThread
        protected void onPreExecute() {
        }

          这个方法又没有做任何操作,之前我们讲过, onPreExecute() 方法是在执行 doInBackGround() 之前执行,用来做一些初始化操作的,所以如果我们有需要的话,就需要自己重写 onPreExecute() 方法了。

      接着看 executeOnExecutor() 方法,在执行完 onPreExecute() 方法之后,继续往下,将 params 赋值给 mWorker.mParams 之后,又执行了 exec.execute(mFuture) , mFuture 是在前面的构造方法中初始化的,我们看代码:

        public AsyncTask() {
            mWorker = new WorkerRunnable<Params, Result>() {
                public Result call() throws Exception {
                    mTaskInvoked.set(true);
    
                    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                    //noinspection unchecked
                    Result result = doInBackground(mParams);
                    Binder.flushPendingCommands();
                    return postResult(result);
                }
            };
    
            mFuture = new FutureTask<Result>(mWorker) {
                @Override
                protected void done() {
                    try {
                        postResultIfNotInvoked(get());
                    } catch (InterruptedException e) {
                        android.util.Log.w(LOG_TAG, e);
                    } catch (ExecutionException e) {
                        throw new RuntimeException("An error occurred while executing doInBackground()",
                                e.getCause());
                    } catch (CancellationException e) {
                        postResultIfNotInvoked(null);
                    }
                }
            };
        }

      可以看到在这里调用了 doInBackground() 方法,并最后返回了 postResult(result) ,再继续看,找到 postResult(result) 

        private Result postResult(Result result) {
            @SuppressWarnings("unchecked")
            Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                    new AsyncTaskResult<Result>(this, result));
            message.sendToTarget();
            return result;
        }

      可以看到,在这部分代码中,显示获取到了一个Handler,然后调用这个Handler对象的obtainMessage()方法得到一个Message对象,我们看一下获取到的这个Handler对象:

        private static Handler getHandler() {
            synchronized (AsyncTask.class) {
                if (sHandler == null) {
                    sHandler = new InternalHandler();
                }
                return sHandler;
            }
        }

      发现是一个 InternalHandler 对象,继续找这个 InternalHandler 对象

        private static class InternalHandler extends Handler {
            public InternalHandler() {
                super(Looper.getMainLooper());
            }
    
            @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
            @Override
            public void handleMessage(Message msg) {
                AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
                switch (msg.what) {
                    case MESSAGE_POST_RESULT:
                        // There is only one result
                        result.mTask.finish(result.mData[0]);
                        break;
                    case MESSAGE_POST_PROGRESS:
                        result.mTask.onProgressUpdate(result.mData);
                        break;
                }
            }
        }

      这里就清楚了,获取到的是一个 MainLooper ,也就是说获取的是在主线程中的Handler,也就是说,上面的操作最后将Message发送到了主线程中,然后根据发送过来的消息是  MESSAGE_POST_RESULT  还是 MESSAGE_POST_PROGRESS 来判断该执行什么方法

      如果是 MESSAGE_POST_RESULT  ,我们查看finish方法:

        private void finish(Result result) {
            if (isCancelled()) {
                onCancelled(result);
            } else {
                onPostExecute(result);
            }
            mStatus = Status.FINISHED;
        }

      到这里,就一目了然了,调用了onPostResult方法更新UI。

      整个流程走完,会发现其实AsyncTask还是Handler机制,只不过是对线程做了优化和封装而已

    更多内容:

      Android应用AsyncTask处理机制详解及源码分析

      Android异步类AsyncTask详解

  • 相关阅读:
    opencv 图片像素x,y 访问!!!
    python numpy 三维数组 排序问题
    python+opencv水表识别
    tesseractOCR安装
    cookie 的寻找和使用以及页面滚动(python+selenium)
    你还在用a标签吗?——用button替代a
    js正则高级函数(replace,matchAll用法),实现正则替换(实测很有效)
    腾讯云服务器centos7.2+nginx(开启gzip压缩)+uwsgi+Django+react
    轮播图采用js、jquery实现无缝滚动和非无缝滚动的四种案例实现,兼容ie低版本浏览器
    webstorm 添加css前缀(兼容)自动添加
  • 原文地址:https://www.cnblogs.com/xs104/p/4869669.html
Copyright © 2011-2022 走看看