1

少し前に書いたゲームにはANRの問題があり、デバッグでは、HTTPリクエストに時間がかかる(したがってANRが発生する)ことが示唆されています。

ハンドラー内から呼び出されるRunnableにHTTPコードを割り当てることで、ANRを回避できると思いましたが、そうではないようです。

スタックダンプは、ランナブル/ハンドラーコードがまだ「メイン」スレッド内で実行されていることを示唆しているため、ANRが発生しますか?

実行しているタスクは非同期(ハイスコアと実績のアップロード)であるため、開始して独自のデバイスに完全に任せることができます-ANRが問題にならないように、これを実装するための最良の方法は何ですか?

あるトピックでは、ハンドラーはゲームのアクティビティ内ではなく、アプリケーションクラスで作成する必要があると提案されましたが、これらのケースの違いについての詳細は見つかりませんか?

すべてのアイデアは大いに感謝しています。

psはこれを拡張して質問します-HTTPに関連するANRは、これらの要求にSHORTタイムアウトを設定したため、電話がアウトオブサービス/ネットワーク/ WiFiになっていると思います(これらは必須ではなく、後で再試行しました!?)

4

2 に答える 2

3

Aは、現在のスレッドでデフォルト( egのHandlerないコンストラクター)ごとにコードを実行/メッセージを処理します。ほとんどの場合、これがメインスレッドです。別のスレッドで実行する場合は、使用するスレッドを指定する必要があります。Loopernew Handler()Looper

Androidには、を使用HandlerThreadしてを作成するThreadというユーティリティクラスがありますLooper

簡単な例:

public class MyActivity extends Activity {
    private Handler mHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        HandlerThread handlerThread = new HandlerThread("background-handler");
        handlerThread.start();
        Looper looper = handlerThread.getLooper();
        mHandler = new Handler(looper);

        mHandler.post(new Runnable() {
            public void run() {
                // code executed in handlerThread
            }
        });
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // stops the HandlerThread
        mHandler.getLooper().quit();
    }
}

タスクに必要な情報が一部であり、報告する必要がない場合は、を使用しIntentServiceます。アクティビティライフサイクルでアクティビティが再作成されても、それらは怒りません。

Service独自のファイルに小さなファイルを作成します

public class SaveService extends IntentService {
    public SaveService() {
        super("SaveService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        if ("com.example.action.SAVE".equals(intent.getAction())) {
            String player = intent.getStringExtra("com.example.player");
            int score = intent.getIntExtra("com.example.score", -1);
            magicHttpSave(player, score); // assuming there is an implementation here
        }
    }
}

に追加しますAndroidManifest.xml

<application ....

    <service android:name=".SaveService" />
</application>

そしてあなたのコードでそれを始めてください

Intent intent = new Intent(this /* context */, SaveService.class);
intent.setAction("com.example.action.SAVE");
intent.putExtra("com.example.player", "John123");
intent.putExtra("com.example.score", 5123);
startService(intent);

IntentService#onHandleIntent()すでにバックグラウンドスレッドで実行されているので、気にする必要はありません。

于 2012-11-13T21:35:22.670 に答える
1

ハンドラーはメインスレッドで実行されます。それがANRの原因です。アプリケーションで作成した場合でも、デフォルトでは(ハンドラーにパラメーターが指定されていない)メインスレッドで作成されます。独自のスレッドでルーパーを作成する必要があります。ここを参照してください

独自のルーパーで初期化されたハンドラー。これは、ANRを解決するための実行可能なオプションです...

より単純な代替ソリューションは、非同期ネットワーク操作をAsyncTaskに配置する場合です。簡単なアプローチは、AsyncTaskをアクティビティに配置することです。もう少し複雑なのは、通信を実行し、通信が終了するとメモリから自分自身をクリーンアップするサービス(UIに関連しない機能のホルダー)を作成することです...

AsyncTaskを使用して、アクティビティに配置します/アクティビティから起動します...

最後に、Androidのスレッドに関する優れたチュートリアルをここで見つけることができます。

于 2012-11-13T21:19:55.567 に答える