【问题标题】:Activity terminating abruptly without any exception活动突然终止,没有任何异常
【发布时间】:2015-11-06 02:49:43
【问题描述】:

我有一个活动有时会突然终止,但没有报告或记录任何异常。 Activity 突然结束,应用程序返回堆栈中的前一个 Activity。 我正在使用 ACRA (http://code.google.com/p/acra/) 来捕获和报告错误,它适用于应用程序中的所有其他错误,但在这种情况下,它没有检测到任何已引发的异常。 Logcat 中也没有报告任何内容。

当用户执行某个操作时,它总是发生在应用程序中的同一个“位置”,但它是非常间歇性的,我还没有在附加调试器时实现它。 是否有任何其他选项(除了 ACRA 和 Logcat)来确定活动发生了什么?或者这是 Android 活动世界中“已知”的东西?

如果重要的话,这个 Activity 正在做 Bitmap 操作和保存;我不得不采取措施避免潜在的内存不足错误;但是当 OOM 异常发生时,我收到了 ACRA 报告,所以我认为这不是 OOME 造成的。

在似乎失败的地方,Activity 创建了一个 AsyncTask 并执行它。这是 AsyncTask 的代码(ActivityAsyncTask 是一个非常简单的超类;EditPhotoEctivity 是在创建或执行此任务期间的某个时候无一例外地死去的那个):

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;

import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.media.MediaScannerConnection;
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
import android.net.Uri;
import android.view.View;

public class CompositeAndSavePictureTask extends ActivityAsyncTask<File, Void, Uri>
    implements MediaScannerConnectionClient {

    public static final String FILE_EXTENSION = ".jpg";
    private static final int COMPRESSION_QUALITY = 100;

    private File file;
    private Uri mSavedImageUri;
    private MediaScannerConnection mMediaScannerConnection;


    public CompositeAndSavePictureTask(EditPhotoActivity owningActivity) {
        super(owningActivity);
        mMediaScannerConnection = new MediaScannerConnection(owningActivity, this);
    }


    @Override
    protected EditPhotoActivity getOwner() {
        return (EditPhotoActivity) super.getOwner();
    }


    @Override
    protected void onPreExecute() {
        getOwner().toggleControlsVisibility(false);
    }

    @Override
    protected Uri doInBackground(File... params) {
        file = params[0];
        Bitmap picture = null;
        View mainContentView = getMainContentView();

        try {
            picture = captureBitmap(mainContentView);
            saveBitmap(picture);
        } catch (Exception ex) {
            LogUtils.logError(this, "Could not save photo", ex);
            setError(ex);
            return null;
        } finally {
            cleanUpCapture(mainContentView, picture);
        }

        try {
            mMediaScannerConnection.connect();
            synchronized (mMediaScannerConnection) {
                mMediaScannerConnection.wait();
            }
        } catch (InterruptedException ex) {
            LogUtils.logInfo(this, "MediaScannerConnection was interrupted during scan.");
            setError(ex);
        }

        return mSavedImageUri;
    }


    protected Bitmap captureBitmap(View mainContentView) throws Exception {
        mainContentView.setDrawingCacheEnabled(true);
        return mainContentView.getDrawingCache();
    }


    protected void cleanUpCapture(View mainContentView, Bitmap capturedBitmap) {
        mainContentView.setDrawingCacheEnabled(false);

        if (capturedBitmap != null) {
            capturedBitmap.recycle();
        }
    }


    protected void saveBitmap(Bitmap bitmap) throws IOException {
        BufferedOutputStream outStream = null;
        try {
            outStream = new BufferedOutputStream(FileUtils.openOutputStream(file));
            bitmap.compress(CompressFormat.JPEG, COMPRESSION_QUALITY, outStream);
        } finally {
            try {
                if (outStream != null) {
                    outStream.close();
                }
            } catch (IOException ex) {
                LogUtils.logError(this, "Could not close output stream", ex);
            }
        }
    }


    @Override
    protected void onPostExecute(Uri savedFileURI) {
        getOwner().toggleControlsVisibility(true);
        getOwner().onSaveResult(savedFileURI);
    }


    public void onMediaScannerConnected() {
        mMediaScannerConnection.scanFile(file.getPath(), null /* mimeType */);
    }


    public void onScanCompleted(String path, Uri uri) {
        mMediaScannerConnection.disconnect();
        mSavedImageUri = uri;
        synchronized (mMediaScannerConnection) {
            mMediaScannerConnection.notify();
        }
    }

}

另见view.getDrawingCache() only works once,它有一些关系,但情况略有不同。

欢迎任何和所有想法。

【问题讨论】:

  • 能否提供一些源代码?现在就像蒙着眼睛拍摄一样。
  • 你能在某个地方“完成”你的活动吗?
  • @nicholas 我已经仔细检查和三重检查是否有任何无意调用完成()。活动中的唯一条件是成功完成或其他预期条件。
  • @Shade 我刚刚用一些代码编辑了这个问题。
  • @Amplify91 有 4 次对 finish() 的调用,除 1 次外,其余都是在 Activity 初始化期间。由于用户交互而发生的情况发生在 AsyncTask 完成并保存其文件之后。我已经验证,当突然失败发生时,文件还没有保存,代码也没有到达对 finish() 的调用。

标签: android android-activity


【解决方案1】:

我之前也遇到过类似的问题。我试图打开一个文件进行阅读,但我没有输入“/sdcard/something.txt”的完整地址,而是在没有 sdcard 部分的情况下给了它错误的路径(只是“something.txt”)。在经历了很多痛苦之后,我发现如果你想让程序打开一些不存在的东西,活动就会在没有任何通知的情况下结束(到控制台、到 logcat 等)。因为它不会发回错误,所以它不会进入“catch”分支。

所以,我建议检查文件操作。

免责声明:我确信这会在尝试使用 ndk 和本机代码打开错误的路径时导致这种行为,但我想如果你在 java 代码中犯了这个错误,它会是一样的。

【讨论】:

    【解决方案2】:

    请原谅新手评论,但如果它在没有异常的情况下终止,您可能在某处捕获它并且程序继续以它的快乐方式继续,但处于无效状态。

    【讨论】:

    • @r-hughes 我希望它这么简单;代码已经针对这种事情进行了双重和三重检查。我添加了一些日志记录,似乎故障发生在mainContentView.setDrawingCacheEnabled(true);return mainContentView.getDrawingCache(); 行中的某处
    • 是的,您已经完成了日志记录。如果 Android 由于内存不足或其他一些不明原因而终止它,您的 onPause 会被调用。嗯...如果 .getDrawingCache() 返回 null,那会对您的 Activity 产生什么影响?
    • 我将其简化为 'mainContentView.getDrawingCache();'导致突然终止,但当时不得不转移到其他项目。希望我能找到一种方法来可靠地重现这一点,这样我就可以进行更多调试。
    猜你喜欢
    • 2011-11-14
    • 2016-12-18
    • 1970-01-01
    • 2011-05-29
    • 2012-09-20
    • 1970-01-01
    • 2011-09-09
    • 2021-10-10
    • 2016-10-07
    相关资源
    最近更新 更多