2014-04-16 3 views
6

Ich habe eine GDK-App, die in XE12 funktionierte, aber jetzt in XE16 abstürzt nach dem Übergang zu GDK: 19. Insbesondere verursacht das Aufrufen von openOptionsMenu() in einer Aktivität (in diesem Fall zum Öffnen eines Optionsmenüs auf einer Live-Karte) BadTokenExceptions.Aufruf von openOptionsMenu() in XE16 verursacht WindowManager.BadTokenException

Logcat Ausgang:

04-16 03:36:43.197: E/AndroidRuntime(2465): FATAL EXCEPTION: main 
04-16 03:36:43.197: E/AndroidRuntime(2465): Process: com.voidstar.glass.sample.pinDrop, PID: 2465 
04-16 03:36:43.197: E/AndroidRuntime(2465): java.lang.RuntimeException: Unable to resume activity {com.voidstar.glass.sample.pinDrop/com.voidstar.glass.sample.pinDrop.MenuActivity}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running? 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2828) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2857) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2290) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.app.ActivityThread.access$800(ActivityThread.java:138) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1236) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.os.Handler.dispatchMessage(Handler.java:102) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.os.Looper.loop(Looper.java:149) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.app.ActivityThread.main(ActivityThread.java:5061) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at java.lang.reflect.Method.invokeNative(Native Method) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at java.lang.reflect.Method.invoke(Method.java:515) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:610) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at dalvik.system.NativeStart.main(Native Method) 
04-16 03:36:43.197: E/AndroidRuntime(2465): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running? 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.view.ViewRootImpl.setView(ViewRootImpl.java:561) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:259) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at com.android.internal.policy.impl.PhoneWindow.openPanel(PhoneWindow.java:693) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at com.android.internal.policy.impl.PhoneWindow.openPanel(PhoneWindow.java:555) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.app.Activity.openOptionsMenu(Activity.java:2878) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at com.voidstar.glass.sample.pinDrop.MenuActivity.onResume(MenuActivity.java:71) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1194) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.app.Activity.performResume(Activity.java:5316) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2818) 
04-16 03:36:43.197: E/AndroidRuntime(2465):  ... 12 more 

Methode in Service, der die Aktivität auf die Live-Karte bindet:

@Override 
    public int onStartCommand(Intent intent, int flags, int startId) {  
     // This method is called whenever the Glassware is invoked via voice commands or the OK Glass menu. 
     if (mLiveCard == null) {  
      Log.d(TAG, "Connecting mLocationManager"); 

      Criteria criteria = new Criteria(); 
      criteria.setAccuracy(Criteria.ACCURACY_COARSE); 

      PinDropLocationListener listener = new PinDropLocationListener(); 
      locationListeners.add(listener); 
      mLocationManager.requestSingleUpdate(criteria, listener, null); 

      mLiveCard = new LiveCard(getBaseContext(), LIVE_CARD_TAG); 
      mLiveCard.setViews(new RemoteViews(getPackageName(), R.layout.activity_waiting)); 
      mLiveCard.attach(this); // Prevent this Service from being killed to free up memory 

      Intent menuIntent = new Intent(this, MenuActivity.class); // Since menus can only be attached to Activities, we create an activity to own and launch the menu. 
      menuIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 
      mLiveCard.setAction(PendingIntent.getActivity(this, 0, menuIntent, 0)); // This Intent will be fired whenever the LiveCard is tapped. 

      Log.d(TAG, "Publishing LiveCard"); 
      mLiveCard.publish(PublishMode.REVEAL); // Add the LiveCard to the Timeline and switch to it 
      Log.d(TAG, "Done publishing LiveCard"); 
     } else { 
      mLiveCard.navigate(); // Switch to the app if it's already running 
     } 

     return START_STICKY; // No idea what this does. Your guess is as good as mine. 
    } 

Und die problematische Aktivität:

/** 
* Activity showing the options menu. 
*/ 
public class MenuActivity extends Activity { 
    // This is technically an Immersion! 
    // Because Services have no UI, we need to open this Activity, which in turn opens its menu! 

    PinDropService.MenuBinder mBinder; 

    private static String TAG = "PinDropMenu"; 

    boolean hasLocation; 

    /* 
    * Links this Activity to the Service that spawned it, so the Menu can send and receive information 
    */ 
    private ServiceConnection mConnection = new ServiceConnection() { 

     @Override 
     public void onServiceConnected(ComponentName name, IBinder service) { 
      if (service instanceof PinDropService.MenuBinder) { 
       mBinder = (PinDropService.MenuBinder)service; 
       hasLocation = mBinder.hasLocation(); 
       Log.d(TAG, hasLocation ? "Received has location" : "Received no location"); 
       //openOptionsMenu(); 
      } 
     } 

     @Override 
     public void onServiceDisconnected(ComponentName name) {} 
    }; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     bindService(new Intent(this, PinDropService.class), mConnection, 0); 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
     openOptionsMenu(); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     MenuInflater inflater = getMenuInflater(); 
     inflater.inflate(R.menu.pindropmenu, menu); 
     return true; 
    } 

    @Override 
    public boolean onPrepareOptionsMenu(Menu menu) { 
     if (!hasLocation) { 
      menu.findItem(R.id.directions).setVisible(false); 
      menu.findItem(R.id.remember).setVisible(false); 
     } 
     else { 
      menu.findItem(R.id.directions).setVisible(true); 
      menu.findItem(R.id.remember).setVisible(true); 
     } 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle item selection. 
     switch (item.getItemId()) { 
      case R.id.directions: 
       mBinder.startNavigation(); 
       return true; 
      case R.id.remember: 
       mBinder.addToTimeline(); // TODO: Add Mirror functionality! 
       return true; 
      case R.id.stop: // IT IS CRITICALLY IMPORTANT TO ADD THIS OR THE GLASSWARE CAN'T BE KILLED IN USERSPACE! 
       stopService(new Intent(this, PinDropService.class)); 
       return true; 
      default: 
       return super.onOptionsItemSelected(item); 
     } 
    } 

    @Override 
    public void onOptionsMenuClosed(Menu menu) { 
     // Nothing else to do, closing the Activity. 
     finish(); 
    } 

    @Override 
    public void onStop() { 
     super.onStop(); 
     unbindService(mConnection); // Don't leak Services! 
    } 
} 

die Live-Karte Ursachen Tapping ein sofortiger Absturz, und die obige Logcat-Ausgabe wird ausgegeben. Was komisch ist, ist, dass, wenn das auskommentierte openOptionsMenu() unkommentiert ist und das existierende openOptionsMenu() auskommentiert ist, das erste Tippen das Menü öffnet. Der zweite Versuch, das Menü zu öffnen, schlägt mit ähnlicher Logcat-Ausgabe fehl (die BadTokenException ist die Hauptausnahmebedingung anstelle einer inneren Ausnahme bei RuntimeException).

Antwort

4

As petey said, aber Sie müssenonResume()onAttachedToWindow()zusätzlich außer Kraft zu setzen. Mein Code sieht nun ungefähr so ​​aus:

private boolean isAttached = false; 

@Override 
public void onAttachedToWindow() { 
    super.onAttachedToWindow(); 
    this.isAttached = true; 
    openOptionsMenu(); 
} 

@Override 
public void onResume() { 
    super.onResume(); 
    if (this.isAttached) 
    openOptionsMenu(); 
} 
5

Antwort von dario in skylight1,

"-Proben wurden ebenfalls aktualisiert - von Compass:"

@Override 
public void onAttachedToWindow() { 
    super.onAttachedToWindow(); 
    mAttachedToWindow = true; 
    openOptionsMenu(); 
} 

TY dario!