在父活动中从子活动中捕获异常
Posted
技术标签:
【中文标题】在父活动中从子活动中捕获异常【英文标题】:Catch Exception from child activity in Parent activity 【发布时间】:2014-02-03 23:54:36 【问题描述】:我一直想知道是否可以通过捕获父 Activity 中的崩溃来阻止 android 应用中的崩溃。
假设我在子活动的 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());
子.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: 经过大量阅读(感谢user370305)线程How do I obtain crash-data from my Android application?
我已经走到了死胡同,要么我处理 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);
);
【问题讨论】:
是的,这是可能的,期望是可序列化的,因此它们可以放在一个包中 Activity 是独立的,Intent 通信是异步的。也许你可以探索startActivityForResult的方式。 看***.com/questions/601503/… Startactivity 不起作用 您可以通过一些创意来做到这一点。给我几天,我会发布一些代码(大忙人)。 【参考方案1】:Android 中的 Activity 必须独立管理,因为它们有 their own lifecycle。因此,在产生异常的活动中捕获异常。
如果您的活动需要交互才能返回到先前的用户活动,请完成捕获异常的活动(子)并让先前的活动(父)知道结果。将Starting Activities and Getting Results 视为一种将父子活动相互通信的方法。
【讨论】:
我知道我应该在产生异常的活动中捕获异常,并且我也知道如何从子活动中获取结果,问题出在编程不正确,但由于我可以覆盖 UncaughtExceptionHandler 我想知道我是否可以对我得到的未捕获异常做点什么......【参考方案2】:希望我能正确理解您想要什么。您可以查看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);
希望这能有所帮助。
【讨论】:
是的,这似乎是我正在寻找的想法,因为我不在我的开发人员电脑附近,我无法测试它,但时间不多了,我认为你对问题不利于赏金。我会在星期一检查解决方案是否有效,如果是这种情况,我会将其设置为接受的答案。感谢您的示例和信息! @RdPC 我们不是星期一吗? ;) 我测试了这个解决方案,但不幸的是,这并不能阻止主要活动崩溃。你可以开始一个新的活动,但不能回到“主要活动”,因为它在被杀死的线程中,它一直在死亡。如果有办法不让调用活动被杀死,那就太好了! @QuickFix 我认为没有办法做到这一点。因为当您的活动发生异常并且应该崩溃时会调用此异常处理程序。您可以通过更正所有代码并且不创建任何异常来避免这种情况。或者您可以再次启动 MainActivity(创建新实例)并为其恢复以前的数据【参考方案3】:崩溃需要来自代码中的某个特定点。您可以使用子项中的 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;
对不起,忍不住了:)
说真的,捕捉全局异常听起来有点危险,因为你不知道它会从哪里来,但已经提前决定了如何处理它,此外,查看你的代码,不管对孩子的调用是什么将终止。
【讨论】:
好吧,异常会在函数和过程堆栈中上升,直到它们到达堆栈的末尾或被捕获,但是,活动不是这种情况:p 因为 android 会破坏子活动并导致父级,无论您将try catch放在父级的哪个位置(也在onResume中尝试过)【参考方案4】:我认为您误解了异常的性质。您只能在源自您的代码的方法调用上捕获异常。换句话说,您只能在调用堆栈中捕获低于您的代码的调用。请看下面的调用栈:
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
方法本身之外,您无法在任何地方捕获任何异常。我希望,这可以清楚地说明在另一个活动中捕获异常。
如果你想知道子Activity自己创建失败,你应该捕获insideonCreate
childactivity的所有异常,然后使用一些通知父活动的标准 Android 机制。 startActivityForResult 可能就是其中之一。
【讨论】:
好吧,我确实了解异常是如何工作的,我只是想知道是否有办法在父 Activity 上获取它,因为我能够修改父 Activity 上的 DefaultUncaughtExceptionHandler 并登录孩子异常,当然我知道如果我通过 startActivityForResult 调用活动,我可以在孩子身上捕获它并发送结果,但如何制作正确的程序并不是重点。我想知道这是否可能...... 嗯,你的问题标题表明你想抓住那些,我的意思是这是不可能的,为什么会这样。如果您考虑一下,捕获和获取异常是完全不同的事情。我的第二点是你最好选择平台推荐的方法,而不是一些黑客或变通方法。从长远来看,这将使您的开发更容易。【参考方案5】:您可以使用一个 ResultReceiver,您可以在主活动意图的子活动意图包中作为额外传递。
以下是从主 Activity 启动子 Activity 的方法:
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
【讨论】:
虽然是与使用 onActivityResult 不同的方法,但您的示例只是在子活动中捕获异常并将反馈发送回父级的另一种方法,我的问题要求处理异常的方法由父活动中的孩子引起 好吧,我想您可以将该机制包装在自定义活动类中并抛出一些 ChildActivityException... 几乎就像您在客户端/服务器情况下所做的那样。不知道有没有更直接的方法。【参考方案6】:如果您捕获所有可能的异常并提供适当的操作,您就可以停止崩溃。
关于在父级中捕获异常:为什么要这样做? 您可以捕获子异常并通过意图将必要的信息发送到父活动。我认为不可能在父级中捕获子级异常。
【讨论】:
是的,如果我发现所有异常,我知道如何阻止孩子的崩溃,但这不是重点。我只是想知道是否有任何方法可以处理父活动中的异常......【参考方案7】:你不能。当您收到 UncaughtException 时,这意味着它终止的线程,您与此无关。但是您可以使用 UncaughtExceptionHandler 记录此事件并重新启动您的应用程序(并打开“新”父活动)。 Android 对所有活动和服务使用单个主线程。因此,如果有人在主线程中抛出未捕获的异常 - 每个人都会死。您不能在单独的线程中运行活动。
【讨论】:
是的,我就是这么想的。我可以捕获 UncaughtException,但如果我不通过再次抛出它来崩溃应用程序,它将停止工作以上是关于在父活动中从子活动中捕获异常的主要内容,如果未能解决你的问题,请参考以下文章