美文网首页
AsyncTask的一些疑问

AsyncTask的一些疑问

作者: BlackNeko | 来源:发表于2017-01-22 22:17 被阅读101次

    使用:新建类继承AsyncTask,实现其doInBackground方法

    protected void onPreExecute()
    protected String doInBackground(String... params)
    protected void onProgressUpdate(Integer... values)
    protected void onCancelled()
    protected void onCancelled(String s)
    protected void onPostExecute(String s)
    

    或者直接new

    AsyncTask<String, Integer, String> asyncTask
                    = new AsyncTask<String, Integer, String>() {
        @Override
        protected String doInBackground(String... params) {
            return null;
        }
    };
    asyncTask.execute("hii");
    

    doInBackground(String... params) 中要更新UI可以调用 publishProgress(Progress... values) , publishProgress() 方法本身执行在异步线程,但会调用 Handler 发 MESSAGE_POST_PROGRESS事件抛到主线程,让 onProgressUpdate(Integer... values) 处理,不要手动调用 onProgressUpdate(Integer... values)

    为什么只能在UI线程创建?

    因为Android老的版本上用于线程间通信的 InternalHandler 创建时没有为其指定Looper,所以它会默认使用当前线程的Looper,如果当前线程没有事先调用过 Looper.prepare() ,就会报 RuntimeException("Can't create handler inside thread that has not called Looper.prepare()") 异常,即使调用过 Looper.prepare() 由于不是主线程,也不能去修改UI。至少在API 16上是这样,后来的版本里面这条被修改了,AsyncTask 在实例化 InternalHandler 是为其指定主线程。

    public InternalHandler() {
        super(Looper.getMainLooper());
    }
    

    为什么只能在主线程中调用 AsyncTask#execute() ?

    先看执行代码:

    @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }
    
    @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;
    }
    

    并没有为 onPreExecute() 方法的执行特别指定线程,所以 onPreExecute() 是执行在当前线程,如果要在 onPreExecute() 中修改UI的话,AsyncTask#execute() 就要在UI线程中执行。

    为什么一个AsyncTask实例只能执行一次?

    在并发条件下多次执行execute(),会让线程内的数据不安全,并没有加锁机制,而是限制一个Task只能被执行一次。

    其他

    仿 AsyncTask 做的一个单线程执行工具(从《Android开发进阶》这本书上看到的)

    DbCommand.java

    可以改单线程为多个线程:

    private static int coreThreadNum = Runtime.getRuntime().availableProcessors();
    private final static ExecutorService executor = new ThreadPoolExecutor(
             coreThreadNum, coreThreadNum, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
    

    相关文章

      网友评论

          本文标题: AsyncTask的一些疑问

          本文链接:https://www.haomeiwen.com/subject/spwobttx.html