如何处理ContentProvider中的异常?

时间:2015-10-21 15:37:53

标签: android android-contentprovider

我有一个执行数据库或网络请求的内容提供商。如果没有网络,则引发IOException,我想再做一次请求(这次在数据库上)。

我的代码看起来像

/**
 * Content provider
 */
//...
public Cursor query (Uri uri /*,...*/) {
    switch(uriMatcher.match(uri)) {
        case NETWORK:
            JSONObject json;
            try {
                json = new HttpTask().getItems(); // If no network throws IoException
            } catch (IOException e) {
                //Do something
            }
            return new Cursor(/* ... */);
            break;
        case DATABASE:
            //Access database
            return new Cursor(/* ... */);
            break;
    }
}
//...

我应该:

  1. 仅在contentProvider中处理异常并在发生错误时直接移至数据库案例?
  2. 处理HttpTask中的例外,以便json“只是”为空
  3. 创建一个像这个one的自定义游标加载器和一个自定义的RuntimeException?如果是这样,在内容提供者中,我将抛出异常并在CursorLoader中捕获它。
  4. 编辑1

    或者我应该在使用之前检查网络状态:

    ConnectivityManager connectivityManager = (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (connectivityManager != null) {
        NetworkInfo ni = connectivityManager.getActiveNetworkInfo();
        if (ni.getState() != NetworkInfo.State.CONNECTED) {
            // record the fact that there is not connection
            isConnected = false;
        }
    }
    

    编辑2 以下是使用自定义例外和自定义加载器的方法

    NoNetworkException.java

    public class NoNetworkException extends RuntimeException {
        public NoNetworkException(String s) {
            super(s);
        }
    }
    

    NoNetworkSafeCursorLoader.java

    public class NoNetworkSafeCursorLoader extends CursorLoader {
        private NoNetworkException exception;
    
        public NoNetworkSafeCursorLoader(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
            super(context, uri, projection, selection, selectionArgs, sortOrder);
        }
    
        @Override
        public Cursor loadInBackground() {
            try {
                return super.loadInBackground();
            } catch(NoNetworkException exception) {
                this.exception = exception;
            }
            return null;
        }
    
        public NoNetworkException getException() {
            return exception;
        }
    }
    

    现在在内容提供商中,您需要抛出NoNetworkException

    //...
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) throws NoNetworkException {
        //...
    }
    //...
    

    并且在回调中你必须检查是否抛出了异常

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) throws NoNetworkException {
        NoNetworkSafeCursorLoader l = (NoNetworkSafeCursorLoader) loader;
    
        if(l.getException() != null) {
            //No network, do somethings
        }
        else {
            //Network ok, do otherthings
        }
    }
    

3 个答案:

答案 0 :(得分:1)

您首先应该检查网络状态。然后,如果网络请求失败,请在catch - 块

中进行数据库访问
public Cursor query (Uri uri /*,...*/) {
    Cursor cursor;
    switch(uriMatcher.match(uri)) {
        case NETWORK:
            JSONObject json;
            try {
                 json = new HttpTask().getItems(); // If no network throws IoException
                 cursor = new Cursor(/* convert json */)
            } catch (IOException e) {
                cursor = //access the database
            }
            break;
        case DATABASE:
            //Access database
            cursor = new Cursor(/* ... */);
            break;
        }
    return cursor;
}

另外,您应该看一下Sync Adapters这是谷歌说你应该这样做的方式。根据您的使用情况,它可能是一个很好的帮助,因为同步适配器已经处理网络检查和其他事情,以最大限度地延长电池寿命。

答案 1 :(得分:1)

在这种情况下,你可以做的事情很少,

  1. 是的,@ leoderprofi说,您必须检查网络是否可用于您想要的HTTP任务。

  2. 而不是在抛出异常后使用Try Catch进行管理。您可以做的是在此之前检查对象可用性。比如,在解析之前检查JSON是否为null,在获取游标之后还检查它是否为null,如果不是null,它实际上是否有任何数据init,它最有可能在游标中得到异常对象存在但它没有任何数据,当你从中获取数据时给你例外。

  3. 是的,你可以创建一个自定义加载器并处理并在那里抛出异常,你也可以做的就是使用接口管理它来创建成功和错误回调。

  4. 希望它有所帮助。 感谢。

答案 2 :(得分:1)

正确的解决方案......封装您的网络功能,如果网络不可用则故障转移到数据库,无需第二次查询调用。

我不会创建一个自定义加载器和异常,除非你的客户端真的想知道网络尝试失败了,但如果它只是用db请求跟进它,那么为什么要打扰通知任何人,但这取决于你的用例。

不知道你的实际要求;删除NETWORK和DATABASE内容URI并使用一个MY_DATA更清晰。您的客户是否真的知道或关心它是否要求/或?

public Cursor query (Uri uri /*,...*/) {
    switch(uriMatcher.match(uri)) {
        case NETWORK:
            // check network
            if ( isNetworkAvailable(context) ) {
                JSONObject json;
                try {
                    json = new HttpTask().getItems(); // If no network throws IoException
                    return new Cursor(/* ... */);
                } catch (IOException e) {
                    // Log a warning
                }
            }
            // delete this break;
            // failover to DB
        case DATABASE:
            //Access database
            return new Cursor(/* ... */);
            break;
    } 
}

private boolean isNetworkAvailable(Context ctx) {
    boolean isConnected = false;
    ConnectivityManager connectivityManager = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (connectivityManager != null)
        NetworkInfo ni = connectivityManager.getActiveNetworkInfo();
        isConnected = ni.getState() == NetworkInfo.State.CONNECTED;
    }
    return isConnected;
}

您甚至可以使用公共静态布尔值isNetworkAvailable(...),以获得可在其他地方使用的简单实用方法。