Я столкнулся с этим примером андроида, который выполняет AsyncTask от потока UI. Класс ExportDatabaseTask объявляют и инстанцируют в Действии, и по-видимому возможно сослаться на контекст UI действия от onPreExecute и onPostExecute событий, как это:
public class ManageData extends Activity {
private ExportDatabaseTask exportDatabaseTask;
[...]
@Override
public void onCreate(final Bundle savedInstanceState) {
[...]
ManageData.this.exportDatabaseTask = new ExportDatabaseTask();
ManageData.this.exportDatabaseTask.execute();
[...]
}
private class ExportDatabaseTask extends AsyncTask {
private final ProgressDialog dialog = new ProgressDialog(ManageData.this);
protected void onPreExecute() {
this.dialog.setMessage("Exporting database...");
this.dialog.show();
}
protected Boolean doInBackground(final String... args) {
[...]
}
protected void onPostExecute(final Boolean success) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
}
}
Я пытаюсь осуществить рефакторинг это так, чтобы ExportDatabaseTask был объявлен в другом классе, который не является Действием по различным причинам, и я не могу вполне выяснить, как заставить его работать. Я испытываю недостаток в некоторых основных понятиях Java здесь, которые я с готовностью допускаю.
А именно, myActivity является пустым в onPreExecute (). Почему это?
// this is a click event handler in my activity that starts the export
public void onClick(View v) {
Exporter ex = new Exporter(getApplicationContext(), ActivityMain.this);
ex.exportDatabaseTask.execute();
}
//this is the utility class
public class Exporter {
public ExportDatabaseTask exportDatabaseTask;
private Context myContext;
private ActivityMain myActivity;
public Exporter(Context ctx, ActivityMain act) {
myContext = ctx;
myActivity = act;
this.exportDatabaseTask = new ExportDatabaseTask();
}
public class ExportDatabaseTask extends AsyncTask {
private final ProgressDialog dialog = new ProgressDialog(myContext);
// can use UI thread here?
protected void onPreExecute() {
// ====> this throws a Nullpointer exception:
myActivity.dialog.setMessage("Exporting database...");
myActivity.dialog.show();
}
protected Boolean doInBackground(final Void... args) {
}
protected void onPostExecute(final Boolean success) {
if (myActivity.dialog.isShowing()) {
myActivity.dialog.dismiss();
}
}
}
}
Я понимаю, что могу взять код от пред и поствыполнить события и поместить его в onclick обработчик в моем действии, избежав этого вопроса, но мне все еще любопытно, почему код выше не работает.
Правило №1: Никогда не используйте getApplicationContext ()
для получения контекста
. Действие
является Контекстом
. Вам не нужен другой Контекст
, а Контекст
, который вы получаете из getApplicationContext ()
, совершенно непригоден для операций, связанных с графическим интерфейсом пользователя.
Теперь, разобравшись с этим ...
очевидно, можно сослаться на контекст пользовательского интерфейса действия из События onPreExecute и onPostExecute
ExportDatabaseTask
- это частный внутренний класс действия Activity
. Внутренние классы в Java имеют доступ к методам и членам данных своего внешнего класса.
В частности, myActivity имеет значение null в onPreExecute (). Почему?
Сомневаюсь. Я подозреваю, что диалоговое окно null
внутри myActivity
. Это тоже даст вам NullPointerException
в указанной строке.