วิธีรับผลลัพธ์ของ OnPostExecute () ไปยังกิจกรรมหลักเนื่องจาก AsyncTask เป็นคลาสแยกต่างหาก


361

ฉันมีสองคลาสนี้ กิจกรรมหลักของฉันและคนที่ยื่นออกมาในAsyncTaskตอนนี้ในกิจกรรมหลักของฉันฉันต้องการที่จะได้รับผลจากในOnPostExecute() AsyncTaskฉันจะส่งผ่านหรือรับผลลัพธ์ไปยังกิจกรรมหลักได้อย่างไร

นี่คือตัวอย่างรหัส

กิจกรรมหลักของฉัน

public class MainActivity extends Activity{

    AasyncTask asyncTask = new AasyncTask();

    @Override
    public void onCreate(Bundle aBundle) {
        super.onCreate(aBundle);            

        //Calling the AsyncTask class to start to execute.  
        asyncTask.execute(a.targetServer); 

        //Creating a TextView.
        TextView displayUI = asyncTask.dataDisplay;
        displayUI = new TextView(this);
        this.setContentView(tTextView); 
    }

}

นี่คือคลาส AsyncTask

public class AasyncTask extends AsyncTask<String, Void, String> {

TextView dataDisplay; //store the data  
String soapAction = "http://sample.com"; //SOAPAction header line. 
String targetServer = "https://sampletargeturl.com"; //Target Server.

//SOAP Request.
String soapRequest = "<sample XML request>";    



@Override
protected String doInBackground(String... string) {

String responseStorage = null; //storage of the response

try {


    //Uses URL and HttpURLConnection for server connection. 
    URL targetURL = new URL(targetServer);
    HttpURLConnection httpCon = (HttpURLConnection) targetURL.openConnection();
    httpCon.setDoOutput(true);
    httpCon.setDoInput(true);
    httpCon.setUseCaches(false); 
    httpCon.setChunkedStreamingMode(0);

    //properties of SOAPAction header
    httpCon.addRequestProperty("SOAPAction", soapAction);
    httpCon.addRequestProperty("Content-Type", "text/xml; charset=utf-8"); 
    httpCon.addRequestProperty("Content-Length", "" + soapRequest.length());
    httpCon.setRequestMethod(HttpPost.METHOD_NAME);


    //sending request to the server.
    OutputStream outputStream = httpCon.getOutputStream(); 
    Writer writer = new OutputStreamWriter(outputStream);
    writer.write(soapRequest);
    writer.flush();
    writer.close();


    //getting the response from the server
    InputStream inputStream = httpCon.getInputStream(); 
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);

    int intResponse = httpCon.getResponseCode();

    while ((intResponse = bufferedReader.read()) != -1) {
        byteArrayBuffer.append(intResponse);
    }

    responseStorage = new String(byteArrayBuffer.toByteArray()); 

    } catch (Exception aException) {
    responseStorage = aException.getMessage(); 
    }
    return responseStorage;
}

protected void onPostExecute(String result) {

    aTextView.setText(result);

}       

}   

คุณสามารถสร้างอินเทอร์เฟซอย่างที่ HelmiB อธิบายหรือคุณสามารถสร้างเครื่องรับสัญญาณออกอากาศในพื้นที่คุณสามารถดูตัวอย่างการใช้งาน reciver ของตัวกระจายเสียงได้ที่นี่wiki.workassis.com/android-local-broadcast-receiver
Bikesh M

ทำไมไม่ใช้รูปแบบการสังเกตการณ์?
JAAAY

คำตอบ:


750

ง่าย:

  1. สร้างinterfaceคลาสซึ่งString outputเป็นทางเลือกหรืออาจเป็นตัวแปรใดก็ได้ที่คุณต้องการส่งคืน

    public interface AsyncResponse {
        void processFinish(String output);
    }
    
  2. ไปที่AsyncTaskชั้นเรียนของคุณและประกาศอินเตอร์เฟสAsyncResponseเป็นฟิลด์:

    public class MyAsyncTask extends AsyncTask<Void, Void, String> {
      public AsyncResponse delegate = null;
    
        @Override
        protected void onPostExecute(String result) {
          delegate.processFinish(result);
        }
     }
    
  3. ในกิจกรรมหลักของคุณคุณต้องimplementsเชื่อมAsyncResponseต่อ

    public class MainActivity implements AsyncResponse{
      MyAsyncTask asyncTask =new MyAsyncTask();
    
      @Override
      public void onCreate(Bundle savedInstanceState) {
    
         //this to set delegate/listener back to this class
         asyncTask.delegate = this;
    
         //execute the async task 
         asyncTask.execute();
      }
    
      //this override the implemented method from asyncTask
      @Override
      void processFinish(String output){
         //Here you will receive the result fired from async class 
         //of onPostExecute(result) method.
       }
     }
    

UPDATE

ฉันไม่ทราบว่าสิ่งนี้เป็นที่ชื่นชอบของคุณ interfaceดังนั้นที่นี่เป็นที่เรียบง่ายและความสะดวกสบายวิธีการใช้งาน

interfaceยังคงใช้เหมือนกัน FYI คุณอาจรวมสิ่งนี้เข้ากับAsyncTaskคลาส

ในAsyncTaskชั้นเรียน:

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

  // you may separate this or combined to caller class.
  public interface AsyncResponse {
        void processFinish(String output);
  }

  public AsyncResponse delegate = null;

    public MyAsyncTask(AsyncResponse delegate){
        this.delegate = delegate;
    }

    @Override
    protected void onPostExecute(String result) {
      delegate.processFinish(result);
    }
}

ทำสิ่งนี้ในActivityชั้นเรียนของคุณ

public class MainActivity extends Activity {

   MyAsyncTask asyncTask = new MyAsyncTask(new AsyncResponse(){

     @Override
     void processFinish(String output){
     //Here you will receive the result fired from async class 
     //of onPostExecute(result) method.
     }
  }).execute();

 }

หรือใช้อินเทอร์เฟซบนกิจกรรมอีกครั้ง

public class MainActivity extends Activity 
    implements AsyncResponse{

    @Override
    public void onCreate(Bundle savedInstanceState) {

        //execute the async task 
        new MyAsyncTask(this).execute();
    }

    //this override the implemented method from AsyncResponse
    @Override
    void processFinish(String output){
        //Here you will receive the result fired from async class 
        //of onPostExecute(result) method.
    }
}

ในขณะที่คุณสามารถเห็นวิธีแก้ไขปัญหา 2 ข้อด้านบนวิธีแรกและวิธีที่สามจำเป็นต้องสร้างวิธีการprocessFinishส่วนอีกวิธีหนึ่งอยู่ภายในพารามิเตอร์ผู้โทร ที่สามเป็นระเบียบมากขึ้นเนื่องจากไม่มีคลาสที่ไม่ระบุชื่อซ้อนกัน หวังว่านี่จะช่วยได้

เคล็ดลับ : การเปลี่ยนแปลงString output, String responseและString resultประเภทการจับคู่ที่แตกต่างกันเพื่อให้ได้รับวัตถุที่แตกต่าง


20
เขียนทั้งหมดทั้งหมดแล้วเห็นคำตอบของคุณ :) นี่คือความคิดที่เหมือนกัน! +1 ด้วยวิธีนี้หลายสิ่งสามารถฟังผลลัพธ์ของ AsyncTask!
Roloc

8
ฉันได้รับข้อยกเว้น nullpointer เนื่องจากผู้รับมอบสิทธิ์ถูกตั้งค่าเป็นโมฆะโปรด
ล้างข้อมูล

2
เพียงทราบสำหรับนักพัฒนา. net หนึ่งสามารถใช้ AutoResetEvents เพื่อให้บรรลุนี้และยังมีการใช้งานจาวาสำหรับ autoresetevents แต่สิ่งนี้สะอาดกว่ามาก ProcessFinish thread ปลอดภัยหรือไม่
Syler

13
สำหรับทุกคนที่ได้รับตัวชี้โมฆะผ่านอินเทอร์เฟซของคุณไปยังตัวสร้างคลาส asyncTask ของคุณจากนั้นกำหนดให้กับตัวแปรแล้วเรียก processfinish () บนตัวแปรนั้น สำหรับการอ้างอิงดู asnwer ได้รับการยอมรับ stackoverflow.com/questions/9963691/…
ซันนี่

2
@Sunny คุณพูดถูก ... เราต้องเริ่มต้นวัตถุ async สำหรับ async.delegate = this; ในการทำงาน ..
Ninja_Coder

24

มีตัวเลือกน้อย:

  • รังAsyncTaskชั้นภายในของคุณActivityระดับ สมมติว่าคุณไม่ได้ใช้งานเดียวกันในหลาย ๆ กิจกรรมนี่เป็นวิธีที่ง่ายที่สุด รหัสทั้งหมดของคุณยังคงเหมือนเดิมคุณเพียงแค่ย้ายคลาสงานที่มีอยู่ไปเป็นคลาสซ้อนภายในคลาสของกิจกรรมของคุณ

    public class MyActivity extends Activity {
        // existing Activity code
        ...
    
        private class MyAsyncTask extends AsyncTask<String, Void, String> {
            // existing AsyncTask code
            ...
        }
    }
  • สร้างตัวสร้างที่กำหนดเองสำหรับคุณที่จะมีการอ้างอิงถึงคุณAsyncTask คุณจะยกตัวอย่างงานกับสิ่งที่ต้องการActivitynew MyAsyncTask(this).execute(param1, param2)

    public class MyAsyncTask extends AsyncTask<String, Void, String> {
        private Activity activity;
    
        public MyAsyncTask(Activity activity) {
            this.activity = activity;
        }
    
        // existing AsyncTask code
        ...
    }

ในตัวเลือกที่สอง: ทำไมต้องผ่านความเจ็บปวดของคอนสตรัคเตอร์และฟิลด์ถ้าคลาสไม่ใช่static? เพียงแค่ใช้fieldOrMethodจากMyActivityหรือMyActivity.this.fieldOrMethodถ้ามันเป็นเงา
TWiStErRob

@TWiStErRob ที่สองถือว่าMyAsyncTaskเป็นไม่ได้ระดับชั้น
quietmint

1
โอ้ขอโทษprivate/ protectedสำหรับชั้นเรียนระดับสูงสุดไม่ได้รับอนุญาตดังนั้นฉันคิดว่ามันจะต้องเป็นstaticชั้นที่ไม่ได้อยู่ภายใน
TWiStErRob

2
เพียงแค่ระวังว่า AsyncTask ชั้นในสามารถเป็นแหล่งที่มาของหน่วยความจำรั่วตามที่อธิบายไว้ที่นี่garena.github.io/blog/2014/09/10/android-memory-leaks
Mark Pazon

2
การเก็บข้อมูลอ้างอิงกิจกรรมไว้เป็นความจำที่ไม่แน่นอน วิธีการติดต่อกลับดีกว่านี้
OneCricketeer

19

ฉันรู้สึกว่าวิธีการด้านล่างนั้นง่ายมาก

ฉันได้ประกาศอินเทอร์เฟซสำหรับการโทรกลับ

public interface AsyncResponse {
    void processFinish(Object output);
}

จากนั้นสร้างภารกิจแบบอะซิงโครนัสสำหรับตอบคำขอแบบขนานทุกประเภท

 public class MyAsyncTask extends AsyncTask<Object, Object, Object> {

    public AsyncResponse delegate = null;//Call back interface

    public MyAsyncTask(AsyncResponse asyncResponse) {
        delegate = asyncResponse;//Assigning call back interfacethrough constructor
    }

    @Override
    protected Object doInBackground(Object... params) {

      //My Background tasks are written here

      return {resutl Object}

    }

    @Override
    protected void onPostExecute(Object result) {
        delegate.processFinish(result);
    }

}

จากนั้นเรียกว่าภารกิจอะซิงโครนัสเมื่อคลิกปุ่มในคลาสกิจกรรม

public class MainActivity extends Activity{

    @Override
    public void onCreate(Bundle savedInstanceState) {

    Button mbtnPress = (Button) findViewById(R.id.btnPress);

    mbtnPress.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() {

                    @Override
                    public void processFinish(Object output) {
                        Log.d("Response From Asynchronous task:", (String) output);

                        mbtnPress.setText((String) output);
                   }
                });

                asyncTask.execute(new Object[] { "Your request to aynchronous task class is giving here.." });


            }
        });

    }



}

ขอบคุณ


17

คุณสามารถลองใช้รหัสนี้ในชั้นเรียนหลักของคุณ ที่ได้ผลสำหรับฉัน แต่ฉันได้ใช้วิธีการในทางอื่น

try {
    String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
} 
catch (ExecutionException | InterruptedException ei) {
    ei.printStackTrace();
}

2
คุณช่วยอธิบายได้ไหมว่าทำไมสิ่งนี้ถึงช่วยให้ OP มีปัญหา
John Odom

3
นั่นช่วยฉัน ฉันลองวิธีอื่นเช่นคำตอบจาก @HelmiB แต่ฉันไม่ได้ผลลัพธ์
Nicu P

โอเคขอโทษสำหรับคำตอบของฉัน เธอจำเป็นต้องเรียกคลาส AsyncTask แล้วจึงใส่พารามิเตอร์ไปยังการเรียกนี้ AsyncTask ถูกกำหนดโดย 3 ประเภททั่วไป: 1 params (โดเมนเซิร์ฟเวอร์หรือพารามิเตอร์อื่น ๆ ) 2 ความคืบหน้า (สามารถเป็นโมฆะ), 3 ผลลัพธ์ ชนิดเหล่านี้ทั้งหมดสามารถเป็น: JSONObject หรือสตริงหรือชนิดข้อมูลใด ๆ เมื่อคุณมีคลาส AsyncTask คุณควรกำหนดตำแหน่งที่จะส่งข้อมูล เช่น asyncTask.execute (" sampletargeturl.com"). get () ;
Nicu P

เมื่อใช้วิธีนี้ฉันได้รับคำเตือนเกี่ยวกับ Logcat: "I / Choreographer﹕ ข้ามเฟรม 50 เฟรม! แอปพลิเคชันอาจทำงานได้มากเกินไปบนเธรดหลัก" วิธีจัดการกับสิ่งนี้? UI ค้างเมื่อรอส่งคืนจาก AsyncTask หรือไม่
Huy Do

@NicuP คุณอาจลืมโทรexecute()ดูคำตอบของฉันฉันได้เพิ่มความคิดเห็นแล้ว คุณอาจต้องการตรวจสอบคำตอบที่อัปเดตของฉัน หวังว่านี่จะช่วยได้
HelmiB

16

คำตอบนี้อาจจะช้า แต่ผมอยากจะพูดถึงบางสิ่งเมื่อคุณขึ้นอยู่กับActivity AsyncTaskที่จะช่วยคุณป้องกันการล่มและการจัดการหน่วยความจำ ดังที่ได้กล่าวไปแล้วในคำตอบข้างต้นไปด้วยinterfaceเราก็บอกว่าพวกเขาเรียกกลับ พวกเขาจะทำงานเป็นผู้รายงาน แต่ไม่เคยส่งการอ้างอิงที่แข็งแกร่งActivityหรือinterfaceใช้การอ้างอิงที่อ่อนแอเสมอไปในกรณีเหล่านั้น

โปรดดูภาพหน้าจอด้านล่างเพื่อค้นหาวิธีการที่อาจทำให้เกิดปัญหา

ป้อนคำอธิบายรูปภาพที่นี่

อย่างที่คุณสามารถดูว่าเราเริ่มต้นAsyncTaskด้วยการอ้างอิงที่แข็งแกร่งแล้วไม่มีการรับประกันว่าActivity/ ของเราFragmentจะมีชีวิตอยู่จนกว่าเราจะได้รับข้อมูลดังนั้นจะเป็นการดีกว่าที่จะใช้WeakReferenceในกรณีเหล่านั้นและจะช่วยในการจัดการหน่วยความจำ การอ้างอิงที่แข็งแกร่งของเราActivityนั้นจะมีสิทธิ์ได้รับการเก็บขยะหลังจากการบิดเบือน

ตรวจสอบข้อมูลโค้ดด้านล่างเพื่อค้นหาวิธีใช้ WeakReference ที่ยอดเยี่ยม -

MyTaskInformer.java ส่วนต่อประสานซึ่งจะทำงานเป็นผู้แจ้ง

public interface MyTaskInformer {

    void onTaskDone(String output);

}

MySmallAsyncTask.javaAsyncTask WeakReferenceการทำงานระยะยาวซึ่งจะใช้

public class MySmallAsyncTask extends AsyncTask<String, Void, String> {

    // ***** Hold weak reference *****
    private WeakReference<MyTaskInformer> mCallBack;

    public MySmallAsyncTask(MyTaskInformer callback) {
        this.mCallBack = new WeakReference<>(callback);
    }

    @Override
    protected String doInBackground(String... params) {

        // Here do whatever your task is like reading/writing file
        // or read data from your server or any other heavy task

        // Let us suppose here you get response, just return it
        final String output = "Any out, mine is just demo output";

        // Return it from here to post execute
        return output;
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);

        // Here you can't guarantee that Activity/Fragment is alive who started this AsyncTask

        // Make sure your caller is active

        final MyTaskInformer callBack = mCallBack.get();

        if(callBack != null) {
            callBack.onTaskDone(s);
        }
    }
}

MainActivity.javaชั้นนี้ใช้ในการเริ่มต้นAsyncTaskใช้งานของฉันinterfaceในชั้นoverrideนี้และวิธีการบังคับนี้

public class MainActivity extends Activity implements MyTaskInformer {

    private TextView mMyTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMyTextView = (TextView) findViewById(R.id.tv_text_view);

        // Start your AsyncTask and pass reference of MyTaskInformer in constructor
        new MySmallAsyncTask(this).execute();
    }

    @Override
    public void onTaskDone(String output) {

        // Here you will receive output only if your Activity is alive.
        // no need to add checks like if(!isFinishing())

        mMyTextView.setText(output);
    }
}

2
มันเยี่ยมมาก! จุดสำคัญที่ไม่สามารถสังเกตเห็นได้
HasH

6

ใน Oncreate ของคุณ ():

`

myTask.execute("url");
String result = "";
try {
      result = myTask.get().toString();
} catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
}catch (ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

} `


6

คุณสามารถทำได้ในไม่กี่บรรทัดเพียงแทนที่ onPostExecute เมื่อคุณโทร AsyncTask ของคุณ นี่คือตัวอย่างสำหรับคุณ:

new AasyncTask()
{
    @Override public void onPostExecute(String result)
    {
       // do whatever you want with result 
    }
}.execute(a.targetServer);

ฉันหวังว่ามันจะช่วยให้คุณมีความสุขการเข้ารหัส :)


มันไม่ทำงานสำหรับฉัน มันไม่ได้เข้าสู่onPostExecuteวิธีการ
Francisco Romero

4

ทำไมผู้คนถึงทำให้มันยากเหลือเกิน

นี้ควรจะเพียงพอ

ห้ามใช้งาน onPostExecute บนงาน async แต่ควรนำไปใช้กับกิจกรรม:

public class MainActivity extends Activity 
{

@Override
public void onCreate(Bundle savedInstanceState) {

    //execute the async task 
    MyAsyncTask task = new MyAsyncTask(){
            protected void onPostExecute(String result) {
                //Do your thing
            }       

    }

    task.execute("Param");

}


}

มันใช้งานได้สำหรับฉัน มันง่ายและเข้าใจง่ายที่สุด ฉันคิดว่ามันใช้ประโยชน์จากสิ่งที่ Java ถูกออกแบบมาให้ทำ ขอบคุณ PS: จำเป็นต้องเพิ่ม@Overrideหรือไม่
แก่เก่า

1
ไม่ @Override เป็นเพียงคำอธิบายประกอบ ดังนั้นคุณกำลังบอกคอมไพเลอร์ java ว่าคุณตั้งใจจะลบล้างเมธอดและรับข้อมูลหากคุณไม่ได้ทำเช่นนั้น
bugdayci

4

คุณสามารถเรียกget()วิธีการของAsyncTask(หรือโอเวอร์โหลดget(long, TimeUnit)) วิธีนี้จะบล็อกจนกว่าจะAsyncTaskเสร็จสิ้นการทำงานของมัน ณ จุดนั้นมันจะกลับมาให้คุณResultได้เสร็จสิ้นการทำงานตรงจุดนี้ก็จะกลับคุณ

เป็นการดีที่คุณจะต้องทำงานอื่น ๆ ระหว่างการสร้าง / เริ่มต้นภารกิจ async ของคุณและเรียกใช้getวิธีการไม่เช่นนั้นคุณจะไม่ได้ใช้งาน async อย่างมีประสิทธิภาพมากนัก


1
Downvoted vecause get () จะบล็อกเธรดหลัก ไม่มีเหตุผลที่จะใช้ AsyncTask ถ้ามันจะปิดกั้น
GabrielBB

3

คุณสามารถเขียนผู้ฟังของคุณเอง มันเหมือนกับHelmiBคำตอบของแต่ดูเป็นธรรมชาติมากกว่า:

สร้างส่วนต่อประสานฟัง:

public interface myAsyncTaskCompletedListener {
    void onMyAsynTaskCompleted(int responseCode, String result);
}

จากนั้นเขียนภารกิจอะซิงโครนัสของคุณ:

public class myAsyncTask extends AsyncTask<String, Void, String> {

    private myAsyncTaskCompletedListener listener;
    private int responseCode = 0;

    public myAsyncTask() {
    }

    public myAsyncTask(myAsyncTaskCompletedListener listener, int responseCode) {
        this.listener = listener;
        this.responseCode = responseCode;
    }

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


    @Override
    protected String doInBackground(String... params) {
        String result;
        String param = (params.length == 0) ? null : params[0];
        if (param != null) {
            // Do some background jobs, like httprequest...
            return result;
        }
        return null;
    }

    @Override
    protected void onPostExecute(String finalResult) {
        super.onPostExecute(finalResult);
        if (!isCancelled()) {
            if (listener != null) {
                listener.onMyAsynTaskCompleted(responseCode, finalResult);
            }
        }
    }
}

ในที่สุดก็ใช้ฟังในกิจกรรม:

public class MainActivity extends AppCompatActivity implements myAsyncTaskCompletedListener {

    @Override
    public void onMyAsynTaskCompleted(int responseCode, String result) {

        switch (responseCode) {
            case TASK_CODE_ONE: 
                // Do something for CODE_ONE
                break;
            case TASK_CODE_TWO:
                // Do something for CODE_TWO
                break;
            default: 
                // Show some error code
        }        
    }

และนี่คือวิธีที่คุณสามารถเรียกใช้ asyncTask:

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Some other codes...
        new myAsyncTask(this,TASK_CODE_ONE).execute("Data for background job");
        // And some another codes...
}

2

สวัสดีคุณสามารถทำสิ่งนี้:

  1. สร้างคลาสที่ใช้ AsyncTask

    // TASK 
    public class SomeClass extends AsyncTask<Void, Void, String>>
    {
    
        private OnTaskExecutionFinished _task_finished_event;
    
        public interface OnTaskExecutionFinished
        {
            public void OnTaskFihishedEvent(String Reslut);
        }
    
        public void setOnTaskFinishedEvent(OnTaskExecutionFinished _event)
        {
            if(_event != null)
            {
                this._task_finished_event = _event;
            }
        }
    
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
    
        }
    
        @Override
        protected String doInBackground(Void... params)
        {
            // do your background task here ...
    
            return "Done!";
        }
    
        @Override
        protected void onPostExecute(String result)
        {
            super.onPostExecute(result);
            if(this._task_finished_event != null)
            {
                this._task_finished_event.OnTaskFihishedEvent(result);
            }
            else
            {
                Log.d("SomeClass", "task_finished even is null");
            }
        }
    }
  2. เพิ่มในกิจกรรมหลัก

    // MAIN ACTIVITY
    public class MyActivity extends ListActivity
    {
       ...
        SomeClass _some_class = new SomeClass();
        _someclass.setOnTaskFinishedEvent(new _some_class.OnTaskExecutionFinished()
        {
        @Override
        public void OnTaskFihishedEvent(String result)
        {
            Toast.makeText(getApplicationContext(),
                    "Phony thread finished: " + result,
                    Toast.LENGTH_SHORT).show();
        }
    
       });
       _some_class.execute();
       ...
     }

1

สร้างสมาชิกสแตติกในคลาสกิจกรรมของคุณ จากนั้นกำหนดค่าระหว่างonPostExecute

ตัวอย่างเช่นหากผลลัพธ์ของ AsyncTask ของคุณเป็นสตริงให้สร้างสตริงคงที่สาธารณะในกิจกรรมของคุณ

public static String dataFromAsyncTask;

จากนั้นในonPostExecuteAsyncTask เพียงทำการโทรไปที่คลาสหลักของคุณและตั้งค่า

MainActivity.dataFromAsyncTask = "result blah";


1
ความเป็นไปได้ของการรั่วไหลของหน่วยความจำในสถานการณ์นี้คืออะไร?
แอนดรอยด์

0

ฉันทำให้มันทำงานได้โดยใช้เธรดและตัวจัดการ / ข้อความ ขั้นตอนดังต่อไปนี้: ประกาศกล่องโต้ตอบความคืบหน้า

ProgressDialog loadingdialog;

สร้างฟังก์ชั่นเพื่อปิดกล่องโต้ตอบเมื่อการดำเนินการเสร็จสิ้น

   private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        loadingdialog.dismiss();

    }
    };

รหัสรายละเอียดการดำเนินการของคุณ:

 public void startUpload(String filepath) {
    loadingdialog = ProgressDialog.show(MainActivity.this, "Uploading", "Uploading Please Wait", true);
    final String _path = filepath;
    new Thread() {
        public void run() {
            try {
                UploadFile(_path, getHostName(), getPortNo());
                handler.sendEmptyMessage(0);

            } catch (Exception e) {
                Log.e("threadmessage", e.getMessage());
            }
        }
    }.start();
}

0

คุณต้องใช้"โปรโตคอล"เพื่อมอบหมายหรือให้ข้อมูลกับAsynTaskที่จะมอบหมายหรือให้ข้อมูลไปยัง

ผู้รับมอบสิทธิ์และแหล่งข้อมูล

ผู้รับมอบสิทธิ์เป็นวัตถุที่ทำหน้าที่ในนามของหรือในการประสานงานกับวัตถุอื่นเมื่อวัตถุนั้นพบเหตุการณ์ในโปรแกรม ( คำจำกัดความของ Apple )

โปรโตคอลเป็นอินเตอร์เฟสที่กำหนดวิธีการบางอย่างเพื่อมอบหมายพฤติกรรมบางอย่าง

นี่คือตัวอย่างที่สมบูรณ์ !!!


0

ลองนี้:

public class SomAsyncTask extends AsyncTask<String, Integer, JSONObject> {

    private CallBack callBack;

    public interface CallBack {
        void async( JSONObject jsonResult );
        void sync( JSONObject jsonResult );
        void progress( Integer... status );
        void cancel();
    }

    public SomAsyncTask(CallBack callBack) {
        this.callBack = callBack;
    }

    @Override
    protected JSONObject doInBackground(String... strings) {

        JSONObject dataJson = null;

        //TODO query, get some dataJson

        if(this.callBack != null)
            this.callBack.async( dataJson );// asynchronize with MAIN LOOP THREAD

        return dataJson;

    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

        if(this.callBack != null)
            this.callBack.progress(values);// synchronize with MAIN LOOP THREAD

    }

    @Override
    protected void onPostExecute(JSONObject jsonObject) {
        super.onPostExecute(jsonObject);

        if(this.callBack != null)
            this.callBack.sync(jsonObject);// synchronize with MAIN LOOP THREAD
    }

    @Override
    protected void onCancelled() {
        super.onCancelled();

        if(this.callBack != null)
            this.callBack.cancel();

    }
}

และตัวอย่างการใช้งาน:

public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);

         final Context _localContext = getContext();
         SomeAsyncTask.CallBack someCallBack = new SomeAsyncTask.CallBack() {

                @Override
                public void async(JSONObject jsonResult) {//async thread
                    //some async process, e.g. send data to server...
                }

                @Override
                public void sync(JSONObject jsonResult) {//sync thread
                    //get result...

                    //get some resource of Activity variable...
                    Resources resources = _localContext.getResources();
                }

                @Override
                public void progress(Integer... status) {//sync thread
                    //e.g. change status progress bar...
                }

                @Override
                public void cancel() {

                }

            };

            new SomeAsyncTask( someCallBack )
                                .execute("someParams0", "someParams1", "someParams2");

    }

0

อาจจะลงน้ำเล็กน้อย แต่ฉันให้โทรกลับทั้งรหัสการดำเนินการและผลลัพธ์ แน่นอนว่าเพื่อความปลอดภัยของเธรดคุณต้องระวังสิ่งที่คุณเข้าถึงในการดำเนินการติดต่อกลับ

การใช้ AsyncTask:

public class AsyncDbCall<ExecuteType,ResultType> extends AsyncTask<ExecuteType, Void,  
ResultType>
{
    public interface ExecuteCallback<E, R>
    {
        public R execute(E executeInput);
    }
    public interface PostExecuteCallback<R>
    {
        public void finish(R result);
    }

    private PostExecuteCallback<ResultType> _resultCallback = null;
    private ExecuteCallback<ExecuteType,ResultType> _executeCallback = null;


    AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback, PostExecuteCallback<ResultType> postExecuteCallback)
    {
        _resultCallback = postExecuteCallback;
        _executeCallback = executeCallback;
    }

    AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback)
    {
        _executeCallback = executeCallback;
    }

    @Override
    protected ResultType doInBackground(final ExecuteType... params)
    {
        return  _executeCallback.execute(params[0]);
    }

    @Override
    protected void onPostExecute(ResultType result)
    {
        if(_resultCallback != null)
            _resultCallback.finish(result);
    }
}

โทรกลับ:

 AsyncDbCall.ExecuteCallback<Device, Device> updateDeviceCallback = new 
 AsyncDbCall.ExecuteCallback<Device, Device>()
    {
        @Override
        public Device execute(Device device)
        {
            deviceDao.updateDevice(device);
            return device;
        }
    };

และในที่สุดการเรียกใช้งาน async:

 new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);

0

หวังว่าคุณจะผ่านเรื่องนี้ถ้าไม่โปรดอ่าน

https://developer.android.com/reference/android/os/AsyncTask

คุณควรเลือกตัวเลือกที่ดีที่สุดเท่าที่จะเป็นไปได้ทั้งนี้ขึ้นอยู่กับลักษณะของข้อมูลผลลัพธ์

เป็นตัวเลือกที่ยอดเยี่ยมในการใช้งานส่วนต่อประสาน

ตัวเลือกอื่น ๆ จะเป็น ..

  • หากมีการกำหนดคลาส AsyncTask ภายในคลาสที่คุณต้องการใช้ผลลัพธ์ให้ใช้ตัวแปรโกลบอลแบบคงที่หรือ get () ให้ใช้จากคลาสภายนอก ( ตัวแปรระเหยถ้าจำเป็น) แต่ควรตระหนักถึงความคืบหน้าของ AsyncTask หรืออย่างน้อยควรตรวจสอบให้แน่ใจว่างานนั้นเสร็จสิ้นแล้วและมีให้บริการผ่านวิธีการตัวแปร / get () ทั่วโลก คุณสามารถใช้ การสำรวจ, onProgressUpdate (ความคืบหน้า ... ) , การซิงโครไนซ์หรืออินเทอร์เฟซ (ซึ่งเหมาะกับคุณที่สุด)

  • หากผลเป็นที่รองรับจะเป็นรายการ sharedPreference หรือมันโอเคที่จะได้รับการบันทึกเป็นไฟล์ในหน่วยความจำที่คุณสามารถบันทึกไว้แม้จะมาจากงานพื้นหลังตัวเองและสามารถใช้onPostExecute ()วิธีการ
    ที่จะได้รับการแจ้งเตือนเมื่อผลที่ได้คือมีอยู่ใน ความทรงจำ.

  • หากสตริงมีขนาดเล็กเพียงพอและจะใช้กับการเริ่มต้นของกิจกรรม เป็นไปได้ที่จะใช้intents ( putExtra () ) ภายใน onPostExecute ()แต่โปรดจำไว้ว่าบริบทคงที่นั้นไม่ปลอดภัย สำหรับการจัดการ

  • หากเป็นไปได้คุณสามารถเรียกใช้วิธีการคงที่จากเมธอด onPostExecute () โดยผลลัพธ์จะเป็นพารามิเตอร์ของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.