a

Câu hỏi Trả về một giá trị từ AsyncTask trong Android [trùng lặp]


Câu hỏi này đã có câu trả lời ở đây:

Một câu hỏi đơn giản: có thể trả về một giá trị trong AsyncTask?

//AsyncTask is a member class
private class MyTask extends AsyncTask<Void, Void, Void>{

    protected Void doInBackground(Void... params) {
         //do stuff
         return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        //do stuff
        //how to return a value to the calling method?
    }
}

Và sau đó trong vòng của tôi Activity/Fragment:

// The task is started from activity
myTask.execute()
// something like this?
myvalue = myTask.getvalue() 

CHỈNH SỬA: Điều này đã được hỏi một thời gian dài trước đây, nơi tôi đã không quen thuộc với Java, bây giờ mà tôi tốt hơn với nó, tôi sẽ làm một bản tóm tắt nhanh chóng:

Điểm của nhiệm vụ không đồng bộ là nhiệm vụ là asynchronous, nghĩa là sau khi bạn gọi execute() về nhiệm vụ, nhiệm vụ bắt đầu chạy trên một chuỗi của riêng nó. trả về một giá trị từ asynctask sẽ là vô nghĩa vì chuỗi gọi ban đầu đã thực hiện trên các công cụ khác (do đó tác vụ không đồng bộ).

Hãy nghĩ về thời gian: Tại một thời điểm, bạn đã bắt đầu một tác vụ sẽ chạy song song với luồng chính. Khi tác vụ chạy song song hoàn thành, thời gian cũng đã trôi qua trên luồng chính. Tác vụ song song không thể quay ngược thời gian để trả về giá trị cho chuỗi chính.

Tôi đã đến từ C vì vậy tôi không biết nhiều về điều này. Nhưng có vẻ như rất nhiều người đang có cùng một câu hỏi nên tôi nghĩ tôi sẽ xóa nó một chút.


92
2018-02-26 23:19


gốc


Liên quan đến chỉnh sửa của bạn; một tập hợp liên quan chặt chẽ của các đối tượng dựa trên luồng không có khái niệm trả về một cái gì đó; threadpools và tương lai. Khi bạn gửi một nhiệm vụ cho một hồ bơi thread bạn sẽ có được một tương lai. Tại một số thời điểm trong tương lai (hy vọng sau khi cuộc chạy đua kết thúc), bạn hỏi tương lai cho giá trị trả về của nó. Nếu runnable đã kết thúc bạn ngay lập tức nhận được giá trị trả về, nếu không phải là thread đợi cho đến khi nó kết thúc. Tôi thường sử dụng điều này để nhổ một cái gì đó vào một số phần, chạy chúng tất cả đồng thời và sau đó nhận được kết quả (thường chỉ có một vài dòng sau) - Richard Tingle
@RichardTingle bạn có thể cung cấp cho tôi một số liên kết về những gì bạn đang nói về ... mẫu mã sẽ tốt hơn. Cảm ơn trước & plzz đừng quên đề cập đến tôi trong bình luận của bạn. - kumar kundan
Tôi có thể có kết quả với một thứ gì đó giống như người nghe không? - rostamiani
Có, nhưng hãy cẩn thận không để rò rỉ nó, sử dụng WeakReference hoặc một cái gì đó tương tự - tom91136


Các câu trả lời:


Tại sao không gọi một phương thức xử lý giá trị?

public class MyClass extends Activity {

    private class myTask extends AsyncTask<Void, Void, Void> {

        //initiate vars
        public myTask() {
            super();
            //my params here
        }

        protected Void doInBackground(Void... params) {
            //do stuff
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            //do stuff
            myMethod(myValue);
        }
    }

    private myHandledValueType myMethod(Value myValue) {
        //handle value 
        return myHandledValueType;
    }
}

26
2018-02-26 23:22



và làm thế nào để tôi truy cập myMethod? - tom91136
Một cái gì đó như thế này sẽ làm việc. - ababzy
Nó không hoạt động, ví dụ myTask mTask = new myTask (); mTask.execute (); sẽ không trả về myHandledValueType. - Cheung
Định dạng kém, nhưng về cơ bản AsyncTask gọi phương thức hoạt động: myMethod với myValue (được cho là biến lớp được đặt trong doInBackground). Trong myMethod bạn xử lý kết quả của AsyncTask (không có lý do nào cho một giá trị trả về ở đây, chỉ cần thực hiện công việc trong phương thức này cho kết quả). Việc triển khai tốt hơn là mở rộng AsyncTask <Void, Void, Value> và có giá trị trả về doInBackground và có OnPostExecute lấy giá trị và chuyển nó vào myMethod - điều này sẽ tránh được bất kỳ biến lớp lộn xộn nào và cách AsyncTask được thiết kế để hoạt động. - jt-gilkeson
Tôi đã sử dụng asynctask với một giao diện. Giao diện được kích hoạt khi asynctask được hoàn thành (và thành công trong trường hợp của tôi, thành công trong ý nghĩa tải lên thành công). Trong hàm thành công của giao diện, tôi đã gọi phương thức từ asynctask và tôi nhận được giá trị - SKT


Đó là gì onPostExecute() là cho. Nó chạy trên chuỗi giao diện người dùng và bạn có thể phân phối kết quả từ đó đến màn hình (hoặc bất kỳ nơi nào khác bạn cần). Nó sẽ không được gọi cho đến khi kết quả cuối cùng có sẵn. Nếu bạn muốn cung cấp kết quả trung gian, hãy xem onProgressUpdate()


38
2018-02-26 23:22



vâng tôi biết doInBackground () trả về dữ liệu và đặt nó ở đó, nhưng làm cách nào để chuyển dữ liệu sang hoạt động chính của tôi dưới dạng biến? - tom91136
@ Tom91136 - Chỉ ghi đè onPostExecute() để lưu trữ kết quả theo một biến mà bạn chọn. Lưu ý rằng mã ban đầu của bạn không có ý nghĩa bởi vì phương pháp (giả thuyết) myTask.getValue()sẽ được gọi là trước một kết quả đã có sẵn. Bạn cũng có thể gọi AsyncTask get() phương pháp để có được kết quả, nhưng bạn không nên làm điều này từ chuỗi giao diện người dùng cho đến khi bạn biết chắc chắn rằng kết quả có sẵn. Nếu không, nó sẽ chặn luồng UI, đánh bại mục đích sử dụng AsyncTask ngay từ đầu. - Ted Hopp
@TedHopp bạn nói để lưu trữ kết quả trong một biến của sự lựa chọn của bạn trong onPostExecute() nhưng làm cách nào bạn nhận được biến BACK đó cho hoạt động của bạn? Ví dụ: nếu bạn muốn công việc của mình kết nối với internet và tải xuống một số thông tin và sau đó bạn muốn làm điều gì đó với thông tin đó ... Bạn làm cách nào .execute() các AsyncTask và sau đó làm điều gì đó với thông tin đó nếu dòng mã tiếp theo chạy trước AsyncTask hoan thanh? - Jake Wilson
@ Jakobud - Bạn không thể làm điều đó. Bạn cần di chuyển "dòng mã tiếp theo" ở một nơi khác (ví dụ: onPostExecute()). Tôi sử dụng sự tương tự này: bạn không viết mã chờ đầu vào của người dùng (ví dụ: nhấn nút); thay vào đó, bạn viết trình xử lý sự kiện phản ứng khi người dùng cung cấp một số đầu vào. Hãy nghĩ về onPostExecute() như một trình xử lý sự kiện khi có kết quả của AsyncTask. Đó là nơi bạn đặt mã (hoặc gọi các phương thức) mà sẽ không hoạt động trừ khi kết quả là, thực sự, có sẵn. - Ted Hopp
Nên AsyncTask không nên thực sự được coi là một hàm tiện ích mà chỉ đơn giản là lấy và trả về một số thông tin nhưng thay vì một cái gì đó lớn hơn nhiều mà lấy thông tin và cũng thao tác giao diện người dùng (hoặc bất cứ điều gì) sau khi lấy thông tin đó? - Jake Wilson


Cách dễ nhất là chuyển đối tượng gọi vào tác vụ không đồng bộ (khi xây dựng nó nếu bạn thích):

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

    private MyImagesPagerFragment mimagesPagerFragment;
    private ArrayList<ImageData> mImages = new ArrayList<ImageData>();

    public AsyncGetUserImagesTask(MyImagesPagerFragment imagesPagerFragment) {
        this.mimagesPagerFragment = imagesPagerFragment;
    }

    @Override
    public Void doInBackground(Void... records) {
        // do work here
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        mimagesPagerFragment.updateAdapter(mImages);
    }
}

Và trong lớp gọi (hoạt động hoặc đoạn của bạn) thực hiện nhiệm vụ:

public class MyImagesPagerFragment extends Fragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        AsyncGetUserImagesTask mGetImagesTask = new AsyncGetUserImagesTask(this);
        mGetImagesTask.execute();
    }

Và sau đó onPostExecuteMethod sẽ gọi bất kỳ phương thức nào trên lớp khởi tạo của bạn mà bạn thích, ví dụ:

    public void updateAdapter(List<ImageData> images) {
        mImageAdapter.setImages(images);
        mImageAdapter.notifyDataSetChanged();
    }
}

20
2018-04-02 11:07



Cảm ơn bạn! Cho đến nay, đây là giải pháp tốt nhất. - lomza
Giải pháp tuyệt vời! - PeteH
đây là tiêm phụ thuộc cơ bản - Kaushik Gopal
Giải pháp này hoạt động. Trừ khi điều này sẽ được tái sử dụng bởi các mảnh khác, nó sẽ đơn giản hơn để chỉ thực hiện nhiệm vụ không đồng bộ một lớp bên trong riêng (hoặc ẩn danh) và không truyền xung quanh đoạn. Ngoài ra, thay vì sử dụng Void cho kết quả, bạn có thể chỉ định mảng hình ảnh. doInBackground sẽ trả về mảng hình ảnh, và trên bài thực thi sẽ đưa nó vào như một tham số, điều này sẽ loại bỏ sự cần thiết của một biến lớp để truyền dữ liệu xung quanh. - jt-gilkeson
@ DIEGOF.G. Chính xác - do đó là "Trừ khi điều này sẽ được tái sử dụng" trình độ chuyên môn. Nếu bạn muốn có một giải pháp tái sử dụng - bạn có thể tạo một lớp phân đoạn tùy chỉnh với lớp asynctask bên trong được nhúng - sau đó mở rộng các đoạn cần chức năng này từ lớp đó. - jt-gilkeson


bạn có thể thử cái này: myvalue = new myTask().execute().get();  trừ là nó sẽ đóng băng quá trình cho đến khi asyncron sẽ không được hoàn thành;


9
2017-12-26 11:05



bất kỳ cách nào khác để tránh giao diện người dùng bị đóng băng này - CoronaPintu
Thực hiện các tác vụ nặng trong chuỗi giao diện người dùng bị khuyến khích và có thể dẫn đến ANR. Hơn nữa, thực hiện một hoạt động mạng trên thread chính gây ra NetworkOnMainThreadException và sụp đổ ngay lập tức bằng cách thiết kế. Kiểm tra bài viết hay đó: developer.android.com/training/articles/perf-anr#java - Nikita Bosik


Ví dụ mã: Hoạt động sử dụng AsyncTask để lấy giá trị trong một chuỗi nền, sau đó AsyncTask trả về kết quả quay lại Activity bằng cách gọi processValue:

public class MyClass extends Activity 
{
  private void getValue()
  {
      new MyTask().execute();
  }

  void processValue(Value myValue) 
  {
     //handle value 
     //Update GUI, show toast, etc..
  }

  private class MyTask extends AsyncTask<Void, Void, Value> 
  {
    @Override
    protected Value doInBackground(Void... params) 
    {
      //do stuff and return the value you want 
      return Value;
    }

    @Override
    protected void onPostExecute(Value result) 
    {
      // Call activity method with results
      processValue(result);
    }
  }
}

9
2017-11-16 00:16





Bạn cần sử dụng "giao thức" ủy quyền hoặc cung cấp dữ liệu cho AsynTask.

Đại biểu và nguồn dữ liệu 

Một đại biểu là một đối tượng hành động thay mặt, hoặc phối hợp với, một đối tượng khác khi đối tượng đó gặp một sự kiện trong một chương trình. (Apple định nghĩa)

các giao thức là các giao diện xác định một số phương thức để ủy nhiệm một số hành vi.


XÁC NHẬN: Sự kiện chính xác từ đối tượng trong chuỗi nền


AsynkTask:

public final class TaskWithDelegate extends AsyncTask<..., ..., ...> {
    //declare a delegate with type of protocol declared in this task
    private TaskDelegate delegate;

    //here is the task protocol to can delegate on other object
    public interface TaskDelegate {
        //define you method headers to override
        void onTaskEndWithResult(int success);
        void onTaskFinishGettingData(Data result);
    }

    @Override
    protected Integer doInBackground(Object... params) {
        //do something in background and get result
        if (delegate != null) {
            //return result to activity
            delegate.onTaskFinishGettingData(result);
        }   
    }

    @Override
    protected void onPostExecute(Integer result) {
        if (delegate != null) {
            //return success or fail to activity
            delegate.onTaskEndWithResult(result);
        }   
    }
}

Hoạt động:

public class DelegateActivity extends Activity implements TaskDelegate {
    void callTask () {
            TaskWithDelegate task = new TaskWithDelegate;
        //set the delegate of the task as this activity
        task.setDelegate(this);
    }

    //handle success or fail to show an alert...
    @Override
    void onTaskEndWithResult(int success) {

    }

    //handle data to show them in activity...
    @Override
    void onTaskFinishGettingData(Data result) {

    }
}

CHỈNH SỬA: nếu bạn gọi đại biểu trong doInBackground và đại biểu cố gắng chỉnh sửa một số chế độ xem, điều đó sẽ bị lỗi vì chế độ xem chỉ có thể được thao tác bởi chuỗi chính.


THÊM

NGUỒN DỮ LIỆU: Cung cấp dữ liệu cho đối tượng trong chuỗi nền


AsyncTask:

public final class TaskWithDataSource extends AsyncTask<..., ..., ...> {
    //declare a datasource with type of protocol declared in this task
    private TaskDataSource dataSource;
    private Object data;

    //here is the task protocol to can provide data from other object
    public interface TaskDataSource {
        //define you method headers to override
        int indexOfObject(Object object);
        Object objectAtIndex(int index);
    }

    @Override
    protected void onPreExecute(Integer result) {
        if (dataSource != null) {
            //ask for some data
            this.data = dataSource.objectAtIndex(0);
        }   
    }

    @Override
    protected Integer doInBackground(Object... params) {
        //do something in background and get result
        int index;
        if (dataSource != null) {
            //ask for something more
            index = dataSource.indexOfObject(this.data);
        }   
    }
}

Hoạt động:

public class DataSourceActivity extends Activity implements TaskDataSource {
    void callTask () {
            TaskWithDataSource task = new TaskWithDataSource;
        //set the datasource of the task as this activity
        task.setDataSource(this);
    }

    //send some data to the async task when it is needed...
    @Override
    Object objectAtIndex(int index) {
        return new Data(index);
    }

    //send more information...
    @Override
    int indexOfObject(Object object) {
        return new object.getIndex();
    }
}

8
2017-11-08 18:38





Sử dụng thông số chung

AsyncTask<Params, Progress, Result>
  • Params - kiểu dữ liệu đầu vào của công việc
  • Progress - cách thông báo cho thế giới về tiến bộ
  • Result - kiểu dữ liệu đầu ra của công việc

Suy nghĩ như

Result = task(Params)

Thí dụ

Tải YourObject theo URL chuỗi:

new AsyncTask<String, Void, YourObject>()
{
    @Override
    protected void onPreExecute()
    {
        /* Called before task execution; from UI thread, so you can access your widgets */

        // Optionally do some stuff like showing progress bar
    };

    @Override
    protected YourObject doInBackground(String... url)
    {
        /* Called from background thread, so you're NOT allowed to interact with UI */

        // Perform heavy task to get YourObject by string
        // Stay clear & functional, just convert input to output and return it
        YourObject result = callTheServer(url);
        return result;
    }

    @Override
    protected void onPostExecute(YourObject result)
    {
        /* Called once task is done; from UI thread, so you can access your widgets */

        // Process result as you like
    }
}.execute("http://www.example.com/");

3
2018-04-11 19:54





Để bạn có được kết quả từ AsyncTask nó cần phải làm điều đó sau super.onPostExcecute(result); Bởi vì điều này có nghĩa là nền và AsyncTask cũng đã hoàn thành. ví dụ.:

... into your async task

@Override
protected void onPostExecute(MyBeanResult result) {
    if (dialog.isShowing()) {
        dialog.dismiss();
    }
    if (mWakeLock.isHeld()) {
        mWakeLock.release();
    }
    super.onPostExecute(result);
    MyClassName.this.checkResponseForIntent(result);
}

và methodr checkResponseForIntent có thể bằng một cái gì đó như thế này:

private void checkResponseForIntent(MyBeanResult response) {
    if (response == null || response.fault != null) {
        noServiceAvailable();
        return;
    }
 ... or do what ever you want, even call an other async task...

Tôi đã gặp vấn đề này khi sử dụng .get() từ AsyncTask và ProgressBar không hoạt động với get(), trên thực tế, nó chỉ hoạt động sau khi hoàn thành doInBackground.

Tôi hy vọng rằng nó sẽ giúp bạn.


2
2017-07-05 06:43



thats true, các đối thoại tiến bộ chỉ wont làm việc với get () phương pháp - antroid


Chuyển lớp MainActivity sang Async, Vì vậy, bạn sẽ truy cập các hàm MainActivity trong lớp bên trong, Cái này làm việc tốt cho tôi:

public class MainActivity extends ActionBarActivity {

   void callAsync()
   {
      Async as = new Async(this,12,"Test");
      as.execute();
   }

   public void ReturnThreadResult(YourObject result)
   {
     // TO DO:
     // print(result.toString());

   }
}


public class Async extends AsyncTask<String, String, Boolean> {
    MainActivity parent;
    int param1;
    String param2;

    public Async(MainActivity parent,int param1,String param2){
       this.parent = parent;
       this.param1 = param1;
       this.param2 = param2;
    }

    @Override
    protected void onPreExecute(){};

    @Override
    protected YourObject doInBackground(String... url)
    {
        return result;
    }

    @Override
    protected void onPostExecute(YourObject result)
    {
       // call an external function as a result 
       parent.ReturnThreadResult(result);
    }
  }  

1
2018-06-18 21:51