2014-04-16 10 views
6

Mam aplikację GDK, która działała poprawnie w XE12, ale teraz ulega awarii w XE16 po przejściu na GDK: 19. W szczególności wywołanie openOptionsMenu() w działaniu (w tym przypadku, aby otworzyć menu opcji na karcie aktywnej) powoduje, że BadTokenExceptions.Wywołanie metody openOptionsMenu() w XE16 powoduje, że WindowManager.BadTokenException

wyjście

Logcat:

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 

Sposób Służby, które wiąże się z działalnością, Live kartka:

@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. 
    } 

a problematyczną działalność:

/** 
* 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! 
    } 
} 

dotykając żywo przyczyn kartonowe natychmiastowa awaria, a wyjście Logcat powyżej jest zrzucane. Dziwne jest to, że skomentowane openOptionsMenu() jest odkomentowane, a istniejące openOptionsMenu() jest zakomentowane, pierwsze kliknięcie otworzy menu. Druga próba otwarcia menu zakończy się niepowodzeniem, z podobnym wyjściem Logcat (wyjątek BadTokenException jest głównym wyjątkiem zamiast wewnętrznego wyjątku w RuntimeException).

Odpowiedz

4

As petey said, ale trzeba zastąpić onAttachedToWindow()opróczonResume(). Mój kod wygląda teraz tak:

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

Odpowiedź z Dario w skylight1,

"próbki zostały zaktualizowane, a także - z Compass:" Dario

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

TY!

Powiązane problemy