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);
Спасибо за все ваши предложения
Ответы
Ответ 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);
}