4

コード内で再現が難しい問題を見つけようとしています。モンキーツールを使用しました。しかし、ここでは、問題はAndroidスピナーの内部にあるようです。それはAPI/フレームワークの問題ですか?同じ結果でもう一度試してみました。

// CRASH: com.panguso.mobile.client (pid 11171)
// Short Msg: java.lang.NullPointerException
// Long Msg: java.lang.NullPointerException
// Build Label: google/soju/crespo:4.1.1/JRO03E/403059:user/release-keys
// Build Changelist: 403059
// Build Time: 1342214487000
// java.lang.NullPointerException
//  at android.widget.Spinner$DialogPopup.dismiss(Spinner.java:828)
//  at android.widget.Spinner$DialogPopup.onClick(Spinner.java:862)
//  at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:924)
//  at android.widget.AdapterView.performItemClick(AdapterView.java:298)
//  at android.widget.AbsListView.performItemClick(AbsListView.java:1086)
//  at android.widget.AbsListView.onKeyUp(AbsListView.java:2996)
//  at android.widget.ListView.commonKey(ListView.java:2196)
//  at android.widget.ListView.onKeyUp(ListView.java:2051)
//  at android.view.KeyEvent.dispatch(KeyEvent.java:2633)
//  at android.view.View.dispatchKeyEvent(View.java:7086)
//  at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1354)
//  at android.widget.ListView.dispatchKeyEvent(ListView.java:2026)
//  at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1358)
//  at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1358)
//  at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1358)
//  at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1358)
//  at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1358)
//  at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:1892)
//  at com.android.internal.policy.impl.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1369)
//  at android.app.Dialog.dispatchKeyEvent(Dialog.java:702)
//  at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1819)
//  at android.view.ViewRootImpl.deliverKeyEventPostIme(ViewRootImpl.java:3575)
//  at android.view.ViewRootImpl.deliverKeyEvent(ViewRootImpl.java:3531)
//  at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3113)
//  at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4153)
//  at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4132)
//  at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4224)
//  at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
//  at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
//  at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:163)
//  at android.view.ViewRootImpl.doConsumeBatchedInput(ViewRootImpl.java:4203)
//  at android.view.ViewRootImpl$ConsumeBatchedInputRunnable.run(ViewRootImpl.java:4243)
//  at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
//  at android.view.Choreographer.doCallbacks(Choreographer.java:555)
//  at android.view.Choreographer.doFrame(Choreographer.java:523)
//  at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
//  at android.os.Handler.handleCallback(Handler.java:615)
//  at android.os.Handler.dispatchMessage(Handler.java:92)
//  at android.os.Looper.loop(Looper.java:137)
//  at android.app.ActivityThread.main(ActivityThread.java:4745)
//  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:786)
//  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
//  at dalvik.system.NativeStart.main(Native Method)
// 
** Monkey aborted due to error.
Events injected: 1801
:Sending rotation degree=0, persist=false
:Dropped: keys=5 pointers=0 trackballs=0 flips=0 rotations=0
## Network stats: elapsed time=17738ms (0ms mobile, 17738ms wifi, 0ms not connected)
** System appears to have crashed at event 1801 of 10000 using seed 0
4

2 に答える 2

4

あなたが投稿したスタックトレースはあなたのコード内のクラスについて言及していません。つまり、この問題は少なくともあなたが直接引き起こしたものではありません。

コードがたどるパスであるため、スタックトレースを下から上に少し分析します(そのスタックトレースのソースコードはhttp://www.grepcode.com/?st=trueを使用して見つけることができます)。

...
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)

モンキーは、ソフト/ハードキーボードで生成できるようなキーイベントを発行します。

次に、キーイベントは、アプリのコンテンツとActionBarを含むDecorViewに転送されます。イベントをにDecorView転送しDialogます。

...
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:1819)
at android.app.Dialog.dispatchKeyEvent(Dialog.java:702)

ここから、ビュー階層を通過して、ListView

at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1358)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1358)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1358)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1358)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1358)
at android.widget.ListView.dispatchKeyEvent(ListView.java:2026)
at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1354)
at android.view.View.dispatchKeyEvent(View.java:7086)
at android.view.KeyEvent.dispatch(KeyEvent.java:2633)
at android.widget.ListView.onKeyUp(ListView.java:2051)
at android.widget.ListView.commonKey(ListView.java:2196)

キーをそのListViewコンテンツに転送します。これはaのように見え、クリックすると、これが表示する(ドロップダウンリスト)にSpinneraがトリガーされるように見えます。.dismiss()DialogSpinner

at android.widget.AbsListView.onKeyUp(AbsListView.java:2996)
at android.widget.AbsListView.performItemClick(AbsListView.java:1086)
at android.widget.AdapterView.performItemClick(AdapterView.java:298)
at com.android.internal.app.AlertController$AlertParams$3.onItemClick(AlertController.java:924)
at android.widget.Spinner$DialogPopup.onClick(Spinner.java:862)
at android.widget.Spinner$DialogPopup.dismiss(Spinner.java:828)

Spinnerコードに言及していないスタックトレースは、システムUI、つまりActionBarの一部である可能性があります。

例
(ソース:android.com

(ここから取られた)画像で見ることができるように、Spinner(日付を示す)とDialogListView日、週、...)が下にあります。アイテムの1つ、スピナー自体、または外部のどこかをクリックすると、ダイアログが閉じます。

NullPointerException次のコードで発生します

public void dismiss() {
    mPopup.dismiss();  // Spinner.java:828
    mPopup = null;
}

mPopup明らかにnullです。これは、ポップアップが設定されているため、以前にポップアップが表示されなかった場合にのみ発生します。

public void show() {
    AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
    if (mPrompt != null) {
        builder.setTitle(mPrompt);
    }
    mPopup = builder.setSingleChoiceItems(mListAdapter,
            getSelectedItemPosition(), this).show();
}

それはAPI/フレームワークの問題ですか?

わかりませんが、サルは通常のユーザーが必ずしも到達できないものをクリックすることができ、ユーザーがクリックできない時間/速度でクリックすることができます。したがって、この問題は、APIプログラマーが予測/テストしなかった方法でクリックすることによって引き起こされる可能性があります。スタックトレースは純粋にフレームワークであり、他の場所でチェックしますが、ここではチェックしないため、特に可能nullですmPopup

しかし、その可能性に加えて、それはあなたのコードにも関連している可能性があります。レイアウト(またはActionBar)のどこかに追加して、Spinner意図していないことを実行した可能性があります。また、デフォルトの動作(特にキーイベント処理)をオーバーライドしない場合、フレームワークはコードにジャンプする必要がなく、まったく同じスタックトレースを生成すると思います。

于 2012-08-20T12:08:25.203 に答える
0

残念ながら、すべてのAndroidデバイスで同じ問題が発生しています。この回答には、さらに詳しく説明したいという仮説があります。

しかし、これは奇妙な部分です。DialogPopupがOnClickListenerとして設定されているため、スタックトレースはmPopupのアイテムがクリックされたときのようです。したがって、その時点でmPopupはnullであってはなりません。ただし、DialogPopup.dismiss()の場合はnullです。

何がそれを説明できますか?これが私の仮説です。まあ、猿は通常かなり速いです。実際のユーザーよりも高速です。mPopupが最初のDialogPopup.onClick()によって実際に却下される前に、2つのアイテムをクリックできる可能性があります。したがって、DialogPopup.dismiss()を2回呼び出し、2回目はNPEを呼び出します。

このバグがまだアクティブであることを考えると、この問題を回避するための解決策を考え出す時が来たと思います。これも私が気付いたいくつかのことです:

  1. エミュレータでmonkeytesterを実行しているとき、スピナーnullpointerのバグが原因でクラッシュすることはありません。エミュレーターはAndroidデバイスよりもかなり遅く、モンキーテスターはクラッシュを引き起こすのに十分な速さでタッチイベントを発行できないため、これは真実だと思います。

  2. モンキーテスターでAndroidデバイスを使用する場合、同じシードを使用すると、ほとんどの場合、同じクラッシュが発生します。デバイスはシードごとに同じ疑似ランダムタッチイベントを受信するため、これは理にかなっています。0シードを使用することはもうありません。これは、ほとんどの場合、2、3回のタッチイベントの後にクラッシュが発生するためです。


回避策

私が行ったすべての検索から、問題の実際の解決策はありません。しかし、クラッシュを回避するためにできることがいくつかあります。

  1. エミュレーターを使用して、数分より長く続くテストを実行します。エミュレーターのパフォーマンスは実際のデバイスよりもはるかに遅いため、モンキーテスターはクラッシュを引き起こすのに十分な速度でコマンドを発行できません。Intelハードウェアアクセラレータ(HAXM)を使用している場合は、それを使用しないAVDを作成することをお勧めします。AVDが起動するのを永遠に待つ必要がないように、スナップショットを有効にし、GPUアクセラレーションを無効にしてください。

  2. 実際のデバイスでテストする場合は、必ず--throttle <millis>パラメーターをモンキーテスターに​​渡してください。ドキュメントからの定義は次のとおりです。

    イベント間に固定遅延を挿入します。このオプションを使用して、Monkeyの速度を落とすことができます。指定しない場合、遅延は発生せず、イベントは可能な限り迅速に生成されます。

以下を使用するコマンドの例を次に示し--throttleます。

adb -s shell monkey --throttle 200 -p com.your.package -v 500000

デバイスに最適な遅延を見つけるようにしてください。私のSamsungGalaxyNexusの場合、クラッシュを防ぐために、遅延はほぼ1秒である必要があります。これは言うまでもありませんが、遅延が長ければ長いほど、サルのテストを完了するのに時間がかかります。これが、デバイスがクラッシュしていないが、非常に遅くならない値を見つけることが重要である理由です。

于 2014-01-14T04:41:01.113 に答える