我有一个显示ProgressDialog的AsyncTask。 AsyncTask在活动开始时启动:
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_layout);
new MyTask().execute();
}
// ... other code
private class MyTask extends AsyncTask<Void, Void, Void>{
private ProgressDialog dialog = new ProgressDialog(MyActivity.this);
@Override
protected void onPreExecute() {
dialog.show();
}
@Override
protected Void doInBackground(Void... voids) {
// get data from a server
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
// call to a method in MyActivity which updates the UI.
if (dialog.isShowing()) {
dialog.dismiss();
}
}
}
}
此代码完美无缺,直到我旋转屏幕。这是有道理的,因为用于创建对话框的上下文不再存在(因为在旋转时重新创建活动),并且导致窗口泄漏。
我能想到的唯一解决方案不是一个非常好的解决方案:创建任务和对话框的静态实例,并在销毁活动时简单地关闭对话框,并在任务中重新创建对话框还在运行。
那么如何在不丢失功能的情况下解决这样的问题(因此在任务运行时必须始终显示对话框,并且应该允许旋转设备)?
答案 0 :(得分:1)
正如Raghunandan在评论中所说,我查看了碎片并解决了我的问题。
我创建了一个片段来启动我的AsyncTask,正如Raghunandan提供的blogpost中所解释的那样。
为了确保我的Dialog没有泄露,我创建了一个DialogFragment,如here所述(基本对话框)。
这是我的工作代码:
我的活动:
public class MyActivity extends Activity implements MyTaskFragment.TaskCallbacks {
private MyTaskFragment task;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_layout);
FragmentManager fm = getFragmentManager();
task = (MyTaskFragment) fm.findFragmentByTag("myTask");
if (task == null) {
task = new MyTaskFragment();
fm.beginTransaction().add(task, "myTask").commit();
}
}
@Override
public void onPreExecute() {
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("myDialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
StringProgressDialogFragment dialog = StringProgressDialogFragment.newInstance("My message");
dialog.show(ft, "myDialog");
}
@Override
public void onPostExecute() {
StringProgressDialogFragment dialog = (StringProgressDialogFragment) getFragmentManager().findFragmentByTag("myDialog");
if (dialog!=null) {
dialog.dismiss();
}
// update UI
}
// ... other code
}
我的任务片段:
public class MyTaskFragment extends Fragment {
private TaskCallbacks mCallbacks;
private Task mTask;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mCallbacks = (TaskCallbacks) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Retain this fragment across configuration changes.
setRetainInstance(true);
// Create and execute the background task.
mTask = new Task();
mTask.execute();
}
@Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
private class Task extends AsyncTask<Void, Void, Void> {
@Override
protected void onPreExecute() {
mCallbacks.onPreExecute();
}
@Override
protected Void doInBackground(Void... voids) {
// do stuff
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
mCallbacks.onPostExecute();
}
}
public static interface TaskCallbacks {
void onPreExecute();
void onPostExecute();
}
}
我的对话片段:
public class StringProgressDialogFragment extends DialogFragment {
private String message;
public static StringProgressDialogFragment newInstance(String message) {
StringProgressDialogFragment dialog = new StringProgressDialogFragment();
Bundle args = new Bundle();
args.putString("message", message);
dialog.setArguments(args);
return dialog;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
ProgressDialog dialog = new ProgressDialog(getActivity());
message = getArguments().getString("message");
dialog.setMessage(message);
return dialog;
}
}
答案 1 :(得分:0)
试试样品。它会工作。基本上只是通过处理配置更改来限制oncreate调用。这个解决方案可以帮到你。
public class MainActivity extends Activity {
LoadProgrssdata task = new LoadProgrssdata();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, "oncreate called", Toast.LENGTH_SHORT).show();
task.execute();
}
public class LoadProgrssdata extends AsyncTask<Void, Void, Void> {
ProgressDialog progressDialog;
//declare other objects as per your need
@Override
protected void onPreExecute()
{
progressDialog= ProgressDialog.show(MainActivity.this, "Progress Dialog Title Text","Process Description Text", true);
//do initialization of required objects objects here
};
@Override
protected Void doInBackground(Void... params)
{
//do loading operation here
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
progressDialog.dismiss();
};
}
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Log.e("orientation ", "landscape");
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Log.e("orientation ", "portrait");
}
}
}
并在android清单文件中:
<activity
android:name="com.example.MainActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden|screenSize" />
答案 2 :(得分:0)
新的Loaders API可以为您提供帮助(可通过支持包获得) - man。他们将解决旋转问题,但不会解决问题。泄漏。解决mem。泄漏编写自己的“AsyncTask”(带有“clearContext”例程)并在活动的onDestroy(或onPause,取决于您的体系结构)中清除它的上下文。它可能看起来像一辆自行车,但任务最多需要1天,您可以完全控制后台工作人员使用的所有资源。
顺便说一句:考虑通过片段使用对话框,因为它解决了屏幕旋转时对话框的杀戮。
答案 3 :(得分:0)
我设法通过尝试捕获doInBackground中可能发生的任何崩溃来解决此问题。