LoginSignup
18
17

More than 5 years have passed since last update.

ActionBar を持たないテーマを設定した Activity でやっておかないと悲しいクラッシュに遭遇した話

Posted at

テーマとして、android:windowNoTitle="true"を設定することで、ActionBar を表示させないようにすることができます。

こうすると、ActionBar を持たない Activity が出来上がるため、Activity#getActionBar()Activity#getSupportActionBar()nullを返すようになります。

この場合、以下の点について気をつけていないと、見に覚えのないクラッシュログに苛まれることになります。

メニューキーを無効化する

メニューキーは、すなわち ActionItem の OverFlow の中身を呼び出す機能として使われます。

つまり、ActionBar の機能を使おうとします。

しかし、android:windowNoTitle="true"なテーマの Activity では、ActionBar そのものが生成されないので、メニューキーのハンドリングをした時に NullPointerException となってしまいます。

例えば、以下の様なクラッシュレポートが来た場合、まさにこのような状況にあると言えます。

java.lang.NullPointerException
    at android.support.v7.a.r.b(ActionBarImplICS.java:219)
    at android.support.v7.a.r.(ActionBarImplICS.java:52)
    at android.support.v7.a.r.(ActionBarImplICS.java:41)
    at android.support.v7.a.l.a(ActionBarActivityDelegateICS.java:47)
    at android.support.v7.a.g.b(ActionBarActivityDelegate.java:81)
    at android.support.v7.a.f.getMenuInflater(ActionBarActivity.java:71)
    at android.app.Activity.onCreatePanelMenu(Activity.java:2445)
    at android.support.v4.app.q.onCreatePanelMenu(FragmentActivity.java:224)
    at android.support.v7.a.f.a(ActionBarActivity.java:232)
    at android.support.v7.a.l.a(ActionBarActivityDelegateICS.java:147)
    at android.support.v7.a.f.onCreatePanelMenu(ActionBarActivity.java:199)
    at android.support.v7.a.m.onCreatePanelMenu(ActionBarActivityDelegateICS.java:285)
    at com.android.internal.policy.impl.PhoneWindow.preparePanel(PhoneWindow.java:388)
    at com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel(PhoneWindow.java:779)
    at com.android.internal.policy.impl.PhoneWindow.onKeyDown(PhoneWindow.java:1444)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1833)
    at android.view.ViewRootImpl.deliverKeyEventPostIme(ViewRootImpl.java:3466)
    at android.view.ViewRootImpl.handleFinishedEvent(ViewRootImpl.java:3439)
    at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2577)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4475)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:559)
    at dalvik.system.NativeStart.main(Native Method)

この回避策として、メニューキーを無効化する手段があります。


    @Override // avoid inflating menu without action bar
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ( keyCode == KeyEvent.KEYCODE_MENU ) {
            // do nothing
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

WebView の LongClick を無効化する

WebView は、デフォルトで長押しのイベントをハンドリングし、テキストの選択状態を取り扱うことが出来るようになります。
すると、テキストが選択状態になった時、Contextual ActionBar が有効になります。

つまり、ActionBar の機能を使おうとします。

しかし、前述のとおり ActionBar のインスタンスは無いので、またしても NullPointerException となります。

例えば、以下の様なクラッシュレポートが来た場合、まさにこのような状況にあると言えます。

java.lang.NullPointerException
    at android.support.v7.a.r.b(ActionBarImplICS.java:219)
    at android.support.v7.a.r.(ActionBarImplICS.java:52)
    at android.support.v7.a.r.(ActionBarImplICS.java:41)
    at android.support.v7.a.l.a(ActionBarActivityDelegateICS.java:47)
    at android.support.v7.a.g.b(ActionBarActivityDelegate.java:81)
    at android.support.v7.a.g.k(ActionBarActivityDelegate.java:205)
    at android.support.v7.a.l.a(ActionBarActivityDelegateICS.java:196)
    at android.support.v7.a.m.onActionModeStarted(ActionBarActivityDelegateICS.java:351)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.startActionMode(PhoneWindow.java:2255)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.startActionModeForChild(PhoneWindow.java:2178)
    at android.view.ViewGroup.startActionModeForChild(ViewGroup.java:571)
    at android.view.ViewGroup.startActionModeForChild(ViewGroup.java:571)
    at android.view.ViewGroup.startActionModeForChild(ViewGroup.java:571)
    at android.view.View.startActionMode(View.java:3607)
    at android.webkit.WebView.setUpSelect(WebView.java:6103)
    at android.webkit.WebView.selectText(WebView.java:4873)
    at android.webkit.WebView.selectText(WebView.java:4866)
    at android.webkit.WebView.performLongClick(WebView.java:4851)
    at android.webkit.WebView$PrivateHandler.handleMessage(WebView.java:9422)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4475)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:792)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:559)
    at dalvik.system.NativeStart.main(Native Method)

WebView の長押しを無効化するには、以下のようにします。

WebView webview = ...'
webview.setLongClickable(false);
webview.setOnLongClickListener(new OnLongClickListener() {
    @Override
    public boolean onLongClick(View view) {
        return true; // successfully handled.
    }
});
18
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
17