I have an Activity that sometimes terminates abruptly but without any exception being reported or logged. The Activity just ends suddenly and the app returns to the previous Activity in the stack. I'm using ACRA (http://code.google.com/p/acra/) to capture and report errors, and it works well for all other errors in the app, but in this one case it does not detect any exception having been thrown. Nor is anything reported in Logcat.
It always happens at the same "place" in the app, when the user takes a certain action, but it is very intermittent and I've yet to make it happen while attached with the debugger. Are there any other options (besides ACRA and Logcat) for determining what is happening to the Activity? Or is this something in the world of Android Activities that is "known?"
If it matters, this Activity is doing Bitmap manipulation and saving; I've had to take steps to avoid potential out of memory errors; but I was getting ACRA reports of OOM exceptions when they did occur, so I don't think this is due to OOME.
At the point where it seems to fail, the Activity creates an AsyncTask and executes it. Here's the code for the AsyncTask (ActivityAsyncTask is a really simple super class; EditPhotoEctivity is the one that is dying without an exception, sometime during the creation or execution of this task):
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&g开发者_Go百科t;
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();
}
}
}
See also view.getDrawingCache() only works once, which has some relation but is a slightly different scenario.
Any and all ideas are welcomed.
I had a similar problem before. I was trying to open a file for reading, but instead of typing the complete address which was "/sdcard/something.txt", I gave it the wrong path (just "something.txt") without the sdcard part. After a lot of pain I have discovered that if you want the program to open something that is not really there, the activity just ends whitout any notice (to to console, to logcat etc. ). As it won't send back an error, it won't go on the "catch" branch.
So, I would suggest checking the file opperations.
Disclaimer: I know for sure that this causes this kind of behavior when trying to open the wrong path using the ndk and native code, but I suppose it would be the same if you do this mistake from in java code.
Please forgive the newbie comment, but if it's terminating without a Exception, you may be catching it somewhere and the program is continuing on it's merry way, but in an invalid state.
精彩评论