Rozwój Androida: posiadanie Asynctasku w oddzielnym pliku klasy

Grałem na różnych przykładach próbując zapoznać się z AsyncTask. Do tej pory wszystkie przykłady widziałem miały AsyncTask włączone do onCreate metody głównej działalności. Co nie podoba mi się bardzo, więc chciałem zobaczyć, jak trudno byłoby rozdzielić go na własną klasę. Jak narazie mam to:

Główna aktywność

package com.example.asynctaskactivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.example.asynctaskactivity.ShowDialogAsyncTask;

public class AsyncTaskActivity extends Activity {

 Button btn_start;
 ProgressBar progressBar;
 TextView txt_percentage;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        btn_start = (Button) findViewById(R.id.btn_start);
        progressBar =  (ProgressBar) findViewById(R.id.progress);
        txt_percentage= (TextView) findViewById(R.id.txt_percentage);
        Log.v("onCreate","Attempt set up button OnClickListener");
        btn_start.setOnClickListener(new View.OnClickListener() 
        { 
           @Override
           public void onClick(View v) {
               btn_start.setEnabled(false);
               new ShowDialogAsyncTask().execute();
           }
        });

        Log.v("onCreate","Success!"); 
    }
}

Nowa klasa seperate AsyncTask

package com.example.asynctaskactivity;

import android.os.AsyncTask;
import android.os.SystemClock;
import android.util.Log;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class ShowDialogAsyncTask extends AsyncTask<Void, Integer, Void>{
int progress_status;

@Override
    protected void onPreExecute() {
    // update the UI immediately after the task is executed
    Log.v("onPreExecute","1");
    super.onPreExecute();
    Log.v("onPreExecute","2");
    //Toast.makeText(AsyncTaskActivity.this,"Invoke onPreExecute()", Toast.LENGTH_SHORT).show();
    progress_status = 0;
    Log.v("onPreExecute","3");
    txt_percentage.setText("downloading 0%");  
    Log.v("onPreExecute","4");
    }

    @Override
    protected Void doInBackground(Void... params) {
        Log.v("doInBackground","1");
        while(progress_status<100){

            progress_status += 2;

            publishProgress(progress_status);
            SystemClock.sleep(300);

        }
        return null;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);

    progressBar.setProgress(values[0]);
    txt_percentage.setText("downloading " +values[0]+"%");   
    }

    @Override
    protected void onPostExecute(Void result) {
    super.onPostExecute(result);

    //Toast.makeText(AsyncTaskActivity.this,"Invoke onPostExecute()", Toast.LENGTH_SHORT).show();

    txt_percentage.setText("download complete");
    btn_start.setEnabled(true);
    }
}

Pierwotnie to wszystko było w główna działalność, stąd wzmianki o elementach, które AsyncTask powinien teoretycznie aktualizować. Oczywiście w chwili obecnej powoduje to błędy uruchomieniowe, co dało mi do myślenia. Jak Mogę mieć oddzielny plik, ale nadal aktualizować wątek UI.

Przepraszam, jeśli jest to głupie pytanie, całkiem nowe w rozwoju Androida i wątki w tle w szczególności.

Author: Benjamin, 2013-03-19

3 answers

Jak mogę mieć oddzielny plik, ale nadal aktualizować wątek UI.

Okey. Więc na początku wiesz, że główną zaletą AsyncTask dodanego w Activity as inner class jest to, że masz bezpośredni dostęp do wszystkich elementów UI i umożliwia to całkiem "lekkie" aktualizacje UI.

Ale jeśli zdecydowałeś się na oddzielenie AsyncTask od aktywności (które również mają pewne zalety, np. kod jest bardziej czysty, a logika aplikacji jest oddzielona od wyglądu), możesz:

  • ty może przekazać elementy interfejsu użytkownika za pomocą konstruktora klasy
  • możesz tworzyć różne setery
  • możesz utworzyć interfejs, który będzie zawierał wywołania zwrotne. Zobacz też Android AsyncTask sending Callbacks to UI
To chyba wszystko, czego potrzebujesz.
 18
Author: Simon Dorociak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:57

Dodaj interfejs wywołania zwrotnego i pozwól Activity zaimplementować go.

public interface MyAsyncTaskCallback{
    public void onAsyncTaskComplete();
}

W poście:

myAsyncTaskCallback.onAsyncTaskComplete();

W konstruktorze twojego AsyncTask możesz przekazać instancję MyAsyncTaskCallback (Twoje Activity).

 9
Author: nhaarman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-18 22:06:31

Twój najlepszy sposób radzenia sobie z tym jest za pomocą Handlera. Utwórz instancję w aktywności i nadpisaj metodę handleMessage(). Kiedy tworzysz klasę ShowDialogAsyncTask, po prostu przekazuj ją do obsługi i zachowaj odniesienie do niej. Na postExecute możesz skonstruować wiadomość i wysłać ją za pomocą metody obsługi sendMessage().

Poprzednia odpowiedź wspomniana przy użyciu interfejsu i paradygmatu wywołania zwrotnego. To zadziała, jednak istnieje szansa, że aktywność może zostać zniszczona i nie będzie obecna, gdy Metoda postExecute jest wykonane, więc trzeba będzie przetestować na to.

 1
Author: BrianPlummer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-01 16:25:02