我前一段时间写的游戏存在ANR问题,调试表明它们是由于HTTP请求花费了很长时间(从而导致了ANR)。

我以为通过将HTTP代码分配给从Handler中调用的Runnable中,我可以避免使用ANR-但似乎不是这样吗?

堆栈转储表明可运行/处理程序代码仍在“主”线程中运行,因此仍会导致ANR?

它正在执行的任务是异步的(上传高分和成就),因此可以完全将其启动并留给其自己的设备-实现此目标以使ANR不会成为问题的最佳方法是什么?

一个主题建议处理程序应该在Application类中创建,而不是在游戏的Activity中创建-但是我找不到关于这两种情况之间差异的详细信息?

所有的想法都很赞赏。

p.s.将其扩展为询问-我假设与HTTP有关的ANR归因于电话停止服务/网络/WiFi,因为我已为这些请求设置了SHORT超时(它们不是必需的,可以重试)之后!?)

最佳答案

Handler将在当前线程中默认执行代码/处理消息(默认情况下,任何没有Looper的构造函数,例如new 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。如果您的Activity-lifecycle重新创建Activity,那么这些都不会发疯。

您将在自己的文件中创建一个小的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()已经在后台线程上运行,因此您不必为此而烦恼。

关于android - 来自在处理程序中运行的代码的Android ANR?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13368762/

10-10 00:54