Возвращает значение из AsyncTask в Android [дубликат]
этот вопрос уже есть ответ здесь:
один простой вопрос: Можно ли вернуть значение в 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?
}
}
а потом в моей Activity
/Fragment
:
// The task is started from activity
myTask.execute()
// something like this?
myvalue = myTask.getvalue()
изменить: Это было задано давно, где я не был знаком с Java, теперь, когда я лучше с ним, я сделаю краткое резюме:
точка асинхронной задачи заключается в том, что задача asynchronous
, это означает, что после вызова execute()
в задаче задача запускается в собственном потоке. возврат значения из asynctask будет бессмысленным, потому что исходный вызывающий поток уже продолжал делать другие вещи (таким образом, задача асинхронная).
думать о времени: В какой-то момент Вы запустили задачу, которая будет выполняться параллельно с основным потоком. Когда параллельно выполняемая задача завершена, время также истекло в основном потоке. Параллельная задача не может вернуться в прошлое, чтобы вернуть значение в основной поток.
Я шел от C, поэтому я мало знал об этом. Но, похоже, у многих людей один и тот же вопрос, поэтому я подумал, что немного проясню его.
9 ответов
почему бы не вызвать метод, который обрабатывает значение?
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;
}
}
что это onPostExecute()
для. Он работает в потоке пользовательского интерфейса, и вы можете доставить свой результат оттуда на экран (или в любом другом месте). Это не будет называться до окончательного результата. Если вы хотите получить промежуточные результаты, посмотрите на onProgressUpdate()
самый простой способ-передать вызывающий объект в асинхронную задачу (при ее создании, Если хотите):
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);
}
}
и в вызывающем классе (ваша активность или фрагмент) выполните задачу:
public class MyImagesPagerFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
AsyncGetUserImagesTask mGetImagesTask = new AsyncGetUserImagesTask(this);
mGetImagesTask.execute();
}
и тогда onPostExecuteMethod вызовет любой метод в вашем исходном классе, например:
public void updateAdapter(List<ImageData> images) {
mImageAdapter.setImages(images);
mImageAdapter.notifyDataSetChanged();
}
}
вы можете попробовать это: myvalue = new myTask().execute().get();
минус в том, что он заморозит процесс, пока asyncron не будет завершен;
пример кода: Activity использует AsyncTask для получения значения в фоновом потоке, затем AsyncTask возвращает результат обратно в Activity, вызывая 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);
}
}
}
вам нужно использовать "протоколы" делегировать или предоставлять информацию AsynTask
.
делегаты и источники данных
делегат-это объект, который действует от имени, или в координации с другим объектом, когда этот объект обнаруживает событие в программе. (определение Apple)
протоколы-это интерфейсы, которые определяют некоторые методы для делегирования некоторых поведения.
делегат: событий Capturate от объекта в фоновом потоке
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);
}
}
}
действие:
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) {
}
}
EDIT: если вы вызываете делегата в doInBackground, и делегат пытается отредактировать некоторое представление, это приведет к сбою, потому что представление может управляться только основным нитка.
дополнительно
источник: предоставить данные объекту в фоновом потоке
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);
}
}
}
действие:
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();
}
}
общие параметры
AsyncTask<Params, Progress, Result>
-
Params
- тип входных данных задачи -
Progress
- как информировать мир о прогрессе Result
- тип выходных данных задачи
думать
Result = task(Params)
пример
загрузить YourObject
по строке URL:
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/");
для вас получить результат от AsyncTask это нужно сделать после super.onPostExcecute(result)
;
Потому что это означает, что фон и AsyncTask также закончились.
например:
... 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);
}
и methodr checkResponseForIntent может быть чем-то вроде этого:
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...
у меня была эта проблема с использованием .get()
С AsyncTask и ProgressBar просто не работает с get()
на самом деле, это работает только один раз, что doInBackground заканчивает.
Я надеюсь, что это поможет вам.
передайте MainActivity в класс Async, чтобы получить доступ к функциям MainActivity во внутреннем классе, Это прекрасно работает для меня:
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);
}
}