I am trying to handle the config changes correctly when a service is running. So I thought I had achieved this as when testing this on my cheap LG E400 model (small screen) and turn the phone during the dialog (spinner style) showing, I have set up a onsavedinstancestate and in the onCreate look to see if this is !=null and then get the bundle variables to check where the app is with the service.
On the phone this all appears to work fine but when using my galaxy tab2 7.0 , the app actually does not crash during the screen rotation but the dialog box just stays on screen and nothing changes.
when I then look in logcat I have found that it reports a leak :
[HIGH]10-02 13:34:13.213: E/WindowManager(850): Activity co.uk.XXXXX.XXXX.Exportfile has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{4236a780 V.E..... R....... 0,0-580,163} that was originally added here
10-02 13:34:13.213: E/WindowManager(850): android.view.WindowLeaked: Activity co.uk.XXXXXX.XXXXXXXX.Exportfile has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{4236a780 V.E..... R....... 0,0-580,163} that was originally added here
10-02 13:34:13.213: E/WindowManager(850): at android.view.ViewRootImpl.<init>(ViewRootImpl.java:454)
10-02 13:34:13.213: E/WindowManager(850): at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:235)
10-02 13:34:13.213: E/WindowManager(850): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:73)
10-02 13:34:13.213: E/WindowManager(850): at android.app.Dialog.show(Dialog.java:282)
10-02 13:34:13.213: E/WindowManager(850): at co.uk.XXXXXX.XXXXXXX.Exportfile.onCreate(Exportfile.java:123)
10-02 13:34:13.213: E/WindowManager(850): at android.app.Activity.performCreate(Activity.java:5283)
10-02 13:34:13.213: E/WindowManager(850): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1097)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2209)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2295)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3779)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread.access$800(ActivityThread.java:150)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1286)
10-02 13:34:13.213: E/WindowManager(850): at android.os.Handler.dispatchMessage(Handler.java:99)
10-02 13:34:13.213: E/WindowManager(850): at android.os.Looper.loop(Looper.java:175)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread.main(ActivityThread.java:5279)
10-02 13:34:13.213: E/WindowManager(850): at java.lang.reflect.Method.invokeNative(Native Method)
10-02 13:34:13.213: E/WindowManager(850): at java.lang.reflect.Method.invoke(Method.java:511)
10-02 13:34:13.213: E/WindowManager(850): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
10-02 13:34:13.213: E/WindowManager(850): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
10-02 13:34:13.213: E/WindowManager(850): at dalvik.system.NativeStart.main(Native Method)
[/HIGH]
*** EDIT 1 ***
Code from within the onSaveInstanceState (NOW THE LATEST VERSION) :
[HIGH] @Override
public void onSaveInstanceState(Bundle saved) {
if (isexportrunning) {
saved.putBoolean("EXPORTR", isexportrunning);
}
if (ishasexportfinished) {
saved.putBoolean("EXPORTD", ishasexportfinished);
}
if (isfiltered) {
saved.putBoolean("FILTER", isfiltered);
}
if (iswritelogdone) {
saved.putBoolean("DONELOG", iswritelogdone);
}
if (exporti !=null) {
Log.d("SAVEDI","export data count=");
saved.putStringArrayList("DATA", (ArrayList<String>) exporti);
}
if (fullpathname.length()>0) {
saved.putString("PATH", fullpathname);
//Log.d("SAVEDP","File name and location = "+fullpathname);
}
super.onSaveInstanceState(saved);
}
[/HIGH]
Code within the onCreate to get the save objects from the onSaveInstanceState (NOW THE LATEST VERSION) :
[HIGH]if (savedInstanceState != null) {
iswritelogdone = savedInstanceState.getBoolean("DONELOG");
Boolean exportchk = savedInstanceState.getBoolean("EXPORTR");
isfiltered = savedInstanceState.getBoolean("FILTER");
Log.d("EXPCHK","Export Running ="+exportchk);
Boolean exportdone = savedInstanceState.getBoolean("EXPORTD");
Log.d("EXPCHK","Export Done ="+exportdone);
List<String> exportir = savedInstanceState.getStringArrayList("DATA");
//Log.d("EARRAY","Retained array size = "+exportir.size());
String fullpath = savedInstanceState.getString("PATH");
fullpathname = fullpath;
Log.d("EPATH","Full path stored is = "+fullpath);
Log.d("EPATH","Full path NAME stored is = "+fullpathname);
if (!exportprogress.isShowing() && exportchk) {
isexportrunning = true;
ishasexportfinished = false;
exportprogress.setCancelable(false);
exportprogress.setCanceledOnTouchOutside(false);
exportprogress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
exportprogress.setTitle("Export");
exportprogress.setMessage("Gathering Database Information (Config Change)...");
exportprogress.show();
}
if (myexportbr == null && exportchk) {
Log.d("REGBR","Reached the re-register of the broadcast receiver");
myexportbr = new exportbr();
IntentFilter intentFilter = new IntentFilter(ImpExpService.ACTION_MyIntentService);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(myexportbr, intentFilter);
}
if (exportdone) {
isexportrunning = false;
ishasexportfinished = true;
if (!iswritelogdone) {
if (writelog(exportir,fullpath)) {
iswritelogdone = true;
new AlertDialog.Builder(Exportfile.this)
.setIcon(R.drawable.app_icon)
.setTitle("Export Complete")
.setMessage("Export has finished, filename and location are "+fullpath+
" .Returning to main application screen")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
isexportrunning = false;
ishasexportfinished = true;
finish();
}})
.show();
}
} else {
new AlertDialog.Builder(Exportfile.this)
.setIcon(R.drawable.app_icon)
.setTitle("Export Complete")
.setMessage("Export has finished, filename and location are "+fullpath+
" .Returning to main application screen")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
isexportrunning = false;
ishasexportfinished = true;
finish();
}})
.show();
}
}
}
[/HIGH]
Code that starts the service :
[HIGH]Intent intentMyIntentService = new Intent(Exportfile.this,ImpExpService.class);
intentMyIntentService.putExtra("IMPEXP",2);
startService(intentMyIntentService);
Log.d("SERVICE", "Started Service");
myexportbr = new exportbr();
IntentFilter intentFilter = new IntentFilter(ImpExpService.ACTION_MyIntentService);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(myexportbr, intentFilter);
Log.d("BRECIVER", "Started Receiver");
isexportrunning = true;
exportprogress.show();
[/HIGH]
Code in the Broadcast Receiver (NOW THE LATEST VERSION):
[HIGH] public class exportbr extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
Log.d("BRECIVER", "Reached Receiver");
// TODO Auto-generated method stub
exportprogress.dismiss();
String expcomp = arg1.getStringExtra("FINISH");
isexportrunning = false;
ishasexportfinished = true;
exporti = new ArrayList<String>();
exporti = arg1.getStringArrayListExtra("LIST");
Log.d("EXPORT","Records exported are "+Integer.toString(exporti.size()));
if (expcomp.equals("DONE")) {
dialogfullpathname = fullpathname;
if (writelog(exporti,dialogfullpathname)) {
iswritelogdone = true;
new AlertDialog.Builder(Exportfile.this)
.setIcon(R.drawable.app_icon)
.setTitle("Export Complete")
.setMessage("Export has finished, filename and location are "+dialogfullpathname+
" .Returning to main application screen")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
isexportrunning = false;
ishasexportfinished = false;
finish();
}})
.show();
}
} else {
new AlertDialog.Builder(Exportfile.this)
.setIcon(R.drawable.quitapp)
.setTitle("OOPS")
.setMessage("Something has gone horribly wrong
")
.setPositiveButton("OK", null).show();
isexportrunning = false;
}
}
}
[/HIGH]
And finally the onDestroy method :
[HIGH] @Override
protected void onDestroy() {
super.onDestroy();
if (exportprogress.isShowing()){
exportprogress.dismiss();
}
//un-register BroadcastReceiver
if (myexportbr != null) {
unregisterReceiver(myexportbr);
}
}
[/HIGH]
*** EDIT 2 ***
Two things - 1)code above has been updated . 2) the tablet seems to take longer to rotate than the phone but I doubt this is the cause.
Thanks
TimCS
On the phone this all appears to work fine but when using my galaxy tab2 7.0 , the app actually does not crash during the screen rotation but the dialog box just stays on screen and nothing changes.
when I then look in logcat I have found that it reports a leak :
[HIGH]10-02 13:34:13.213: E/WindowManager(850): Activity co.uk.XXXXX.XXXX.Exportfile has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{4236a780 V.E..... R....... 0,0-580,163} that was originally added here
10-02 13:34:13.213: E/WindowManager(850): android.view.WindowLeaked: Activity co.uk.XXXXXX.XXXXXXXX.Exportfile has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView{4236a780 V.E..... R....... 0,0-580,163} that was originally added here
10-02 13:34:13.213: E/WindowManager(850): at android.view.ViewRootImpl.<init>(ViewRootImpl.java:454)
10-02 13:34:13.213: E/WindowManager(850): at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:235)
10-02 13:34:13.213: E/WindowManager(850): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:73)
10-02 13:34:13.213: E/WindowManager(850): at android.app.Dialog.show(Dialog.java:282)
10-02 13:34:13.213: E/WindowManager(850): at co.uk.XXXXXX.XXXXXXX.Exportfile.onCreate(Exportfile.java:123)
10-02 13:34:13.213: E/WindowManager(850): at android.app.Activity.performCreate(Activity.java:5283)
10-02 13:34:13.213: E/WindowManager(850): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1097)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2209)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2295)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3779)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread.access$800(ActivityThread.java:150)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1286)
10-02 13:34:13.213: E/WindowManager(850): at android.os.Handler.dispatchMessage(Handler.java:99)
10-02 13:34:13.213: E/WindowManager(850): at android.os.Looper.loop(Looper.java:175)
10-02 13:34:13.213: E/WindowManager(850): at android.app.ActivityThread.main(ActivityThread.java:5279)
10-02 13:34:13.213: E/WindowManager(850): at java.lang.reflect.Method.invokeNative(Native Method)
10-02 13:34:13.213: E/WindowManager(850): at java.lang.reflect.Method.invoke(Method.java:511)
10-02 13:34:13.213: E/WindowManager(850): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
10-02 13:34:13.213: E/WindowManager(850): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
10-02 13:34:13.213: E/WindowManager(850): at dalvik.system.NativeStart.main(Native Method)
[/HIGH]
*** EDIT 1 ***
Code from within the onSaveInstanceState (NOW THE LATEST VERSION) :
[HIGH] @Override
public void onSaveInstanceState(Bundle saved) {
if (isexportrunning) {
saved.putBoolean("EXPORTR", isexportrunning);
}
if (ishasexportfinished) {
saved.putBoolean("EXPORTD", ishasexportfinished);
}
if (isfiltered) {
saved.putBoolean("FILTER", isfiltered);
}
if (iswritelogdone) {
saved.putBoolean("DONELOG", iswritelogdone);
}
if (exporti !=null) {
Log.d("SAVEDI","export data count=");
saved.putStringArrayList("DATA", (ArrayList<String>) exporti);
}
if (fullpathname.length()>0) {
saved.putString("PATH", fullpathname);
//Log.d("SAVEDP","File name and location = "+fullpathname);
}
super.onSaveInstanceState(saved);
}
[/HIGH]
Code within the onCreate to get the save objects from the onSaveInstanceState (NOW THE LATEST VERSION) :
[HIGH]if (savedInstanceState != null) {
iswritelogdone = savedInstanceState.getBoolean("DONELOG");
Boolean exportchk = savedInstanceState.getBoolean("EXPORTR");
isfiltered = savedInstanceState.getBoolean("FILTER");
Log.d("EXPCHK","Export Running ="+exportchk);
Boolean exportdone = savedInstanceState.getBoolean("EXPORTD");
Log.d("EXPCHK","Export Done ="+exportdone);
List<String> exportir = savedInstanceState.getStringArrayList("DATA");
//Log.d("EARRAY","Retained array size = "+exportir.size());
String fullpath = savedInstanceState.getString("PATH");
fullpathname = fullpath;
Log.d("EPATH","Full path stored is = "+fullpath);
Log.d("EPATH","Full path NAME stored is = "+fullpathname);
if (!exportprogress.isShowing() && exportchk) {
isexportrunning = true;
ishasexportfinished = false;
exportprogress.setCancelable(false);
exportprogress.setCanceledOnTouchOutside(false);
exportprogress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
exportprogress.setTitle("Export");
exportprogress.setMessage("Gathering Database Information (Config Change)...");
exportprogress.show();
}
if (myexportbr == null && exportchk) {
Log.d("REGBR","Reached the re-register of the broadcast receiver");
myexportbr = new exportbr();
IntentFilter intentFilter = new IntentFilter(ImpExpService.ACTION_MyIntentService);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(myexportbr, intentFilter);
}
if (exportdone) {
isexportrunning = false;
ishasexportfinished = true;
if (!iswritelogdone) {
if (writelog(exportir,fullpath)) {
iswritelogdone = true;
new AlertDialog.Builder(Exportfile.this)
.setIcon(R.drawable.app_icon)
.setTitle("Export Complete")
.setMessage("Export has finished, filename and location are "+fullpath+
" .Returning to main application screen")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
isexportrunning = false;
ishasexportfinished = true;
finish();
}})
.show();
}
} else {
new AlertDialog.Builder(Exportfile.this)
.setIcon(R.drawable.app_icon)
.setTitle("Export Complete")
.setMessage("Export has finished, filename and location are "+fullpath+
" .Returning to main application screen")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
isexportrunning = false;
ishasexportfinished = true;
finish();
}})
.show();
}
}
}
[/HIGH]
Code that starts the service :
[HIGH]Intent intentMyIntentService = new Intent(Exportfile.this,ImpExpService.class);
intentMyIntentService.putExtra("IMPEXP",2);
startService(intentMyIntentService);
Log.d("SERVICE", "Started Service");
myexportbr = new exportbr();
IntentFilter intentFilter = new IntentFilter(ImpExpService.ACTION_MyIntentService);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(myexportbr, intentFilter);
Log.d("BRECIVER", "Started Receiver");
isexportrunning = true;
exportprogress.show();
[/HIGH]
Code in the Broadcast Receiver (NOW THE LATEST VERSION):
[HIGH] public class exportbr extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
Log.d("BRECIVER", "Reached Receiver");
// TODO Auto-generated method stub
exportprogress.dismiss();
String expcomp = arg1.getStringExtra("FINISH");
isexportrunning = false;
ishasexportfinished = true;
exporti = new ArrayList<String>();
exporti = arg1.getStringArrayListExtra("LIST");
Log.d("EXPORT","Records exported are "+Integer.toString(exporti.size()));
if (expcomp.equals("DONE")) {
dialogfullpathname = fullpathname;
if (writelog(exporti,dialogfullpathname)) {
iswritelogdone = true;
new AlertDialog.Builder(Exportfile.this)
.setIcon(R.drawable.app_icon)
.setTitle("Export Complete")
.setMessage("Export has finished, filename and location are "+dialogfullpathname+
" .Returning to main application screen")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface arg0, int arg1) {
// TODO Auto-generated method stub
isexportrunning = false;
ishasexportfinished = false;
finish();
}})
.show();
}
} else {
new AlertDialog.Builder(Exportfile.this)
.setIcon(R.drawable.quitapp)
.setTitle("OOPS")
.setMessage("Something has gone horribly wrong
").setPositiveButton("OK", null).show();
isexportrunning = false;
}
}
}
[/HIGH]
And finally the onDestroy method :
[HIGH] @Override
protected void onDestroy() {
super.onDestroy();
if (exportprogress.isShowing()){
exportprogress.dismiss();
}
//un-register BroadcastReceiver
if (myexportbr != null) {
unregisterReceiver(myexportbr);
}
}
[/HIGH]
*** EDIT 2 ***
Two things - 1)code above has been updated . 2) the tablet seems to take longer to rotate than the phone but I doubt this is the cause.
Thanks
TimCS