0

私は Android (4.1) アプリケーションを持っていますが、これは "アプリが停止しました" というメッセージでクラッシュする (再作成できない) と報告されています。ただし、問題は、ユーザーがポップアップするアラートで [OK] を押さなければならないことです。クラッシュは、アプリが (画面上で) アクティブでない場合にのみ発生します。これは、メモリまたはいたずらのために Android がアプリを強制終了していることを示しています。アプリでビットマップを処理しているため、メモリリークを調査していましたが、それは報われませんでした。

次のようなすべてのデフォルトハンドラーをキャッチしてログに記録します。

Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            public void uncaughtException(Thread thread, Throwable ex) {
                Log.e(StaticData.LogTag, "Unhandled exception app", ex);
            }
        });

すべての例外をログに記録します。その後、元の例外ハンドラを呼び出します。このハンドラーは、アプリのメイン アクティビティに配置されます。「停止した」クラッシュが発生した場合、このメソッドは呼び出されませんが、それ以外の場合は呼び出されます。

私のアプリは IntentService を使用して、バックグラウンドでサーバーにデータを送信します。これは 1 ~ 10 秒の長時間実行されるサービスではありません。サービスにもデフォルトの例外ハンドラーを配置しようとします。「画面外」のときにアプリが強制終了されるため、サービスについて言及するので、それが問題に関係しているのではないかと考えましたが、原因は私を回避します。

さらに、アプリは乱流のネットワーク条件で使用されるため、BroadcastReceiver を使用して、ネットワーク接続の変更についてアプリのメイン アクティビティに通知します。人々がメモリ リークの問題の可能性について話しているときに BroadcastReceiver が言及されているのを見たので、これは関連しています。BradcastReceiver の私の実装は次のようになります。

サービス側:

sendOrderedBroadcast(uploadedIntent, null);

活動面:

public static class NetworkStateReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent in) {
        // super.onReceive(context, intent);
        Log.d(StaticData.LogTag, "Network connectivity change");
        if (in.getExtras() != null) {
            NetworkInfo ni = (NetworkInfo) in.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);
            if (ni != null && ni.getState() == NetworkInfo.State.CONNECTED) {
                Log.i(StaticData.LogTag, "Network " + ni.getTypeName() + " connected");
                ...                 
            }
        }
        if (in.getExtras().getBoolean(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE)) {
            Log.d(StaticData.LogTag, "There's no network connectivity");
        }
    }
}

冒頭で述べたように、この問題は主にユーザーにとって煩わしいものです。ユーザーはメールを見たり電話をかけたりするときにポップアップで [OK] を押さなければならないからです。このアプリは、時々強制終了されることを処理するのに十分な堅牢性を備えていますが、アプリがノックアウトされる理由を突き止めたいと思います。

PS。mx log logcollector を介してユーザーにバグ レポートを送信してもらうようにしましたが、葉巻は送信しませんでした。

4

1 に答える 1

0

私はこの問題を解決したようです。犯人は、アプリケーションのメイン アクティビティへの静的な参照だったと思います。この静的を使用して、アプリケーションのコンテキストへの参照を取得していました。ただし、これは Service と BroadcastReceiver では不要です。これらには「コンテキスト」への独自の参照があるためです。

なぜ長い顔?

アクティビティなどの Android ビューへの静的参照はメモリに保持され、ガベージ コレクターによって解放することはできません。これが、静的にすることの背後にあるアイデアでした。オブジェクトへの将来の参照が必要でしたが、それは間違ったアプローチです。

方向を変更すると (例)、Android は現在のアクティビティ (および子ビュー) を再作成し、古いアクティビティは GC 用に解放されます。ビューへの静的参照がある場合、それは収集されず、アクティビティのインスタンスが 2 つになりました。計算を行って、これが時間の経過とともに明らかにメモリをいっぱいにし (リーク)、Android がある時点でアプリを破壊することを理解してください。

この問題に直面した場合、たとえば共有メモリ、ローカル データベース、または savedInstanceState を使用して、データ/状態を新しいアクティビティに引き継ぐ必要があることを認識する必要があります。

@Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (savedInstanceState != null) {
       int value = savedInstanceState.getInteger("key");
    }
}
@Override
protected void onSaveInstanceState(final Bundle outState) {
    outState.putInteger("key", value);
}
于 2013-10-24T12:45:51.263 に答える