android - onpostexecute - thread in asynctask




AsyncTask Android示例 (10)

概念和代碼在這裡

我創建了一個使用Android的AsyncTask的簡單示例。 它以onPreExecute(), doInBackground(), publishProgress()onProgressUpdate() onPreExecute(), doInBackground(), publishProgress()

在這個doInBackground()作為後台線程,而其他作品在UI線程中。 您無法訪問doInBackground()中的UI元素。 序列與我所提到的相同。

但是,如果您需要從doInBackground更新任何窗口小部件, doInBackground可以從doInBackground ,它將調用onProgressUpdate來更新您的UI窗口小部件。

class TestAsync extends AsyncTask<Void, Integer, String>
{
    String TAG = getClass().getSimpleName();

    protected void onPreExecute (){
        super.onPreExecute();
        Log.d(TAG + " PreExceute","On pre Exceute......");
    }

    protected String doInBackground(Void...arg0) {
        Log.d(TAG + " DoINBackGround","On doInBackground...");

        for(int i=0; i<10; i++){
            Integer in = new Integer(i);
            publishProgress(i);
        }
        return "You are at PostExecute";
    }

    protected void onProgressUpdate(Integer...a){
        super.onProgressUpdate(a);
        Log.d(TAG + " onProgressUpdate", "You are in progress update ... " + a[0]);
    }

    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        Log.d(TAG + " onPostExecute", "" + result);
    }
}

在您的活動中像這樣稱呼它:

new TestAsync().execute();

開發者參考這裡

我正在閱讀關於AsyncTask ,並嘗試了下面的簡單程序。 但它似乎並不奏效。 我怎樣才能使它工作?

package com.test;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings.System;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.view.View.OnClickListener;

public class AsyncTaskActivity extends Activity {
    Button btn;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btn = (Button) findViewById(R.id.button1);
        btn.setOnClickListener((OnClickListener) this);
    }

    public void onClick(View view){
        new LongOperation().execute("");
    }

    private class LongOperation extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... params) {
            for(int i=0;i<5;i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            TextView txt = (TextView) findViewById(R.id.output);
            txt.setText("Executed");
            return null;
        }

        @Override
        protected void onPostExecute(String result) {
        }

        @Override
        protected void onPreExecute() {
        }

        @Override
        protected void onProgressUpdate(Void... values) {
        }
    }
}

我只是試圖在後台進程中5秒後更改標籤。

這是我的main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:orientation="vertical" >
    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:indeterminate="false"
        android:max="10"
        android:padding="10dip">
    </ProgressBar>
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Progress" >
    </Button>
    <TextView android:id="@+id/output"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Replace"/>
</LinearLayout>

理論

AsyncTask允許您在後台線程上運行任務,同時將結果發佈到UI線程。

用戶應該始終能夠與應用程序進行交互,避免阻止主(UI)線程執行諸如從Web下載內容等任務很重要。 這是我們使用AsyncTask

UI線程有一個消息隊列和一個處理程序,它允許您通常從其他線程發送和處理可運行對象和消息。 AsyncTask使用簡單的接口來封裝這種行為。

履行

AsyncTask是一個通用類。 (這意味著它的構造函數需要參數化類型,每個泛型參數都被定義為一個帶有三個點的Java變量參數: ...所以在技術上以數組的形式傳遞)。

AsyncTask使用的三種類型是ParamsProgressResult

  1. Params - 執行時發送給任務的參數類型
  2. 進度 - 發布的類型,用於在後台計算期間更新進度
  3. 結果 - 背景計算結果的類型

這三個參數對應於您可以在AsyncTask重寫的三個主要函數:

  • doInBackground()
  • onProgressUpdate()
  • onPostExecute()

    也:

  • onPreExecute()

執行AsyncTask

調用Execute參數發送到後台任務。

怎麼了

  1. 在主/ UI線程上, onPreExecute 。 (在此線程中初始化某些內容。)
  2. 在後台線程上,使用傳遞給Execute函數的參數調用doInBackground()
    • 必須重寫至少doInBackground()才能使用AsyncTask。
    • 長期運行的任務應該發生在哪裡
    • 使用Progress參數調用publishProgress()以隨著長時間運行任務的進度更新一些UI。 這會導致onProgressUpdate()被調用。
  3. 在後台線程上,結果將從doInBackground()任務返回,這會導致
  4. 在main / UI線程上,使用返回的結果調用onPostExecute()

再次使用攔截任務的示例是從Web下載某個內容,以下示例會下載一個圖像並將其顯示在ImageView中。 doInBackground()方法下載圖像並將其存儲在類型為BitMap的對像中。 onPostExecute()方法獲取位圖並將其放置在ImageView中。

class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
    ImageView bitImage;

    public DownloadImageTask(ImageView bitImage) {
        this.bitImage = bitImage;
    }

    protected Bitmap doInBackground(String... urls) {
        String urldisplay = urls[0];
        Bitmap mBmp = null;
        try {
            InputStream in = new java.net.URL(urldisplay).openStream();
            mBmp = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
        return mBmp;
    }

    protected void onPostExecute(Bitmap result) {
        bitImage.setImageBitmap(result);
    }
}

只是:

LongOperation MyTask = new LongOperation();
MyTask.execute();

好的,你試圖通過另一個線程訪問GUI。 這主要是不好的做法。

AsyncTask執行另一個線程內的doInBackground()所有內容,該線程無法訪問視圖所在的GUI。

preExecute()postExecute()在這個新線程發生繁重事件之前和之後為您提供對GUI的訪問,甚至可以將長操作的結果傳遞給postExecute()以顯示任何處理結果。

看到以後更新TextView的位置:

TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");

把它們放在PostExecute()

doInBackground完成後,您將看到更新的TextView文本。

編輯:我注意到你的onClick監聽器不檢查,看看哪個視圖已被選中。 我發現最簡單的方法是通過switch語句。 我有一個完整的課程編輯如下,所有的建議,以避免混淆。

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings.System;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.view.View.OnClickListener;

public class AsyncTaskActivity extends Activity implements OnClickListener {

    Button btn;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = (Button) findViewById(R.id.button1);
        // because we implement OnClickListener we only have to pass "this"
        // (much easier)
        btn.setOnClickListener(this);
    }

    public void onClick(View view) {
        // detect the view that was "clicked"
        switch (view.getId()) {
        case R.id.button1:
            new LongOperation().execute("");
            break;
        }
    }

    private class LongOperation extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... params) {
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.interrupted();
                }
            }
            return "Executed";
        }

        @Override
        protected void onPostExecute(String result) {
            TextView txt = (TextView) findViewById(R.id.output);
            txt.setText("Executed"); // txt.setText(result);
            // might want to change "executed" for the returned string passed
            // into onPostExecute() but that is upto you
        }

        @Override
        protected void onPreExecute() {}

        @Override
        protected void onProgressUpdate(Void... values) {}
    }
}

我建議通過使用這個庫進行後台工作來讓你的生活更輕鬆https://github.com/Arasthel/AsyncJobLibrary

它的這個簡單..

AsyncJob.doInBackground(new AsyncJob.OnBackgroundJob() {

    @Override
    public void doOnBackground() {
        startRecording();
    }
});

我的完整答案在here ,但這裡是一個解釋性圖像,以補充此頁面上的其他答案。 對我而言,了解所有變量的起始位置是開始時最容易混淆的部分。


更改您的代碼,如下所示:

@Override
protected void onPostExecute(String result) {

    runOnUiThread(new Runnable() {
        public void run() {
            TextView txt = (TextView) findViewById(R.id.output);
            txt.setText("Executed");
        }
    });
}

最簡單的例子就是異步做某事:

class MyAsyncTask extends android.os.AsyncTask {
    @Override
    protected Object doInBackground(Object[] objects) {
        //do something asynchronously
        return null;
    }
}

運行它:

(new MyAsyncTask()).execute();

當您在工作線程中時,無法直接操作Android上的UI元素。

當你使用AsyncTask時,請理解回調方法。

例如:

public class MyAyncTask extends AsyncTask<Void, Void, Void>{

    @Override
    protected void onPreExecute() {
        // Here you can show progress bar or something on the similar lines.
        // Since you are in a UI thread here.
        super.onPreExecute();
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        // After completing execution of given task, control will return here.
        // Hence if you want to populate UI elements with fetched data, do it here.
    }

    @Override
    protected void onProgressUpdate(Void... values) {
        super.onProgressUpdate(values);
        // You can track you progress update here
    }

    @Override
    protected Void doInBackground(Void... params) {
        // Here you are in the worker thread and you are not allowed to access UI thread from here.
        // Here you can perform network operations or any heavy operations you want.
        return null;
    }
}

僅供參考:要從工作線程訪問UI線程,您可以在視圖上使用runOnUiThread()方法或post方法。

例如:

runOnUiThread(new Runnable() {
    textView.setText("something.");
});

or
    yourview.post(new Runnable() {
    yourview.setText("something");
});

這會幫助你更好地了解事情。 因此,在你的情況下,你需要在onPostExecute()方法中設置你的textview。


移動這兩行:

TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");

在你的AsyncTask的doInBackground方法中,並將它們放在onPostExecute方法中。 你的AsyncTask應該是這樣的:

private class LongOperation extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(String... params) {
        try {
            Thread.sleep(5000); // no need for a loop
        } catch (InterruptedException e) {
            Log.e("LongOperation", "Interrupted", e);
            return "Interrupted";
        }
        return "Executed";
    }      

    @Override
    protected void onPostExecute(String result) {               
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText(result);
    }
}




android-asynctask