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
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).