如何在调用相机时解决ANR错误?

时间:2011-12-17 08:04:20

标签: android android-camera android-anr-dialog

我在主菜单中有两个按钮。我按下第一个按钮时调用相机。在这里,我没有遇到任何问题。相机正常工作。拍完照片后,我回到主菜单,再次按下第一个按钮。我在这里得到了这个问题。相机正确调用。但是我在拍照的时候得到了ANR error (Reason: keyDispatchingTimedOut)。如何解决这个问题?

修改::

我正在使用以下代码,

按钮监听器

Button imageButton = (Button) findViewById(R.id.button1);
imageButton.setOnClickListener(new  View.OnClickListener() {

    public void onClick(View arg0) {
    Intent intent = new Intent();
    intent.setClass(activity, ImageActivity.class);
    startActivity(intent);
    }
});

ImageActivity.java

public class ImageActivity extends Activity implements SurfaceHolder.Callback {
    private Camera camera = null;
    private SurfaceHolder surfaceHolder = null;
    private boolean previewRunning = false;
    private Button btnDone, btnCapture, btnRetake;
    private Bitmap mBitmap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().setFormat(PixelFormat.TRANSLUCENT);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.surface_screen);
        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.camerapreview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        surfaceHolder.setFixedSize(getWindow().getWindowManager()
                .getDefaultDisplay().getWidth(), getWindow().getWindowManager()
                .getDefaultDisplay().getHeight());
        LayoutInflater  controlInflater = LayoutInflater.from(getBaseContext());

        final View viewControl = controlInflater.inflate(R.layout.control, null);
        LayoutParams layoutParamsControl = new LayoutParams(
                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
        activity.addContentView(viewControl, layoutParamsControl);

        btnCapture = (Button) findViewById(R.id.takepicture);

        btnDone = (Button) findViewById(R.id.send);

        btnCapture.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                camera.takePicture(null, picCalBac, picCalBac);
            }
        });


    Camera.PictureCallback picCalBac = new PictureCallback() {

        public void onPictureTaken(byte[] data, Camera camera) {
            if (data != null) {
                mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            }
        }
    };

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        if (previewRunning) {
            camera.stopPreview();
        }
        try {
            camera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            Log.d("IOException", e.getMessage());
        }
        camera.startPreview();
        previewRunning = true;
    }

    public void surfaceCreated(SurfaceHolder arg0) {
        camera = Camera.open(0);
    }

    public void surfaceDestroyed(SurfaceHolder arg0) {
        camera.stopPreview();
        previewRunning = false;
        camera.release();
    }
}

5 个答案:

答案 0 :(得分:9)

搜索错误时,您可能已经通过了this link

虽然我从未遇到过这样的问题,但在互联网上阅读后,这就是我的理解:

描述:

  

进程时出现ANR或应用程序无响应错误   在主线程上花费太长时间(类似于> 5秒)。 Android的   通过设计杀死该过程和任何相关的设备以备用该设备   资源。

     

解决方案是在另一个线程上运行资源昂贵的任务,并且   然后发布,或相应地更新主线程。

请参阅: Android ANR keyDispatchingTimedOut

因此,在您的情况下,您可能与长时间运行并且Android杀死它们的冲突两个不同的线程。下一个相关代码也会受到影响。

因此,请更好地对代码进行分类,在不同的Thread,Handler中编写每个新任务,如果您正在执行UI任务,请使用runOnUIThreadAsync Task也非常方便。

另一件事是尝试删除其他代码的依赖性。写一些默认值,如果没有正确完成,你可以将用户送回第一个任务。

我认为错误来自您的编码样式,而不是因为您的代码中存在任何特定错误。

您需要改进您的特定代码才能有效执行,并且请参阅以下两个链接:

  1. Design for Responsiveness
  2. Painless Threading
  3. 修改

    我在某处读到并发现有效,

    如何调查ANR?

    首先,查看代码并查找可用的点和长时间运行的操作。示例可以包括在事件线程内使用套接字,锁,线程休眠和其他阻塞操作。你应该确保这些都发生在不同的线程中。如果没有任何问题,请使用DDMS并启用线程视图。这会显示应用程序中的所有线程与您拥有的跟踪类似。重现ANR,同时刷新主线程。这应该向你展示ANR时正在发生的事情

    如果由于线程导致ANR?

    你可以为此用户服务, 所以你的应用程序可以在service.onStart()中执行耗时的任务, 在用于启动服务的意图中传递数据(例如)。

    但是,Services在主应用程序线程上执行。如果单独的 需要线程,它可以由onStart()内的服务创建。

    已有一个内置类可以执行此操作:IntentService

    还找到了一个有用的库应用程序 SalomonBrys/ANR-WatchDog

答案 1 :(得分:6)

Android applications normally run entirely on a single (i.e. main) thread。这意味着您的应用程序在完成long time的主线程中执行的任何操作都可以触发ANR dialog因为您的应用程序没有给自己处理input event或{{{ {1}}。因此,在这种情况下,您可以使用StrictMode来帮助查找可能长时间运行的操作,例如您可能意外执行主线程的网络或数据库操作。如果您发现您认为有问题的违规行为,可以使用各种工具来解决这些问题:ntent broadcastthreadsHandlerAsyncTask等。另外请记住它来自IntentService

要在API Level 9Application或其他应用程序组件Activity方法的早期启用的示例代码:

onCreate()

答案 2 :(得分:5)

我想你已经知道了,

单线程模型会在不考虑其影响的Android应用程序中产生较差的性能。由于所有操作都发生在执行长操作的单个线程上,例如网络访问或数据库查询,因此该线程将阻止整个用户界面。 无法发送任何事件,包括绘制事件,而长时间的操作正在进行中。 * 从用户的角度来看,应用程序显示为挂起 * 更糟糕的是,如果UI线程被阻止超过几秒钟(当前大约5秒),则会向用户显示臭名昭着的“应用程序无响应”(ANR)对话框。

当在“主”线程中发生一些长操作时,会发生ANR。这是事件循环线程,如果它很忙,Android无法处理应用程序中的任何进一步的GUI事件,从而抛出一个ANR对话框。

什么触发ANR?

在Android中,应用程序响应性由活动管理器和Window Manager系统服务监视。当Android检测到以下某种情况时,它将显示特定应用程序的ANR对话框:

* No response to an input event (e.g. key press, screen touch) within 5 seconds
* A BroadcastReceiver hasn't finished executing within 10 seconds

如何解决,请查看Designing for Responsiveness

修改

所以,尝试使用其他单独的工作线程,处理程序,AsyncTask或UIThread为您的相机(媒体记录器)而不是活动的主线程。

1)。请"adb shell cat /data/anr/traces.txt"查看您的应用正忙着做什么     在那时候。这是您需要采取的第一步:理解     您的应用正在做什么导致ANR。

当ANR发生时,所有进程的堆栈都写入此文件,   该流程首先被指控为ANR。这一切都是   转储文件,以便您可以查看它。所以你只想看看它   在ANR之后的时间,在另一个ANR发生之前。

2)。如果没有任何问题,请使用DDMS并启用线程视图。这显示了所有     应用程序中的线程与您拥有的跟踪类似。重现ANR,和     同时刷新主线程。那应该会告诉你到底发生了什么     在ANR的时候。

更多信息请点击此http://android-developers.blogspot.com/2009/05/painless-threading.html

答案 3 :(得分:1)

您可以在Oncreate()Onresume()中的主线程中初始化并启动媒体录制器,而不是在主线程中启动相机使用separeate Handler来启动相机拍照,它会像主UI线程的孩子一样。

使用Handler可以缩短时间并且不会发生ANR。

答案 4 :(得分:1)

似乎相机资源未被释放,从而导致 ANR

代码看起来有点凌乱。您可以查看相机preview:

的api示例

您必须实施onPauseonResume才能使其可靠地运作。