在Android上的异型和错误处理
-
20-09-2019 - |
题
我正在使用使用代码 Handler
至 AsyncTask
. 。后者的作用非常出色 - 主UI线程中的异步更新和结果处理。我不清楚的是如何处理异常吗? AsyncTask#doInBackground
.
我这样做的方法是拥有一个错误处理程序并向其发送消息。它可以正常工作,但是它是“正确的”方法还是更好的选择?
另外,我了解,如果将错误处理程序定义为活动字段,则应在UI线程中执行。但是,有时(非常不可预测)我会得到一个例外,说代码是从 Handler#handleMessage
在错误的线程上执行。我应该初始化错误处理程序 Activity#onCreate
反而?放置 runOnUiThread
进入 Handler#handleMessage
似乎是多余的,但执行非常可靠。
解决方案
它运行良好,但这是“正确”的方法,还有更好的选择吗?
我坚持 Throwable
或者 Exception
在里面 AsyncTask
实例本身,然后在其中做某事 onPostExecute()
, ,因此我的错误处理可以选择在屏幕上显示对话框。
其他提示
创建一个异步对象(您也可以在其他项目中使用)
public class AsyncTaskResult<T> {
private T result;
private Exception error;
public T getResult() {
return result;
}
public Exception getError() {
return error;
}
public AsyncTaskResult(T result) {
super();
this.result = result;
}
public AsyncTaskResult(Exception error) {
super();
this.error = error;
}
}
从您的异步back doinbackground方法返回此对象,然后在执行后检查。 (您可以将此类用作其他异步任务的基类)
以下是对Web服务器获得JSON响应的任务的模型。
AsyncTask<Object,String,AsyncTaskResult<JSONObject>> jsonLoader = new AsyncTask<Object, String, AsyncTaskResult<JSONObject>>() {
@Override
protected AsyncTaskResult<JSONObject> doInBackground(
Object... params) {
try {
// get your JSONObject from the server
return new AsyncTaskResult<JSONObject>(your json object);
} catch ( Exception anyError) {
return new AsyncTaskResult<JSONObject>(anyError);
}
}
protected void onPostExecute(AsyncTaskResult<JSONObject> result) {
if ( result.getError() != null ) {
// error handling here
} else if ( isCancelled()) {
// cancel handling here
} else {
JSONObject realResult = result.getResult();
// result handling here
}
};
}
当我觉得需要处理例外 AsyncTask
正确地,我将其用作超级类:
public abstract class ExceptionAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
private Exception exception=null;
private Params[] params;
@Override
final protected Result doInBackground(Params... params) {
try {
this.params = params;
return doInBackground();
}
catch (Exception e) {
exception = e;
return null;
}
}
abstract protected Result doInBackground() throws Exception;
@Override
final protected void onPostExecute(Result result) {
super.onPostExecute(result);
onPostExecute(exception, result);
}
abstract protected void onPostExecute(Exception exception, Result result);
public Params[] getParams() {
return params;
}
}
正常,你覆盖 doInBackground
在您的子类中进行背景工作,在需要时愉快地抛出例外。然后,您被迫实施 onPostExecute
(因为它是抽象的),这轻轻地提醒您处理所有类型的 Exception
, ,作为参数传递。在大多数情况下,异常导致某种类型的UI输出,因此 onPostExecute
是这样做的理想场所。
如果您想使用Roboguice框架,该框架带来了其他好处,则可以尝试具有额外回调Onexception()的RoboAsynctask。效果非常好,我使用它。http://code.google.com/p/roboguice/wiki/roboasynctask
我用一个界面制作了自己的异步子类,该接口定义了成功和失败的回调。因此,如果在异步箱中抛出异常,则通过onfailure函数将通过异常,否则启用回调将通过您的结果。为什么Android没有更好可用的东西。
public class SafeAsyncTask<inBackgroundType, progressType, resultType>
extends AsyncTask<inBackgroundType, progressType, resultType> {
protected Exception cancelledForEx = null;
protected SafeAsyncTaskInterface callbackInterface;
public interface SafeAsyncTaskInterface <cbInBackgroundType, cbResultType> {
public Object backgroundTask(cbInBackgroundType[] params) throws Exception;
public void onCancel(cbResultType result);
public void onFailure(Exception ex);
public void onSuccess(cbResultType result);
}
@Override
protected void onPreExecute() {
this.callbackInterface = (SafeAsyncTaskInterface) this;
}
@Override
protected resultType doInBackground(inBackgroundType... params) {
try {
return (resultType) this.callbackInterface.backgroundTask(params);
} catch (Exception ex) {
this.cancelledForEx = ex;
this.cancel(false);
return null;
}
}
@Override
protected void onCancelled(resultType result) {
if(this.cancelledForEx != null) {
this.callbackInterface.onFailure(this.cancelledForEx);
} else {
this.callbackInterface.onCancel(result);
}
}
@Override
protected void onPostExecute(resultType result) {
this.callbackInterface.onSuccess(result);
}
}
一个更全面的解决方案 卡加泰·卡兰(Cagatay Kalan)解决方案如下所示:
异步
public class AsyncTaskResult<T>
{
private T result;
private Exception error;
public T getResult()
{
return result;
}
public Exception getError()
{
return error;
}
public AsyncTaskResult(T result)
{
super();
this.result = result;
}
public AsyncTaskResult(Exception error) {
super();
this.error = error;
}
}
异常handlingasynctask
public abstract class ExceptionHandlingAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, AsyncTaskResult<Result>>
{
private Context context;
public ExceptionHandlingAsyncTask(Context context)
{
this.context = context;
}
public Context getContext()
{
return context;
}
@Override
protected AsyncTaskResult<Result> doInBackground(Params... params)
{
try
{
return new AsyncTaskResult<Result>(doInBackground2(params));
}
catch (Exception e)
{
return new AsyncTaskResult<Result>(e);
}
}
@Override
protected void onPostExecute(AsyncTaskResult<Result> result)
{
if (result.getError() != null)
{
onPostException(result.getError());
}
else
{
onPostExecute2(result.getResult());
}
super.onPostExecute(result);
}
protected abstract Result doInBackground2(Params... params);
protected abstract void onPostExecute2(Result result);
protected void onPostException(Exception exception)
{
new AlertDialog.Builder(context).setTitle(R.string.dialog_title_generic_error).setMessage(exception.getMessage())
.setIcon(android.R.drawable.ic_dialog_alert).setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
//Nothing to do
}
}).show();
}
}
示例任务
public class ExampleTask extends ExceptionHandlingAsyncTask<String, Void, Result>
{
private ProgressDialog dialog;
public ExampleTask(Context ctx)
{
super(ctx);
dialog = new ProgressDialog(ctx);
}
@Override
protected void onPreExecute()
{
dialog.setMessage(getResources().getString(R.string.dialog_logging_in));
dialog.show();
}
@Override
protected Result doInBackground2(String... params)
{
return new Result();
}
@Override
protected void onPostExecute2(Result result)
{
if (dialog.isShowing())
dialog.dismiss();
//handle result
}
@Override
protected void onPostException(Exception exception)
{
if (dialog.isShowing())
dialog.dismiss();
super.onPostException(exception);
}
}
这个简单的课可以帮助您
public abstract class ExceptionAsyncTask<Param, Progress, Result, Except extends Throwable> extends AsyncTask<Param, Progress, Result> {
private Except thrown;
@SuppressWarnings("unchecked")
@Override
/**
* Do not override this method, override doInBackgroundWithException instead
*/
protected Result doInBackground(Param... params) {
Result res = null;
try {
res = doInBackgroundWithException(params);
} catch (Throwable e) {
thrown = (Except) e;
}
return res;
}
protected abstract Result doInBackgroundWithException(Param... params) throws Except;
@Override
/**
* Don not override this method, override void onPostExecute(Result result, Except exception) instead
*/
protected void onPostExecute(Result result) {
onPostExecute(result, thrown);
super.onPostExecute(result);
}
protected abstract void onPostExecute(Result result, Except exception);
}
不依赖可变成员共享的另一种方法是使用取消。
这是来自Android文档:
公共最终布尔式取消(布尔梅特雷特iruptrument)
试图取消执行此任务。如果任务已经完成,已经被取消或由于某些其他原因无法取消,则此尝试将失败。如果成功,并且在调用取消时尚未开始此任务,则该任务绝不应运行。如果任务已经启动,则可能会中断执行此任务的线程是否应中断,以试图停止任务。
调用此方法将导致在doinbackground(Object [])返回后在UI线程上调用的OnCancell(对象)。称此方法可以确保永远不会调用OnPostExecute(对象)。调用此方法后,您应该定期从doinbackground(object [])定期检查Iscancelled()返回的值,以尽早完成任务。
因此,您可以在Catch语句中调用CAMPUL,并确保从未调用OnPostExcute,而是在UI线程上调用了OnCancell。因此,您可以显示错误消息。
实际上,异步使用FutureTask&Executor,FutureTask支持异常链首先定义一个助手类
public static class AsyncFutureTask<T> extends FutureTask<T> {
public AsyncFutureTask(@NonNull Callable<T> callable) {
super(callable);
}
public AsyncFutureTask<T> execute(@NonNull Executor executor) {
executor.execute(this);
return this;
}
public AsyncFutureTask<T> execute() {
return execute(AsyncTask.THREAD_POOL_EXECUTOR);
}
@Override
protected void done() {
super.done();
//work done, complete or abort or any exception happen
}
}
其次,让我们使用
try {
Log.d(TAG, new AsyncFutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
//throw Exception in worker thread
throw new Exception("TEST");
}
}).execute().get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
//catch the exception throw by worker thread in main thread
e.printStackTrace();
}
就个人而言,我将使用这种方法。如果需要信息,您只需捕获异常并打印出堆栈跟踪即可。
使您的任务在后台返回布尔值。
就像这样:
@Override
protected Boolean doInBackground(String... params) {
return readXmlFromWeb(params[0]);
}
@Override
protected void onPostExecute(Boolean result) {
if(result){
// no error
}
else{
// error handling
}
}
另一个可能是使用 Object
作为返回类型,在 onPostExecute()
检查对象类型。很短。
class MyAsyncTask extends AsyncTask<MyInObject, Void, Object> {
@Override
protected AsyncTaskResult<JSONObject> doInBackground(MyInObject... myInObjects) {
try {
MyOutObject result;
// ... do something that produces the result
return result;
} catch (Exception e) {
return e;
}
}
protected void onPostExecute(AsyncTaskResult<JSONObject> outcome) {
if (outcome instanceof MyOutObject) {
MyOutObject result = (MyOutObject) outcome;
// use the result
} else if (outcome instanceof Exception) {
Exception e = (Exception) outcome;
// show error message
} else throw new IllegalStateException();
}
}
如果您知道正确的例外,则可以致电
Exception e = null;
publishProgress(int ...);
例如:
@Override
protected Object doInBackground(final String... params) {
// TODO Auto-generated method stub
try {
return mClient.call(params[0], params[1]);
} catch(final XMLRPCException e) {
// TODO Auto-generated catch block
this.e = e;
publishProgress(0);
return null;
}
}
然后转到“ OnProgressupdate”并进行效果
@Override
protected void onProgressUpdate(final Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
mDialog.dismiss();
OptionPane.showMessage(mActivity, "Connection error", e.getMessage());
}
这仅在某些情况下会有所帮助。您也可以保留 Global
Exception
变量并访问异常。