Как получить результат OnPostExecute() для основного действия, потому что AsyncTask - это отдельный класс?
У меня есть два класса. Моя основная деятельность и та, которая расширяет 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);
}
}
Ответы
Ответ 1
Легко:
-
Создайте класс interface
, где String output
является необязательным или может быть любыми переменными, которые вы хотите вернуть.
public interface AsyncResponse {
void processFinish(String output);
}
-
Перейдите в класс AsyncTask
и объявите интерфейс AsyncResponse
как поле:
public class MyAsyncTask extends AsyncTask<Void, Void, String> {
public AsyncResponse delegate = null;
@Override
protected void onPostExecute(String result) {
delegate.processFinish(result);
}
}
-
В своей основной деятельности вам необходимо 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.
}
}
ОБНОВИТЬ
Я не знал, что это такой фаворит для многих из вас. Итак, вот простой и удобный способ использования 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();
}
Или, снова реализуя интерфейс для Activity
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.
}
}
Поскольку вы видите два решения выше, первое и третье, необходимо создать метод processFinish
, другой - метод внутри параметра вызывающего. Третий более аккуратный, потому что нет вложенного анонимного класса. Надеюсь это поможет
Совет. Измените String output
String response
String result
для разных типов соответствия, чтобы получить разные объекты.
Ответ 2
Есть несколько вариантов:
-
Настройте класс AsyncTask
в классе Activity
. Предполагая, что вы не используете одну и ту же задачу в нескольких действиях, это самый простой способ. Весь ваш код остается прежним, вы просто перемещаете существующий класс задач как вложенный класс внутри вашего класса активности.
public class MyActivity extends Activity {
// existing Activity code
...
private class MyAsyncTask extends AsyncTask<String, Void, String> {
// existing AsyncTask code
...
}
}
-
Создайте собственный конструктор для AsyncTask
, который ссылается на ваш Activity
. Вы должны создать экземпляр задачи с чем-то вроде new 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
...
}
Ответ 3
Я чувствовал, что подход ниже очень прост.
Я объявил интерфейс для обратного вызова
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.." });
}
});
}
}
Спасибо
Ответ 4
Вы можете попробовать этот код в своем основном классе.
Это сработало для меня, но я реализовал методы другим способом.
try {
String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
}
catch (ExecutionException | InterruptedException ei) {
ei.printStackTrace();
}
Ответ 5
Вы можете сделать это в нескольких строках, просто переопределите onPostExecute при вызове AsyncTask. Вот вам пример:
new AasyncTask()
{
@Override public void onPostExecute(String result)
{
// do whatever you want with result
}
}.execute(a.targetServer);
Надеюсь, это помогло вам, счастливая трединга:)
Ответ 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();
} `
Ответ 7
Этот ответ может быть поздно, но я хотел бы упомянуть несколько вещей, когда ваша Activity
зависит от AsyncTask
. Это поможет вам предотвратить сбои и управление памятью. Как уже упоминалось выше, ответы идут с interface
, мы также называем их обратными вызовами. Они будут работать в качестве информатора, но никогда не будут посылать сильные ссылки об Activity
или interface
всегда будет использовать слабые ссылки в этих случаях.
Пожалуйста, обратитесь к скриншоту ниже, чтобы узнать, как это может вызвать проблемы.
![enter image description here]()
Как вы можете видеть, если мы запустили AsyncTask
с сильной ссылкой, то нет никакой гарантии, что наша Activity
/Fragment
будет работать до тех пор, пока мы не получим данные, поэтому в этих случаях было бы лучше использовать WeakReference
что также поможет в управлении памятью, так как мы никогда не будем иметь строгую ссылку на нашу Activity
тогда она будет иметь право на сборку мусора после ее искажения.
Ниже приведен фрагмент кода, чтобы узнать, как использовать классную WeakReference.
MyTaskInformer.java
Интерфейс, который будет работать как информер.
public interface MyTaskInformer {
void onTaskDone(String output);
}
MySmallAsyncTask.java
AsyncTask для выполнения длительной задачи, которая будет использовать 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
Этот класс используется для запуска interface
реализации AsyncTask
в этом классе и 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);
}
}
Ответ 8
Почему люди делают это так сложно.
Этого должно быть достаточно.
Не выполняйте onPostExecute в задаче async, скорее реализуйте ее в Activity:
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");
}
}
Ответ 9
Вы можете вызвать get()
метод AsyncTask
(или перегруженный get(long, TimeUnit)
). Этот метод будет блокироваться до тех пор, пока AsyncTask
не завершит свою работу, после чего он вернет вам Result
.
Было бы разумно выполнять другую работу между созданием/запуском вашей задачи async и вызовом метода get
, иначе вы не будете эффективно использовать задачу async.
Ответ 10
Привет, вы можете сделать что-то вроде этого:
-
Создайте класс, который реализует 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");
}
}
}
-
Добавить в основную деятельность
// 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();
...
}
Ответ 11
Вы можете написать свой собственный слушатель. Он также отвечает 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...
}
Ответ 12
Создайте статический член в классе Activity. Затем назначьте значение во время onPostExecute
Например, если результатом вашей AsyncTask является String, создайте общедоступную статическую строку в вашей Activity
public static String dataFromAsyncTask;
Затем в onPostExecute
AsyncTask просто сделайте статический вызов вашему основному классу и установите значение.
MainActivity.dataFromAsyncTask = "result blah";
Ответ 13
Я заставляю его работать, используя потоки и обработчик/сообщение.
Шаги, как следует:
Объявление диалога прогресса
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();
}
Ответ 14
Не нужно использовать интерфейсы, потому что вы не можете получить его возвращаемые значения вне и назначить его любой переменной, например. Все, что вам нужно - это метод get ()
, который ждет, пока doInBackground ()
завершит свою работу, выслушайте результат onPostExecute ()
и верните его:
String result = new myAsyncTask ().execute ().get ();
Теперь вы можете использовать переменную result
, где хотите. Этот тип данных данных аналогичен типу onPostExecute ()
. Но вы не можете использовать его в AsyncTask в другой AsuncTask, потому что вы получите инфинитный цикл. Но я не могу придумать ситуации, когда вам нужно использовать AcuncTask в другом AsuncTask:/
Ответ 15
Вам необходимо использовать "протоколы" для делегирования или предоставления данных в AsynTask
.
Делегаты и источники данных
Делегат - это объект, который действует от имени или в координации с другим объектом, когда этот объект встречает событие в программе. (Определение Apple)
протоколы - это интерфейсы, которые определяют некоторые методы делегирования некоторых действий.
Вот полный пример !!!
Ответ 16
попробуй это:
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");
}
Ответ 17
Решение HelmiB было отличным, но что, если мне придется использовать в одном действии два разных AsyncTask? Как я могу отличить один звонок от другого?