从Android中的AsyncTask返回一个值

tom*_*136 115 java android asynchronous return android-asynctask

一个简单的问题:是否可以返回值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?
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在我的Activity/ Fragment:

// The task is started from activity
myTask.execute()
// something like this?
myvalue = myTask.getvalue() 
Run Code Online (Sandbox Code Playgroud)

编辑:这是很久以前我不熟悉Java的问题,现在我对它更好了,我会做一个简短的总结:

异步任务的重点是任务是asynchronous,这意味着在您调用execute()任务之后,任务开始在自己的线程上运行.从asynctask返回一个值是没有意义的,因为原始调用线程已经继续做其他事情(因此任务是异步的).

想想时间:在某个时间点,您启动了一个与主线程并行运行的任务.当并行运行任务完成时,主线程上也经过了时间.并行任务无法及时返回以将值返回给主线程.

我是从C来的,所以我对此并不了解.但似乎很多人都有同样的问题,所以我想我会稍微澄清一下.

Ted*_*opp 41

onPostExecute()是为了什么.它在UI线程上运行,您可以将结果从那里传送到屏幕(或您需要的任何其他地方).在最终结果可用之前不会调用它.如果您想提供中间结果,请查看onProgressUpdate()

  • 是的,我知道doInBackground()返回数据并将其放在那里,但我如何以变量形式将数据传输到我的主要活动? (16认同)
  • @TedHopp你说要在`onPostExecute()`中将结果存储在你选择的变量中,但是如何将变量返回到你的活动?例如,如果您希望您的任务连接到互联网并下载一些信息,然后您想要对该信息执行某些操作...您如何`.execute()``AsyncTask`然后对该信息执行某些操作如果下一行代码在`AsyncTask`完成之前运行? (9认同)
  • @ Tom91136 - 只需覆盖`onPostExecute()`将结果存储在您选择的变量中.请注意,您的原始代码没有意义,因为(假设的)方法`myTask.getValue()`将被调用_before_结果可用.您也可以调用AsyncTask的`get()`方法来获取结果,但是在确定结果可用之前,不应该从UI线程执行此操作.否则,它将阻止UI线程,首先打败使用AsyncTask的目的. (4认同)
  • @Jakobud - 你做不到.你需要在其他地方移动"下一行代码"(例如,`onPostExecute()`).我用这个比喻:你不编写等待用户输入的代码(例如,按下按钮); 相反,您编写的事件处理程序会在用户提供某些输入时作出反应.将`onPostExecute()`视为AsyncTask结果可用时的事件处理程序.这就是你放置代码(或调用方法)的地方,除非结果确实可用,否则这些代码将无效. (3认同)
  • 所以`AsyncTask`实际上不应该被认为是一个简单地获取并返回一些信息的实用函数,而是一个更大的东西,它可以获取信息并在获取信息后操纵UI(或其他)? (3认同)

aba*_*bzy 33

为什么不调用一个处理值的方法?

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 以及如何访问myMethod? (51认同)
  • 格式化很差,但AsyncTask基本上调用了activity方法:myMethod with myValue(据说是一个在doInBackground中设置的类变量).在myMethod中,您处理AsyncTask的结果(这里没有理由返回值,只需在此方法中为结果执行此操作).更好的实现是扩展AsyncTask <Void,Void,Value>并让doInBackground返回Value并让OnPostExecute接受Value并将其传递给myMethod - 这将避免任何混乱的类变量,并且是AsyncTask的设计工作方式. (7认同)
  • 我在界面中使用了asynctask.当asynctask完成时接口被触发(在我的情况下成功,在意义上传成功中成功).在接口的成功函数中,我从asynctask调用了方法,得到了值 (2认同)

She*_*ran 24

最简单的方法是将调用对象传递给异步任务(如果您愿意,可以在构建它时):

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

并且在调用类(您的活动或片段)中执行任务:

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

然后onPostExecuteMethod将调用您喜欢的原始类上的任何方法,例如:

    public void updateAdapter(List<ImageData> images) {
        mImageAdapter.setImages(images);
        mImageAdapter.notifyDataSetChanged();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案有效.除非这可以被其他片段重用,否则将异步任务设置为私有内部类(或匿名)并且不传递片段会更简单.也可以指定图像数组,而不是使用Void作为结果.doInBackground将返回图像数组,并且在post执行时将把它作为参数,这将消除类变量传递数据的需要. (3认同)
  • 这实际上是依赖注入 (2认同)

jt-*_*son 13

代码示例:Activity使用AsyncTask在后台线程中获取值,然后AsyncTask通过调用processValue将结果返回给Activity:

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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


小智 11

你可以尝试这个:myvalue = new myTask().execute().get(); 减去它会冻结进程,直到asyncron不会完成;

  • 任何其他方式来避免这种冻结的UI (6认同)

Ign*_*ers 9

您需要使用"协议"来委派或提供数据AsynTask.

代表和数据来源

委托是一个对象,当该对象遇到程序中的事件时,该对象代表另一个对象或与另一个对象协调.(Apple定义)

协议是定义一些委托某些行为的方法的接口.


DELEGATE :从后台线程中的对象中截取事件


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);
        }   
    }
}
Run Code Online (Sandbox Code Playgroud)

活动:

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) {

    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果您在doInBackground中调用委托,并且委托尝试编辑某个视图,那将崩溃,因为视图只能由主线程操纵.


额外

DATASOURCE:在后台线程中为对象提供数据


的AsyncTask:

// this refers to Activity
this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
    // Here you can edit views when task notify some changes from background thread
        textView.setText(someValue);
    }
});
Run Code Online (Sandbox Code Playgroud)

活动:

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);
        }   
    }
}
Run Code Online (Sandbox Code Playgroud)