我一直想知道是否可以通过捕获父活动中的崩溃来阻止Android App中的崩溃。
假设我在子活动的onCreate方法中导致致命异常,我能否以任何方式捕获该异常?或者无论我尝试什么,应用程序都会崩溃吗?
这是我的意思的一个例子:
Main.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ly_main);
// My Main activity starts
try{
// Call the next activity
Intent intent = new Intent(getApplicationContext(), Child.class);
startActivity(intent);
}catch(Exception e){
Log.wtf("Exception_WTF","Exception from child activity woohoo \n "+ e.toString());
}
Child.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ly_child);
// Create exception... for science
int a = 0;
a = 1/a;
}
这不起作用。孩子的活动会消失并带走父母。
是否可以通过startActivityForResult来实现?
谢谢,
编辑:我不需要崩溃数据,我只是想知道如何避免应用程序崩溃。
环顾四周我发现: Using Global Exception Handling on android
包括这篇文章:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
Log.e("Alert","Lets See if it Works !!!");
}
});
让我记录uncaughtException,避免“崩溃”,然而,应用程序变黑屏并停止响应......
编辑2: 经过线程How do I obtain crash-data from my Android application?
中的大量阅读(感谢user370305)我已达到死胡同,要么处理uncaughtException并调用defaultUEH.uncaughtException(paramThread,paramThrowable);所以应用程序崩溃,或者我没有调用defaultUEH.uncaughtException,应用程序没有崩溃,但也没有响应...... 有什么想法吗?
final Thread.UncaughtExceptionHandler defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
Log.e("Alert","Lets See if it Works !!!");
defaultUEH.uncaughtException(paramThread, paramThrowable);
});
答案 0 :(得分:6)
Android中的活动必须独立管理,因为它们具有their own lifecycle。因此,仅在生成它们的活动中捕获异常。
如果您的活动需要互动以返回之前的用户活动,请完成捕获异常的活动(子)和让之前的活动(父级)了解结果。请参阅Starting Activities and Getting Results作为相互传达父子活动的方法。
答案 1 :(得分:4)
希望我能正确理解你想要的东西。您可以查看FBReaderJ的源代码,这是一个处理您的问题的真实示例。他们可以做得很好:每当应用程序出错时,他们都会向用户显示错误报告对话框,他们可以通过阅读Throwable
信息来过滤错误。
例如,看一下BookInfoActivity,他们就像这样注册了Exception Handler:
Thread.setDefaultUncaughtExceptionHandler(
new org.geometerplus.zlibrary.ui.android.library.UncaughtExceptionHandler(this)
);
然后UncaughtExceptionHandler类将处理错误:
@Override
public void uncaughtException(Thread thread, Throwable exception) {
final StringWriter stackTrace = new StringWriter();
exception.printStackTrace(new PrintWriter(stackTrace));
System.err.println(stackTrace);
if(myContext != null && myContext instanceof Activity){
((Activity)myContext).finish();
return;
}
// filter the error by get throwable class name and put them into
// intent action which registered in manifest with particular handle activity.
Intent intent = new Intent(
"android.fbreader.action.CRASH",
new Uri.Builder().scheme(exception.getClass().getSimpleName()).build()
);
try {
myContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
// or just go to the handle bug activity
intent = new Intent(myContext, BugReportActivity.class);
intent.putExtra(BugReportActivity.STACKTRACE, stackTrace.toString());
myContext.startActivity(intent);
}
if (myContext instanceof Activity) {
((Activity)myContext).finish();
}
// kill the error thread
Process.killProcess(Process.myPid());
System.exit(10);
}
希望这可以提供帮助。
答案 2 :(得分:1)
崩溃需要来自代码中的某个特定点。您可以使用子语句中的if语句过滤掉导致崩溃的条件,然后抛出异常。父对象的调用将包含try {} catch {}语句,因此异常在父对象中处理。见here。所以对于你的代码,我想这个孩子看起来像
import java.io.TantrumException;
public class Child throws TantrumException() {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ly_child);
// Create exception... for science
int a = 0;
if (a == 0)
throw new TantrumException("Arrrggghhh!");
a = 1/a;
}
}
对不起,忍不住了:)
说真的,捕捉全球异常听起来有点危险,因为你不知道它会从哪里来,但事先已经决定如何处理它,而且,看看你的代码,不管对孩子的呼叫是什么将终止。
答案 3 :(得分:1)
我认为你误解了例外的本质。您只能捕获源自代码的方法调用的异常。换句话说,您只能捕获调用堆栈中代码下方的调用。请查看以下调用堆栈:
main@830028322576, prio=5, in group 'main', status: 'RUNNING'
at com.stuff.ui.MainActivity.onCreate(MainActivity.java:83)
at android.app.Activity.performCreate(Activity.java:5372)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2257)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2349)
at android.app.ActivityThread.access$700(ActivityThread.java:159)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1316)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Method.java:-1)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1187)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
at dalvik.system.NativeStart.main(NativeStart.java:-1)
这只是我的应用程序中某些活动中onCreate
方法中调用堆栈的一个示例。如您所见,第一行下方的所有代码都属于android
,com.android
,java
或dalvik
包。重要的是,在第一行之后,此调用堆栈中没有用户代码。这意味着,除了onCreate
方法本身之外,您无法捕获任何异常。我希望,这可以清楚地说明在另一项活动中捕获异常。
如果您想知道子活动未能自行创建,您应该捕获 child 活动 onCreate
方法中的所有异常,然后使用一些标准的Android机制,用于通知父活动。 startActivityForResult可能就是其中之一。
答案 4 :(得分:1)
您可以使用在主要活动意图的子活动意图包中作为额外传递的ResultReceiver。
以下是从主要活动开始子活动的方法:
private void startChildActivity(){
Intent childActivityIntent = new Intent(this, ChildActivity.class);
ResultReceiver rr = new ResultReceiver(mainUiHandler){
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
switch(resultCode){
case RESULT_ERROR:
String errorMessage = resultData.getString(RESULT_KEY_ERROR_MESSAGE);
textView.setText(errorMessage);
break;
default:break;
}
}
};
childActivityIntent.putExtra(INTENT_EXTRA_KEY_RESULT_RECEIVER, rr);
startActivity(childActivityIntent);
}
这是儿童活动的代码。
public class ChildActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_child);
try{
int a = 0;
a = 1/a;
} catch(Exception e){
Log.e("Exception", e.getMessage());
Intent startIntent = getIntent();
ResultReceiver rr = startIntent.getParcelableExtra(MainActivity.INTENT_EXTRA_KEY_RESULT_RECEIVER);
Bundle resultData = new Bundle();
resultData.putString(MainActivity.RESULT_KEY_ERROR_MESSAGE, e.getMessage());
rr.send(MainActivity.RESULT_ERROR, resultData);
finish(); //close the child activity
}
}
}
答案 5 :(得分:0)
如果捕获所有可能的异常并提供适当的操作,则可以停止崩溃。
关于在父级中捕获异常:为什么要这样做? 您可以捕获孩子的异常并通过意图将必要的信息发送到父活动。我认为不可能在父母身上捕捉孩子的异常。
答案 6 :(得分:0)
你做不到。当你得到UncaughtException时,它意味着它终止的线程,你与此无关。但您可以使用UncaughtExceptionHandler记录此事件并重新启动应用程序(并打开“新”父活动)。 Android为所有活动和服务使用单主线程。因此,如果有人在主线程中抛出未捕获的异常 - 永久死亡。您无法在单独的线程中运行活动。