Question

I have a foreground service that checks stock quotes every 5 minutes. This service is passed a Messenger from the parent FragmentActivity which starts it.

The stock quote checking service passes a Message back to this Handler which is an inner non-static class of the parent FragmentActivity:

private class YahooServiceHandler extends Handler {

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {

            case App.QUOTE_UPDATE_FINISHED:

                Bundle bundle = msg.getData();
                mTickerQuoteIds = bundle.getStringArray("ticker_quote_ids");

                // I need this class to be an inner non-static class to do
                // references to the other fragments this activity hosts.  

                QuoteListFragment quoteListFragment = (QuoteListFragment)mAdapter
                        .getRegisteredFragment(1);

                quoteListFragment.mLoader.onContentChanged();

                // This loops through some Ids returned in the Message to show
                // dialogs for quotes that have passed their price limits

                if (mTickerQuoteIds != null && mTickerQuoteIds.length > 0) {

                    for (int i = 0; i < mTickerQuoteIds.length; i++) {

                        String[] tickerQuoteId = mTickerQuoteIds[i].split("\\|");

                        FragmentManager fm = getSupportFragmentManager();
                        Bundle bundleArgs = new Bundle();
                        bundleArgs.putString("quote_id", tickerQuoteId[1]);
                        bundleArgs.putString("ticker_id", tickerQuoteId[0]);
                        TickerDialog tickerAlertDialog = new TickerDialog();
                        tickerAlertDialog.setArguments(bundleArgs);
                        tickerAlertDialog.show(fm, "fragment_ticker_alert");

                    }

                    mTickerQuoteIds = null;
                }

                Toast.makeText(TabActivity.this, "Quotes refreshed", Toast.LENGTH_SHORT).show();

                break;
            default:
                super.handleMessage(msg);
        }
    }

Of course, because the service loops every 5 minutes, users often push the home button which causes onSaveInstanceState() to be called. If this occurs, and the service tries to show the DialogFragment through the Handler (at some time in the future), I get an IllegalStateException:

03-27 01:44:44.531: E/AndroidRuntime(2143): FATAL EXCEPTION: main
03-27 01:44:44.531: E/AndroidRuntime(2143): Process: com.ootpapps.stocktalker, PID: 2143
03-27 01:44:44.531: E/AndroidRuntime(2143): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
03-27 01:44:44.531: E/AndroidRuntime(2143):     at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1343)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1361)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:595)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:574)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at android.support.v4.app.DialogFragment.show(DialogFragment.java:127)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at com.ootpapps.stocktalker.TabActivity$YahooServiceHandler.handleMessage(TabActivity.java:72)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at android.os.Handler.dispatchMessage(Handler.java:102)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at android.os.Looper.loop(Looper.java:136)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at android.app.ActivityThread.main(ActivityThread.java:5017)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at java.lang.reflect.Method.invokeNative(Native Method)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at java.lang.reflect.Method.invoke(Method.java:515)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
03-27 01:44:44.531: E/AndroidRuntime(2143):     at dalvik.system.NativeStart.main(Native Method)

I'm pretty sure the problem here is with the inner non-static nature of my Handler. The logic works flawlessly if the hosting FragmentActivity is in the foreground, but, if the user hit the home button at any time (as just one example), the IllegalStateException occurs upon trying to show() the DialogFragment.

I'd appreciate a push in the right direction, thank you!

Was it helpful?

Solution

So, I'd like to answer my question on how to make this possible in the easiest way.

My objective was to display a DialogFragment whenever the Service requested. The difficulty with this, is that my Handler was an inner-class to the Activity that hosts the DialogFragment, this was causing LifeCycle issues when I tried to call the DialogFragment.

To achieve this with essentially next to no work, I created a transparent Activity that looks like a Dialog, instead of using the DialogFragment. This simplified everything because I don't have to worry about an IllegalStateException when starting an Activity. So everything works as intended now!

Thanks for the suggestions, but ultimately, if you come across this exception, see if you can simply create a dummy Activity to launch your target Fragment from. This will simplify the LifeCycle issue tremendously!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top