1

私は、HTC Desire (Gingerbread 2.3.7) と Google Nexus 7 (Jelly Bean 4.3) で開発している Android プロジェクトに取り組んでいます。MainActivity から InfoActivity にデータを送信する必要があるため、インテントを使用します。この InfoActivity では、アクション バーに情報を更新するためのメニュー項目もあります。

ここに画像の説明を入力

InfoActivity では、ユーザーにデータを表示します。しかし、これは問題ではなく、問題はメニューにあります。次のコードを見てください。

public class ShowInfoActivity extends ActionBarActivity {

    private MenuItem menuItem   = null;
    // ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
        new OneTask().execute(...);
        // ...
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        case R.id.refresh:
            menuItem = item;
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private class OneTask extends AsyncTask<Object, Void, String> {
        // ...
        @Override
        protected void onPreExecute() {
            MenuItemCompat.setActionView(menuItem,
                        R.layout.actionbar_indeterminate_progress);
            MenuItemCompat.expandActionView(menuItem);
        }
        // ...
        @Override
        protected void onPostExecute(String result) {
            MenuItemCompat.collapseActionView(menuItem);
            MenuItemCompat.setActionView(menuItem, null);
        }
    }

明らかに、最初に実行されたときは menuItem=null なので、クラッシュするはずです。信じられないことに、HTC では正常に動作しますが、Nexus では明らかにクラッシュします。これがデバイス間で異なるのはなぜですか?

PS:私はすでに解決しましたが、なぜこの動作が起こるのか知りたいです...

4

2 に答える 2

1

疑問がある場合は、常にソース コードを確認してください。MenuItemCompat.java を見ると、次のように API レベルに基づいて切り替わることがわかります。

    static final MenuVersionImpl IMPL;
    static {
        final int version = android.os.Build.VERSION.SDK_INT;
        if (version >= 14) {
            IMPL = new IcsMenuVersionImpl();
        } else if (version >= 11) {
            IMPL = new HoneycombMenuVersionImpl();
        } else {
            IMPL = new BaseMenuVersionImpl();
        }
    }

基本実装 (2.3 デバイスで使用される) の基本 setActionView メソッドは MenuItem を返すだけなので、例外がスローされることはありません。

@Override
public MenuItem setActionView(MenuItem item, View view) {
    return item;
}

一方、HoneycombMenuVersionImpl は別のクラスに委譲します。

        @Override
        public boolean setShowAsAction(MenuItem item, int actionEnum) {
            MenuItemCompatHoneycomb.setShowAsAction(item, actionEnum);
            return true;
        }

また、デリゲート クラスは MenuItem で実際のメソッドを呼び出そうとしますが、例外がスローされます。

public static void setShowAsAction(MenuItem item, int actionEnum) {
    item.setShowAsAction(actionEnum);
}

この特定の例では、ソース コードを確認することで質問に答え、さまざまなバージョンの Android 間の互換性に対処するための確かな戦略を示しています。

于 2013-10-01T20:24:18.630 に答える
0

setActionView()/collapseActionView() は Android 4 のネイティブ関数です。null MenuItem を渡すと、確実に眉をひそめます。

Android 2.3 デバイスでは、互換性ライブラリ (android.support.v4) に setActionView()/collapseActionView() の独自の内部実装があり、不正な入力に対する回復力が高い可能性があります。

于 2013-10-01T18:13:13.920 に答える