Search code examples
androiddialogwindowactivity-finish

android: Is your activity running? Dialog box unable to show upon OnFinish


I have an view called SpotOnView, and is extending on Game_shooting_AB. Coding as follows.

Background:

In the SpotOnView there is a countdown timer. When the time is up, the game is over, and a dialog box will popup to ask whether the user would like to quit or play again.

SpotOnView Code:

public class SpotOnView extends View 
{
   ......
  // constructs a new SpotOnView
   public SpotOnView(Context context, RelativeLayout parentLayout)
   {
      super(context);          
      resources = context.getResources();            
      layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      ....    

   } 


   public void start_timer() 
   {
        if (!timerHasStarted) 
        {
            countDownTimer.start();
            timerHasStarted = true;
        } 
        else 
        {
            countDownTimer.cancel();
            timerHasStarted = false;
        }
   }

    public class MyCountDownTimer extends CountDownTimer 
    {
        public MyCountDownTimer(long startTime, long interval) 
        {
            super(startTime, interval);
        }

        @Override
        public void onFinish() 
        {
            text.setText("Time's up!");
               ((Game_shooting_AB)getContext()).replay_dialog();  //LINE 181
        }

        @Override
        public void onTick(long millisUntilFinished) 
        {
            ....
        }
    }

Game_shooting_AB Code:

   public void onCreate(Bundle savedInstanceState) 
   {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.game_shooting);

      // create a new SpotOnView and add it to the RelativeLayout
      RelativeLayout layout = (RelativeLayout) findViewById(R.id.relativeLayout);
      view = new SpotOnView(this, layout);                                          //EXTENDING HERE
      layout.addView(view, 0); // add view to the layout
    ....
}



public void replay_dialog()    
{
    final Dialog dialog1 = new Dialog(Game_shooting_AB.this, android.R.style.Theme_Translucent_NoTitleBar);
    WindowManager.LayoutParams lp = dialog1.getWindow().getAttributes();
    lp.dimAmount = 0.7f;
    dialog1.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

    Window window = dialog1.getWindow();
    window.setGravity(Gravity.CENTER);

    dialog1.setContentView(R.layout.alert_dialog_replay_shooting);
    dialog1.setCancelable(false);
    dialog1.show();     //LINE 431
    ....

Logcat:

The necessary line numbers have added as comment in the above codes.

11-22 00:16:34.365: W/dalvikvm(1105): threadid=1: thread exiting with uncaught exception (group=0x41f342a0)
11-22 00:16:34.370: E/AndroidRuntime(1105): FATAL EXCEPTION: main
11-22 00:16:34.370: E/AndroidRuntime(1105): android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@43304558 is not valid; is your activity running?
11-22 00:16:34.370: E/AndroidRuntime(1105):     at android.view.ViewRootImpl.setView(ViewRootImpl.java:708)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:346)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at android.view.Window$LocalWindowManager.addView(Window.java:554)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at android.app.Dialog.show(Dialog.java:277)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at com.app.abc.Game_shooting_AB.replay_dialog(Game_shooting_AB.java:431)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at com.app.abc.SpotOnView$MyCountDownTimer.onFinish(SpotOnView.java:181)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at android.os.CountDownTimer$1.handleMessage(CountDownTimer.java:118)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at android.os.Handler.dispatchMessage(Handler.java:99)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at android.os.Looper.loop(Looper.java:137)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at android.app.ActivityThread.main(ActivityThread.java:4898)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at java.lang.reflect.Method.invokeNative(Native Method)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at java.lang.reflect.Method.invoke(Method.java:511)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1008)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:775)
11-22 00:16:34.370: E/AndroidRuntime(1105):     at dalvik.system.NativeStart.main(Native Method)

Question:

The logcat shows is your activity running?

  1. I know that the dialog need to have a base to showup. But how could the code be modified?

  2. Would it be possible to code and show the dialog in the SpotOnView instead of writing in the Game_shooting_AB code?

  3. I have tried to modify the code by moving the class MyCountDownTimer and method replay_dialog back to Game_shooting_AB, but the same error still comes out. I would like to ask whether the OnFinish of the MyCountDownTimer will bring the Activity to finish such that the dialog does not able to find base to be shown on?

Thanks so much!!


Solution

  • The problem started from "((Game_shooting_AB)getContext()).replay_dialog();" this line of code.

    As you will find from documentation of android when you call getContext() from inside of a view you get "The view's Context.". Now what you are doing is casting that context to Game_shooting_AB which is not good since that might or might not be the Activity's context. Checkout Romain Guy's answer about this. Thus android is telling you "is your activity running?".

    Now to solve your current problem you can pass your activity instance to this view via any public method and have it store in a local variable.

    Adjust your code like this:

    public class SpotOnView extends View 
    {
      Game_shooting_AB mGame_shooting_AB;
      public void setGame_shooting_AB(Game_shooting_AB mGame_shooting_AB){
       this.mGame_shooting_AB = mGame_shooting_AB;
      }
       ......
       // constructs a new SpotOnView
      public SpotOnView(Context context, RelativeLayout parentLayout)
      {
       super(context);          
       resources = context.getResources();            
        layoutInflater = (LayoutInflater)          context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      ....    
    
      } 
    
    
      public void start_timer() 
      {
        if (!timerHasStarted) 
        {
            countDownTimer.start();
            timerHasStarted = true;
        } 
        else 
        {
            countDownTimer.cancel();
            timerHasStarted = false;
        }
      }
    
    public class MyCountDownTimer extends CountDownTimer 
    {
        public MyCountDownTimer(long startTime, long interval) 
        {
            super(startTime, interval);
        }
    
        @Override
        public void onFinish() 
        {
            text.setText("Time's up!");
               mGame_shooting_AB.replay_dialog();  //LINE 181
        }
    
        @Override
        public void onTick(long millisUntilFinished) 
        {
            ....
        }
    }
    

    After you get the instance of SpotOnView set the activity:

          view = new SpotOnView(this, layout);                                          //EXTENDING HERE
      layout.addView(view, 0); // add view to the layout
      view.setGame_shooting_AB(Game_shooting_AB.this);
    

    Hope this helps.