• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps config changes service and dialog box [SOLVED]

timcs

Member
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
 
I think I have solved the dialog leak but I am now getting this message which means I may have to re-open the database on a config change ?

[HIGH]10-02 22:24:52.454: W/SQLiteConnectionPool(24972): A SQLiteConnection object for database '+data+data+co_uk_XXXXXX_XXXXXX+databases+XXXXX' was leaked! Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.[/HIGH]


Problem here is that the database is opened within the service so I cannot understand the problem. I have an import routine which calls the same service but fires off a different method within that service, this uses the database so I am confused why the export routine is . The only difference between the two is that the export routine waits for the service to finish and then writes the file out within the export class instead of within the service

*** EDIT 1 ****

Scrap this error because it occurred while the app was stuck from the first problem which by the way has happened again.


Thanks

TimCS
 
Reading back my last post may seem like I have sorted this but I have not, I do not seem to be getting dialog and database leaks, however what is happening is when the config change occurs - it is as though the activity / broadcast receiver is not being told by the service that is has finished which then means the dialog box just stays on screen making the user think that it is still running

Thanks

TimCS
 
Working on this further it appears that the dialog is not the issue here. When the activity is restarted by a configuration change , although the broadcast receiver is re-created - it appears that it is not getting the message sent back from the intentservice.

I first thought it was because I was using one intentservice between two different classes using their own broadcastreceiver however when I then created a new intentservice for this specific class (the export class) the problem still remains .

If however I do not change the orientation everything does work. With the import routine however this appears to work both ways.

I cannot find out why one works and the other does not.

Thanks

TimCS
 
With more testing it appears that the service is sending the broadcast back to the receiver before the receiver has been re-registered from a configuration change.

My problem now is how to overcome this situation , there are times where the service is sent afterwards during a config change but for some reason the dialog stays on screen and then does not report back to the user that it has finished.

Any thoughts on this problem would be appreciated ..

Thanks

TimCS
 
Seem to have solved this now. I have used the onSaveInstatanceState method to store the boolean variables at their current state, then used onResume/onPause to get these variables back and unregister/register the broadcast reciever after they have been retrieved from within the onCreate method using the bundle there.

Thanks

TimCS
 
Back
Top Bottom