Подтвердить что ты не робот

Android: Как обновить пользовательский интерфейс от AsyncTask, если AsyncTask находится в отдельном классе?

Я ненавижу внутренний класс.

У меня есть основная деятельность, которая запускает AsyncTask в короткой жизни.

AsyncTask в отдельном файле, не является внутренним классом основного действия

Мне нужна задача async для обновления textView из основного Activity.

Я знаю, что могу обновить TextView из onProgressUpdate, если AsyncTask является внутренним классом

Но как из внешней, независимой, асинхронной задачи?

UPDATE: Это выглядит как работа:

В acitivty я вызываю задачу

backgroundTask = new BackgroundTask(this);
backgroundTask.execute();

В конструкторе у меня

public BackgroundTask(Activity myContext)
{
    debug = (TextView) myContext.findViewById(R.id.debugText);
}

где debug было частным полем AsyncTask.

Так что onProgressUpdate Я могу

debug.append(text);

Спасибо за все ваши предложения

4b9b3361

Ответ 1

EDIT Я отредактировал ответ, чтобы использовать WeakReference


AsyncTask всегда является отдельным классом из Activity, но я подозреваю, что вы имеете в виду, что он находится в другом файле, чем файл вашего класса активности, поэтому вы не можете воспользоваться внутренним классом активности. Просто передайте контекст Activity в качестве аргумента для вашей задачи Async (т.е. К его конструктору)

class MyAsyncTask extends AsyncTask<URL, Integer, Long> {

    WeakReference<Activity> mWeakActivity;

    public MyAsyncTask(Activity activity) {
       mWeakActivity = new WeakReference<Activity>(activity);
    }

 ...

и использовать, когда вам это нужно (не забудьте НЕ использовать во время doInBackground()), то есть, когда вы обычно вызываете

int id = findViewById(...)

в AsyncTask вы вызываете i.e.

Activity activity = mWeakActivity.get();
if (activity != null) {
   int id = activity.findViewById(...);
}

Обратите внимание, что наш Activity может исчезнуть, пока выполняется doInBackground() (поэтому возвращаемая ссылка может стать null), но с помощью WeakReference мы не предотвращаем сбор GC (и утечку памяти) и поскольку активность ушла, обычно даже бессмысленно даже пытаться обновить ее состояние (все же, в зависимости от вашей логики, вы можете сделать что-то вроде изменения внутреннего состояния или обновить БД, но прикосновение к пользовательскому интерфейсу должно быть пропущено).

Ответ 2

Использование интерфейса 1) Создайте один интерфейс

public interface OnDataSendToActivity {
    public void sendData(String str);
}

2) Реализует его в вашей деятельности

public class MainActivity extends Activity implements OnDataSendToActivity{

     @Override
     protected void onCreate(Bundle savedInstanceState) {
          new AsyncTest(this).execute(new String[]{"AnyData"}); // start your task
     }

     @Override
     public void sendData(String str) {
         // TODO Auto-generated method stub

     }

}

3) Создайте конструктор в AsyncTask (активность активности) {}  Зарегистрируйте свой интерфейс в файле AsyncTask  и метод интерфейса вызова, как показано ниже.

public class AsyncTest extends AsyncTask<String, Integer, String> {

    OnDataSendToActivity dataSendToActivity;
    public AsyncTest(Activity activity){
        dataSendToActivity = (OnDataSendToActivity)activity;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        dataSendToActivity.sendData(result);
    }

}

Здесь ваш OnPostExecute вызывается после выполнения всей задачи, выполняемой AsyncTask, и получит "результат", как параметр, возвращаемый doInBackground() {return "";}.

Пока "dataSendToActivity.sendData(результат);" он вызовет метод переопределения активности "public void sendData (String str) {}".

Замечание о краю: обязательно передайте this, то есть текущий контекст активности на AsyncTask, а не создайте другой экземпляр своей активности, иначе ваш Activity будет уничтожен, а новый будет создан.

Ответ 3

Просто передайте контекст (активность или что-то еще) в свою AsyncTask в конструкторе, а затем в onSuccess или onProgressUpdate вызовите все, что вам нужно в контексте.

Ответ 4

Я написал небольшое расширение для AsyncTask для такого сценария. Это позволяет вам сохранять AsyncTask в отдельном классе, но также дает удобный доступ к завершению Задачи:

public abstract class ListenableAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result>{

    @Override
    protected final void onPostExecute(Result result) {
        notifyListenerOnPostExecute(result);
    }

    private AsyncTaskListener<Result> mListener;
    public interface AsyncTaskListener<Result>{
        public void onPostExecute(Result result);
    }
    public void listenWith(AsyncTaskListener<Result> l){
        mListener = l;
    }
    private void notifyListenerOnPostExecute(Result result){
        if(mListener != null)
            mListener.onPostExecute(result);
    }

}

Итак, сначала вы расширяете ListenableAsyncTask вместо AsyncTask. Затем в вашем коде пользовательского интерфейса создайте конкретный экземпляр и установите listenWith (...).

Ответ 5

Сделайте статическую функцию в своем контексте, передавая контекст в ней, чтобы обновить текстовое представление, а затем вызвать эту функцию в классе AsynkTask для обновления.

В классе активности: public static void updateTextView() {

//ваш код здесь }

В классе AynckTask вызовите эту функцию.

Ответ 6

Вопрос уже был дан ответ, но я еще не опубликовал, как это должно быть сделано, я думаю..

Класс mainactivity

  public class MainActivity extends Activity implements OnClickListener
    {

        TextView Ctemp;

        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Ctemp = (TextView) findViewById(R.id.Ctemp);
            doConv = (Button) findViewById(R.id.doConv);
            doConv.setOnClickListener(this);
        }

        @Override
        public void onClick(View arg0) // The conversion to do
        {
            new asyncConvert(this).execute();
        }
    }

теперь в классе async

public class asyncConvert extends AsyncTask<Void, Void, String>
{
    SoapPrimitive response = null;
    Context context;

    public asyncConvert(Context callerclass)
    {
        contextGUI = callerclass;
    }
.
.
.
.
protected void onPostExecute(String result)
    {
        ((MainActivity) contextGUI).Ctemp.setText(result); // changing TextView
    }
}

Ответ 7

    /**
     * Background Async Task to Load all product by making HTTP Request
     * */
     public  static class updateTExtviewAsyncTask extends AsyncTask<String, String, String> {

        Context context;
        ProgressDialog pDialog;
        String id, name;

        String state_id;

        //--- Constructor for getting network id from asking method

        public  updateTExtviewAsyncTask(Context context,String id,String city) 
        {
            context   = context;
            state_id  = id;
            city_name = city;
        }       
        /* *
         * Before starting background thread Show Progress Dialog
         * */
        @Override
        protected void onPreExecute() 
        {
            super.onPreExecute();
            pDialog = ProgressDialog.show(context, "","Please wait...", true, true);
            pDialog.show();

        }

        /**
         * getting All products from url
         * */
        protected String doInBackground(String... args) 
        {
            return null;
        }

        /**
         * After completing background task Dismiss the progress dialog
         * **/
            protected void onPostExecute(String file_url)  {

                     YourClass.UpdateTextViewData("Textview data");
        }
    }

//поместите этот код внутри вашего класса активности, а также объявите обновление static static static

    public static void  UpdateTextViewData(String tvData) 
{
   tv.setText(tvData);
}