Jak uzyskać wynik OnPostExecute () do głównej aktywności, ponieważ AsyncTask jest osobną klasą?

361

Mam te dwie klasy. Mój główny aktywny i jeden, który rozszerza AsyncTaskTeraz moim głównym Aktywny Muszę dostać wynik od OnPostExecute()w AsyncTask. Jak mogę przekazać lub uzyskać wynik mojej głównej działalności?

Oto przykładowe kody.

Moja główna aktywność.

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); 
    }

}

To jest klasa 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);

}       

}   
Stella
źródło
Możesz utworzyć interfejs, jak wyjaśniono HelmiB, lub utworzyć lokalny odbiornik transmisji. Przykład implementacji odbiornika transmisji można zobaczyć tutaj wiki.workassis.com/android-local-broadcast-receiver
Bikesh M
Dlaczego nie użyć wzorca Observer?
JAAAY,

Odpowiedzi:

750

Łatwy:

  1. Utwórz interfaceklasę, gdzie String outputjest opcjonalna lub może być dowolną zmienną, którą chcesz zwrócić.

    public interface AsyncResponse {
        void processFinish(String output);
    }
    
  2. Idź do swojej AsyncTaskklasy i zadeklaruj interfejs AsyncResponsejako pole:

    public class MyAsyncTask extends AsyncTask<Void, Void, String> {
      public AsyncResponse delegate = null;
    
        @Override
        protected void onPostExecute(String result) {
          delegate.processFinish(result);
        }
     }
    
  3. W swojej głównej działalności musisz się implementspołączyć 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.
       }
     }
    

AKTUALIZACJA

Nie wiedziałem, że jest to ulubieniec wielu z was. Oto prosty i wygodny sposób użycia interface.

nadal używam tego samego interface. Do twojej wiadomości, możesz połączyć to w AsyncTaskklasę.

w AsyncTaskklasie:

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);
    }
}

zrób to w swojej Activityklasie

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();

 }

Lub ponownie implementując interfejs działania

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.
    }
}

Jak widać 2 rozwiązania powyżej, pierwsze i trzecie, musi utworzyć metodę processFinish, drugie, metoda znajduje się w parametrze dzwoniącego. Trzeci jest bardziej schludny, ponieważ nie ma zagnieżdżonej anonimowej klasy. Mam nadzieję że to pomoże

Wskazówka : Zmiana String output, String responsei String resultdo różnych typów dopasowania w celu uzyskania różnych obiektów.

HelmiB
źródło
20
Zupełnie to wszystko napisałem, a potem zobaczyłem twoją odpowiedź :) Oto podobne myślenie! +1. Również w ten sposób wiele rzeczy może słuchać wyników AsyncTask!
Roloc,
8
Otrzymuję wyjątek nullpointer, ponieważ dla delegata ustawiono wartość null, proszę go
wyjaśnić
2
Uwaga dla programistów .net, aby to osiągnąć, można użyć AutoResetEvents. Istnieje także implementacja Java dla autoresetevents, ale jest to o wiele czystsze. Nawiasem mówiąc, czy wątek ProcessFinish jest bezpieczny?
Syler,
13
dla wszystkich, którzy otrzymują wskaźnik zerowy, przekaż interfejs do konstruktora klasy asyncTask, a następnie przypisz go do zmiennej, a następnie wywołaj processfinish () na tej zmiennej. W celach informacyjnych patrz zaakceptowany asnwer. stackoverflow.com/questions/9963691/…
Sunny,
2
@Sunny masz rację ... musimy też zainicjować obiekt asynchroniczny dla async.delegate = this; do pracy ..
Ninja_Coder
24

Istnieje kilka opcji:

  • Zagnieżdż AsyncTaskklasę w swojej Activityklasie. Zakładając, że nie używasz tego samego zadania do wielu działań, jest to najłatwiejszy sposób. Cały kod pozostaje taki sam, wystarczy przenieść istniejącą klasę zadania, aby była klasą zagnieżdżoną w klasie działania.

    public class MyActivity extends Activity {
        // existing Activity code
        ...
    
        private class MyAsyncTask extends AsyncTask<String, Void, String> {
            // existing AsyncTask code
            ...
        }
    }
  • Utwórz własny konstruktor, AsyncTaskktóry odwołuje się do Twojego Activity. Utworzyłbyś zadanie z czymś takim 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
        ...
    }
miętówka
źródło
W drugiej opcji: po co przechodzić przez ból konstruktora i pola, jeśli klasa nie jest static? Po prostu użyj dowolnego fieldOrMethodz MyActivitylub MyActivity.this.fieldOrMethodjeśli jest w cieniu.
TWiStErRob,
@TWiStErRob drugi przyjmuje MyAsyncTasksię nie wewnętrzną klasy.
quietmint
1
Och, przepraszam, private/ protecteddla klas najwyższego poziomu jest niedozwolony, dlatego pomyślałem, że to musi być staticklasa inna niż wewnętrzna.
TWiStErRob
2
Tylko uważaj, aby klasa wewnętrzna AsyncTask mogła być źródłem wycieków pamięci, jak wyjaśniono tutaj garena.github.io/blog/2014/09/10/android-memory-leaks
Mark Pazon
2
Trzymanie odniesienia do działania jest także wyciekiem pamięci. Metoda oddzwaniania jest znacznie lepsza
OneCricketeer
19

Czułem, że poniższe podejście jest bardzo łatwe.

Zadeklarowałem interfejs do oddzwaniania

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

Następnie utworzono asynchroniczne zadanie odpowiadające na wszystkie typy równoległych żądań

 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);
    }

}

Następnie wywołano zadanie asynchroniczne po kliknięciu przycisku w klasie aktywności.

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.." });


            }
        });

    }



}

Dzięki

Arszad
źródło
17

Możesz wypróbować ten kod w swojej klasie głównej. To działało dla mnie, ale zaimplementowałem metody w inny sposób

try {
    String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
} 
catch (ExecutionException | InterruptedException ei) {
    ei.printStackTrace();
}
Nicu P.
źródło
2
Czy możesz wyjaśnić, dlaczego pomogłoby to OP w rozwiązaniu problemu?
John Odom
3
To mi pomogło. Próbowałem w inny sposób, jak odpowiedź @HelmiB, ale nie otrzymuję żadnych wyników
Nicu P
Ok przepraszam za moją odpowiedź. Musi wywołać klasę AsyncTask, a następnie umieścić parametr w tym wywołaniu. AsyncTask jest zdefiniowany przez 3 ogólne typy: 1 parametry (domena serwera lub inny parametr) 2 postęp (może być nieważny), 3 wynik. Wszystkie te typy mogą być: JSONObject lub ciągi znaków lub dowolne typy danych. Kiedy masz klasę AsyncTask, powinieneś określić, gdzie wysłać dane. np .: asyncTask.execute („ sampletargeturl.com”). get () ;
Nicu P
Podczas korzystania z tej metody otrzymałem ostrzeżenie dla Logcat: „I / Choreographer ﹕ Pominął 50 ramek! Aplikacja może wykonywać zbyt wiele pracy w swoim głównym wątku.” Jak sobie z tym poradzić? Czy interfejs użytkownika zawiesza się podczas oczekiwania na zwrot z AsyncTask?
Huy Do
@NicuP, może zapomniałeś zadzwonić execute(), zobacz moją odpowiedź, dodałem tam komentarz. możesz sprawdzić moją zaktualizowaną odpowiedź. mam nadzieję że to pomoże.
HelmiB
16

Ta odpowiedź może się spóźnić, ale chciałbym wspomnieć o kilku rzeczach, kiedy jesteś Activityna utrzymaniu AsyncTask. Pomoże to w zapobieganiu awariom i zarządzaniu pamięcią. Jak już wspomniano w powyższych odpowiedziach iść z interface, możemy również powiedzieć im wywołania zwrotne. Będą działać jako informator, ale nigdy nie wysyłają silnych referencji Activitylub interfacezawsze używają słabych referencji w takich przypadkach.

Sprawdź poniższy zrzut ekranu, aby dowiedzieć się, w jaki sposób może to powodować problemy.

wprowadź opis zdjęcia tutaj

Jak widać, jeśli zaczęliśmy AsyncTaskod silnego odniesienia, nie ma gwarancji, że nasze Activity/ Fragmentbędą żyły, dopóki nie otrzymamy danych, więc lepiej byłoby użyć WeakReferencew takich przypadkach, a to również pomoże w zarządzaniu pamięcią, ponieważ nigdy nie będziemy posiadać zdecydowana referencja naszego Activitywówczas będzie kwalifikować się do zbierania śmieci po ich zniekształceniu.

Sprawdź poniższy fragment kodu, aby dowiedzieć się, jak używać niesamowitego WeakReference -

MyTaskInformer.java Interfejs, który będzie działał jako informator.

public interface MyTaskInformer {

    void onTaskDone(String output);

}

MySmallAsyncTask.javaAsyncTask wykonuje długo działające zadanie, które wykorzysta 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.javaTa klasa służy do uruchomienia mojego AsyncTaskimplementacji interfacena tej klasie i na overridetej obowiązkowej metodzie.

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);
    }
}
Rahul
źródło
2
To jest świetne! ważny punkt, którego nie można zauważyć.
HasH
6

w swoim 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();

} `

użytkownik3691697
źródło
6

Możesz to zrobić w kilku wierszach, po prostu zastąp parametr onPostExecute podczas wywoływania funkcji AsyncTask. Oto przykład dla ciebie:

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

Mam nadzieję, że ci pomogło, wesołego kodowania :)

Ayaz Alifov
źródło
To nie działa dla mnie. Po prostu nie wchodzi w onPostExecutemetodę.
Francisco Romero,
4

Dlaczego ludzie utrudniają to.

To powinno wystarczyć.

Nie implementuj metody onPostExecute w zadaniu asynchronicznym, a raczej implementuj ją w działaniu:

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");

}


}
bugdayci
źródło
To działa dla mnie. Jest to prosty i najłatwiejszy do zrozumienia. Myślę, że wykorzystuje to, do czego została zaprojektowana Java. Dzięki. PS: Czy konieczne jest dodanie @Override?
Old Geezer
1
Nie. @Override to tylko adnotacja. Mówisz kompilatorowi Java, że ​​zamierzasz zastąpić metodę i uzyskać informację, jeśli tego nie zrobisz.
bugdayci
4

Możesz wywołać get()metodę AsyncTask(lub przeciążoną get(long, TimeUnit)). Ta metoda będzie blokować do AsyncTaskczasu zakończenia pracy, w którym to momencie zwróci Ci Result.

Rozsądnie byłoby wykonać inną pracę między utworzeniem / uruchomieniem zadania asynchronicznego a wywołaniem getmetody, w przeciwnym razie zadanie asynchroniczne nie będzie wykorzystywane bardzo skutecznie.

nicholas.hauschild
źródło
1
Odebrana vecause get () zablokuje główny wątek. Nie ma powodu, aby używać AsyncTask, jeśli zostanie zablokowany
GabrielBB,
3

Możesz napisać własnego słuchacza. Jest taki sam jak odpowiedź HelmiB , ale wygląda bardziej naturalnie:

Utwórz interfejs odbiornika:

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

Następnie napisz swoje zadanie asynchroniczne:

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);
            }
        }
    }
}

Na koniec zaimplementuj nasłuchiwanie w działaniu:

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
        }        
    }

I tak możesz wywołać 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...
}
Kuvalya
źródło
2

Cześć, możesz zrobić coś takiego:

  1. Utwórz klasę, która implementuje 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. Dodaj główną aktywność

    // 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();
       ...
     }
Oleg Karbushev
źródło
1

Utwórz statycznego członka w swojej klasie aktywności. Następnie przypisz wartość podczasonPostExecute

Na przykład, jeśli wynikiem AsyncTask jest ciąg znaków, utwórz publiczny ciąg statyczny w swoim działaniu

public static String dataFromAsyncTask;

Następnie w onPostExecuteAsyncTask po prostu wywołaj statyczne wywołanie swojej klasy głównej i ustaw wartość.

MainActivity.dataFromAsyncTask = "result blah";

mrres1
źródło
1
jakie są możliwości wycieku pamięci w tym scenariuszu?
antroid
0

Sprawiam, że działa za pomocą wątków i handlera / wiadomości. Kroki, jak następuje: Zadeklaruj okno dialogowe postępu

ProgressDialog loadingdialog;

Utwórz funkcję, aby zamknąć okno dialogowe po zakończeniu operacji.

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

    }
    };

Zakoduj dane swojego wykonania:

 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();
}
PROMIEŃ
źródło
0

Musisz użyć „protokołów”, aby przekazać lub przekazać dane do AsynTask.

Delegaci i źródła danych

Delegat to obiekt, który działa w imieniu lub w koordynacji z innym obiektem, gdy ten obiekt napotka zdarzenie w programie. ( Definicja Apple )

protokoły to interfejsy, które definiują niektóre metody delegowania niektórych zachowań.

Oto kompletny przykład !!!

IgniteCoders
źródło
0

Spróbuj tego:

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();

    }
}

I przykład użycia:

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");

    }
amiron
źródło
0

Prawdopodobnie trochę przesadzam, ale zapewniłem wywołania zwrotne zarówno dla kodu wykonania, jak i wyników. oczywiście dla bezpieczeństwa wątków chcesz uważać na to, do czego masz dostęp w wywołaniu zwrotnym wykonania.

Implementacja 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);
    }
}

Oddzwonienie:

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

I wreszcie wykonanie zadania asynchronicznego:

 new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);
Zgrabnie
źródło
0

Mam nadzieję, że przez to przeszliście , jeśli nie, proszę przeczytać.

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

W zależności od charakteru danych wynikowych należy wybrać najlepszą możliwą opcję, o której można pomyśleć.

To świetny wybór do używania interfejsu

niektóre inne opcje to ...

  • Jeśli klasa AsyncTask jest zdefiniowana w tej samej klasie, w której chcesz użyć wyniku Użyj statycznej zmiennej globalnej lub get () , użyj jej z klasy zewnętrznej (w razie potrzeby zmienna lotna ). ale powinien być świadomy postępu AsyncTask lub powinien przynajmniej upewnić się, że zadanie zostało zakończone, a wynik jest dostępny za pośrednictwem metody zmiennej globalnej / get (). możesz użyć odpytywania, onProgressUpdate (Progress ...) , synchronizacji lub interfejsów (które kiedykolwiek najlepiej Ci odpowiadają)

  • Jeśli wynik jest zgodny z wpisem sharedPreference lub zapisanie go jako pliku w pamięci jest w porządku, możesz zapisać go nawet z samego zadania w tle i użyć metody onPostExecute () ,
    aby otrzymywać powiadomienia, gdy wynik jest dostępny w pamięć.

  • Jeśli łańcuch jest wystarczająco mały i ma być używany przy rozpoczęciu działania. możliwe jest użycie intencji ( putExtra () ) w ramach onPostExecute () , ale pamiętaj, że konteksty statyczne nie są tak bezpieczne, aby sobie z nimi poradzić.

  • Jeśli to możliwe, można wywołać metodę statyczną z metody onPostExecute (), przy czym wynikiem jest parametr

Szorstki
źródło