Wie kann das Ergebnis von OnPostExecute () zur Hauptaktivität gebracht werden, da AsyncTask eine separate Klasse ist?

361

Ich habe diese zwei Klassen. Meine Hauptaktivität und die, die das erweitert AsyncTask. Jetzt muss ich in meiner Hauptaktivität das Ergebnis aus dem OnPostExecute()in der AsyncTask. Wie kann ich das Ergebnis an meine Hauptaktivität weitergeben?

Hier sind die Beispielcodes.

Meine Haupttätigkeit.

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

}

Dies ist die AsyncTask-Klasse

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
quelle
Sie können eine Schnittstelle wie HelmiB erklärt oder einen lokalen Rundfunkempfänger erstellen. Die Beispielimplementierung des Rundfunkempfängers finden Sie hier wiki.workassis.com/android-local-broadcast-receiver
Bikesh M
Warum nicht das Observer-Muster verwenden?
JAAAY

Antworten:

750

Einfach:

  1. Erstellen Sie eine interfaceKlasse, wo dies String outputoptional ist, oder können beliebige Variablen sein, die Sie zurückgeben möchten.

    public interface AsyncResponse {
        void processFinish(String output);
    }
  2. Gehen Sie zu Ihrer AsyncTaskKlasse und deklarieren Sie die Schnittstelle AsyncResponseals Feld:

    public class MyAsyncTask extends AsyncTask<Void, Void, String> {
      public AsyncResponse delegate = null;
    
        @Override
        protected void onPostExecute(String result) {
          delegate.processFinish(result);
        }
     }
  3. In Ihrer Hauptaktivität müssen Sie eine implementsSchnittstelle herstellen 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.
       }
     }

AKTUALISIEREN

Ich wusste nicht, dass dies für viele von Ihnen so ein Favorit ist. Hier ist die einfache und bequeme Art der Verwendung interface.

immer noch gleich interface. Zu Ihrer Information, Sie können dies in der AsyncTaskKlasse kombinieren .

in der AsyncTaskKlasse:

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

Mach das in deiner ActivityKlasse

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

 }

Oder implementieren Sie die Schnittstelle in der Aktivität erneut

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

Wie Sie oben sehen können, müssen zwei Lösungen, die erste und die dritte, eine Methode erstellen processFinish. Die andere, die Methode, befindet sich im Aufruferparameter. Die dritte ist ordentlicher, weil es keine verschachtelte anonyme Klasse gibt. Hoffe das hilft

Tipp : Ändern Sie String output, String responseund String resultzu verschiedenen übereinstimmenden Typen, um unterschiedliche Objekte zu erhalten.

HelmiB
quelle
20
Ich habe das alles total aufgeschrieben und dann deine Antwort gesehen :) Hier ist es, gleich zu denken! +1. Auch auf diese Weise können mehrere Dinge die Ergebnisse der AsyncTask abhören!
Roloc
8
Ich erhalte eine Nullzeiger-Ausnahme, da der Delegat auf Null gesetzt ist. Bitte klären Sie dies
Reyjohn,
2
Nur ein Hinweis für .net-Entwickler, man kann AutoResetEvents verwenden, um dies zu erreichen, und es gibt auch eine Java-Implementierung für Autoresetevents, aber dies ist viel sauberer. Ist ProcessFinish-Thread übrigens sicher?
Syler
13
Für alle, die einen Nullzeiger erhalten, übergeben Sie Ihre Schnittstelle an Ihren asyncTask-Klassenkonstruktor, weisen Sie sie dann einer Variablen zu und rufen Sie dann processfinish () für diese Variable auf. Referenz siehe akzeptierte Antwort. stackoverflow.com/questions/9963691/…
Sunny
2
@Sunny du hast recht ... außerdem müssen wir das asynchrone Objekt für async.delegate = this initialisieren; zu arbeiten ..
Ninja_Coder
24

Es gibt einige Optionen:

  • Verschachteln Sie die AsyncTaskKlasse in Ihrer ActivityKlasse. Angenommen, Sie verwenden nicht dieselbe Aufgabe in mehreren Aktivitäten, ist dies der einfachste Weg. Ihr gesamter Code bleibt gleich. Sie verschieben lediglich die vorhandene Aufgabenklasse in eine verschachtelte Klasse innerhalb der Klasse Ihrer Aktivität.

    public class MyActivity extends Activity {
        // existing Activity code
        ...
    
        private class MyAsyncTask extends AsyncTask<String, Void, String> {
            // existing AsyncTask code
            ...
        }
    }
  • Erstellen Sie einen benutzerdefinierten Konstruktor für Ihre AsyncTask, der auf Ihre verweist Activity. Sie würden die Aufgabe mit so etwas instanziieren 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
        ...
    }
quietmint
quelle
In der zweiten Option: Warum durch den Schmerz eines Konstruktors und eines Feldes gehen, wenn die Klasse nicht ist static? Verwenden Sie einfach eines fieldOrMethodvon MyActivityoder MyActivity.this.fieldOrMethodwenn es im Schatten liegt.
TWiStErRob
@TWiStErRob Die zweite Annahme MyAsyncTaskist keine innere Klasse.
quietmint
1
Oh, sorry, private/ protectedfür Top-Level-Klassen ist nicht erlaubt, daher dachte ich, dass es eine nicht- staticinnere Klasse sein muss.
TWiStErRob
2
Seien Sie nur vorsichtig, dass AsyncTask der inneren Klasse eine Quelle für Speicherlecks sein kann, wie hier erläutert. Garena.github.io/blog/2014/09/10/android-memory-leaks
Mark Pazon
2
Das Festhalten an einer Aktivitätsreferenz ist ebenfalls ein Speicherverlust. Der Rückruf-Ansatz ist weitaus besser als dieser
OneCricketeer
19

Ich fand den folgenden Ansatz sehr einfach.

Ich habe eine Schnittstelle für den Rückruf deklariert

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

Anschließend wurde eine asynchrone Aufgabe zum Beantworten aller Arten von parallelen Anforderungen erstellt

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

}

Rief dann die asynchrone Aufgabe auf, wenn auf eine Schaltfläche in der Aktivitätsklasse geklickt wurde.

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


            }
        });

    }



}

Vielen Dank

Arshad
quelle
17

Sie können diesen Code in Ihrer Hauptklasse ausprobieren. Das hat bei mir funktioniert, aber ich habe Methoden auf andere Weise implementiert

try {
    String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
} 
catch (ExecutionException | InterruptedException ei) {
    ei.printStackTrace();
}
Nicu P.
quelle
2
Können Sie bitte erklären, warum dies OP bei ihrem Problem helfen würde?
John Odom
3
Das hat mir geholfen. Ich habe es auf andere Weise versucht, wie die Antwort von @HelmiB, aber ich bekomme keine Ergebnisse
Nicu P
Ok, entschuldige meine Antwort. Sie muss die AsyncTask-Klasse aufrufen und dann einen Parameter für diesen Aufruf eingeben. AsyncTask wird durch 3 generische Typen definiert: 1 Parameter (Serverdomäne oder andere Parameter) 2 Fortschritt (kann ungültig sein), 3 Ergebnis. Alle diese Typen können sein: JSONObject oder Strings oder beliebige Datentypen. Wenn Sie eine AsyncTask-Klasse haben, sollten Sie definieren, wohin die Daten gesendet werden sollen. Beispiel: asyncTask.execute (" sampletargeturl.com"). get () ;
Nicu P
Bei Verwendung dieser Methode wurde auf Logcat eine Warnung angezeigt: "I / Choreographer ﹕ 50 Frames übersprungen! Die Anwendung arbeitet möglicherweise zu viel an ihrem Hauptthread." Wie gehe ich damit um? Wird die Benutzeroberfläche eingefroren, wenn auf die Rückkehr von AsyncTask gewartet wird?
Huy Do
@NicuP Sie haben vielleicht vergessen anzurufen execute(), siehe meine Antwort, ich habe dort einen Kommentar hinzugefügt. Vielleicht möchten Sie meine aktualisierte Antwort überprüfen. hoffe das hilft.
HelmiB
16

Diese Antwort könnte spät sein, aber ich möchte einige Dinge erwähnen, wenn Sie davon Activityabhängig sind AsyncTask. Dies würde Ihnen helfen, Abstürze und Speicherverwaltung zu verhindern. Wie bereits in den obigen Antworten erwähnt interface, sagen wir auch Rückrufe. Sie werden als Informanten arbeiten, aber in diesen Fällen niemals starke Referenzen senden Activityoder interfaceimmer schwache Referenzen verwenden.

Im folgenden Screenshot erfahren Sie, wie dies zu Problemen führen kann.

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen, wenn wir AsyncTaskmit einer starken Referenz begonnen haben, gibt es keine Garantie dafür, dass unser Activity/ Fragmentam Leben bleibt, bis wir Daten erhalten. WeakReferenceIn diesen Fällen ist es daher besser, es zu verwenden, und dies hilft auch bei der Speicherverwaltung, da wir dies niemals tun werden die starke Referenz unsererActivity dann wird es nach seiner Verzerrung zur Müllabfuhr berechtigt sein.

Überprüfen Sie das folgende Code-Snippet, um herauszufinden, wie Sie fantastische WeakReference verwenden können -

MyTaskInformer.java Schnittstelle, die als Informant arbeitet.

public interface MyTaskInformer {

    void onTaskDone(String output);

}

MySmallAsyncTask.javaAsyncTask für eine lange laufende Aufgabe, die verwendet wird 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.javaDiese Klasse wird verwendet, um mein AsyncTaskImplementierungsprogramm interfacefür diese Klasse und overridediese obligatorische Methode zu starten .

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
quelle
2
Das ist toll! Ein wichtiger Punkt, der nicht bemerkt werden kann.
HasH
6

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

} `

user3691697
quelle
6

Sie können dies in wenigen Zeilen tun. Überschreiben Sie einfach onPostExecute, wenn Sie Ihre AsyncTask aufrufen. Hier ist ein Beispiel für Sie:

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

Ich hoffe es hat dir geholfen, viel Spaß beim Codieren :)

Ayaz Alifov
quelle
Es funktioniert nicht bei mir. Es geht einfach nicht zur onPostExecuteMethode.
Francisco Romero
4

Warum machen es die Leute so schwer?

Dies sollte ausreichen.

Implementieren Sie onPostExecute nicht für die asynchrone Aufgabe, sondern für die Aktivität:

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
quelle
Das funktioniert bei mir. Es ist einfach und am einfachsten zu verstehen. Ich denke, es nutzt das, wofür Java entwickelt wurde. Vielen Dank. PS: Ist es notwendig, eine hinzuzufügen @Override?
Old Geezer
1
@Override ist nur eine Anmerkung. Sie teilen dem Java-Compiler also mit, dass Sie beabsichtigen, die Methode zu überschreiben, und werden informiert, wenn Sie dies nicht tun.
Bugdayci
4

Sie können die get()Methode von AsyncTask(oder die überladene get(long, TimeUnit)) aufrufen . Diese Methode wird blockiert, bis der AsyncTaskseine Arbeit abgeschlossen hat. An diesem Punkt erhalten Sie die zurückResult .

Es ist ratsam, zwischen dem Erstellen / Starten Ihrer asynchronen Aufgabe und dem Aufrufen der getMethode andere Arbeiten auszuführen , da Sie die asynchrone Aufgabe sonst nicht sehr effizient nutzen.

nicholas.hauschild
quelle
1
Downvoted vecause get () blockiert den Hauptthread. Kein Grund, AsyncTask zu verwenden, wenn es blockiert
GabrielBB
3

Sie können Ihren eigenen Hörer schreiben. Es ist dasselbe wie bei HelmiB die Antwort von , sieht aber natürlicher aus:

Listener-Schnittstelle erstellen:

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

Dann schreiben Sie Ihre asynchrone Aufgabe:

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

Implementieren Sie den Listener schließlich in Aktivität:

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

Und so können Sie asyncTask aufrufen:

 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
quelle
2

Hallo du kannst so etwas machen:

  1. Erstellen Sie eine Klasse, die AsyncTask implementiert

    // 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. In Hauptaktivität hinzufügen

    // 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
quelle
1

Erstellen Sie ein statisches Element in Ihrer Aktivitätsklasse. Weisen Sie dann den Wert während deronPostExecute

Wenn das Ergebnis Ihrer AsyncTask beispielsweise eine Zeichenfolge ist, erstellen Sie in Ihrer Aktivität eine öffentliche statische Zeichenfolge

public static String dataFromAsyncTask;

onPostExecuteRufen Sie dann in der AsyncTask einfach einen statischen Aufruf Ihrer Hauptklasse auf und legen Sie den Wert fest.

MainActivity.dataFromAsyncTask = "result blah";

mrres1
quelle
1
Welche Möglichkeiten gibt es in diesem Szenario für Speicherverluste?
Antroid
0

Ich mache es mit Threading und Handler / Nachricht. Schritte wie folgt: Deklarieren Sie einen Fortschrittsdialog

ProgressDialog loadingdialog;

Erstellen Sie eine Funktion zum Schließen des Dialogfelds, wenn der Vorgang abgeschlossen ist.

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

    }
    };

Codieren Sie Ihre Ausführungsdetails:

 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();
}
STRAHL
quelle
0

Sie müssen "Protokolle" verwenden , um Daten an die zu delegieren oder bereitzustellen AsynTask.

Delegierte und Datenquellen

Ein Delegat ist ein Objekt, das im Namen oder in Abstimmung mit einem anderen Objekt handelt, wenn dieses Objekt auf ein Ereignis in einem Programm stößt. ( Apple Definition )

Protokolle sind Schnittstellen, die einige Methoden definieren, um bestimmte Verhaltensweisen zu delegieren.

Hier ist ein vollständiges Beispiel !!!

IgniteCoders
quelle
0

Versuche dies:

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

    }
}

Und Anwendungsbeispiel:

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
quelle
0

Wahrscheinlich ein bisschen über Bord gehen, aber ich habe Rückrufe sowohl für den Ausführungscode als auch für die Ergebnisse bereitgestellt. Natürlich möchten Sie aus Gründen der Thread-Sicherheit vorsichtig sein, auf was Sie in Ihrem Ausführungsrückruf zugreifen.

Die AsyncTask-Implementierung:

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

Ein Rückruf:

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

Und schließlich die Ausführung der asynchronen Aufgabe:

 new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);
Squibly
quelle
0

Ich hoffe, Sie haben dies durchgemacht, wenn nicht, lesen Sie bitte.

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

Abhängig von der Art der Ergebnisdaten sollten Sie die bestmögliche Option auswählen, die Sie sich vorstellen können.

Es ist eine gute Wahl, eine Schnittstelle zu verwenden

Einige andere Optionen wären ..

  • Wenn die AsyncTask-Klasse innerhalb der Klasse definiert ist, in der Sie das Ergebnis verwenden möchten. Verwenden Sie eine statische globale Variable oder get () , verwenden Sie sie von der äußeren Klasse ( ggf. flüchtige Variable ). Sie sollten jedoch über den Fortschritt von AsyncTask informiert sein oder zumindest sicherstellen, dass die Aufgabe abgeschlossen ist und das Ergebnis über die globale Variable / get () -Methode verfügbar ist. Sie können Polling, onProgressUpdate (Progress ...) , Synchronisation oder Schnittstellen verwenden (je nachdem , was für Sie am besten geeignet ist ).

  • Wenn das Ergebnis mit einem sharedPreference-Eintrag kompatibel ist oder als Datei im Speicher gespeichert werden kann , können Sie es sogar von der Hintergrundaufgabe selbst speichern und mithilfe der onPostExecute () -Methode
    benachrichtigt werden, wenn das Ergebnis in verfügbar ist die Erinnerung.

  • Wenn die Zeichenfolge klein genug ist und zu Beginn einer Aktivität verwendet werden soll. Es ist möglich, Absichten ( putExtra () ) in onPostExecute () zu verwenden , aber denken Sie daran, dass statische Kontexte nicht so sicher sind .

  • Wenn möglich, können Sie eine statische Methode aus der onPostExecute () -Methode aufrufen, wobei das Ergebnis Ihr Parameter ist

Hart
quelle