android - 从互联网资源更新 ContentProvider 的底层 SQLite 数据库

标签 android android-contentprovider

我实现了一个 ContentProvider 来提供来自底层 SQLite 数据库的地理位置列表。

这些位置实际上是模型的输出,并且可以以简单的 JSON 字符串的形式在线获取;我不想每次启动应用程序时都下载它们,因此我想将它们本地存储在数据库中,并按照预定义的时间间隔(例如每天一次)更新它们。

我的问题是,我应该在哪里实现下载和解析代码?它应该是我的 ContentProvider 实现的一部分吗?或者是 SQLiteOpenHelper 实现的一部分?

我开始在我的 ContentProvider 中将其实现为一个名为 updateSiteList 的公共(public)函数,但我不知道如何实际调用它(ContentProvider 通常是间接访问的)通过 CursorLoader)!

我对如何进步有点困惑!

有人能指出我正确的方向吗?

谢谢!

最佳答案

有几种方法可以实现这一目标。 我最常用的两种方法是:-

1) 自定义同步适配器。

2) Intent 服务。

使用选项 1,您可以从 Android 系统处理网络连接问题中受益,这是 Android 开发人员推荐的方法

使用选项 2,您可以更好地控制何时下载数据,这对于用户或 Android 系统来说可能是也可能不是最佳时间。

无论哪种方式,解决方案都是相同的。在某个时间点,您将在后台服务中向 URL 发出 HTTP get 请求。当您的请求完成时,您将需要检查响应的状态,如果合适,您将调用内容提供商以相应地插入或更新您的数据。无论您在这部分采取哪种方法都是相同的。

为您提供一些进一步的阅读内容。 https://sites.google.com/site/andsamples/concept-of-syncadapter-androidcontentabstractthreadedsyncadapter

请务必观看 Google I/O 视频

无论您采用哪种方法,下载 json 并插入到您的内容提供程序的代码可能在从您的同步适配器或从应用程序内的某个位置(如果不使用同步适配器)调用的 IntentService 中看起来像这样。

public class ServiceInitialiseData extends IntentService {
    static final String TAG = "ServiceSyncData";
    //ACTION should include application package convention, just to show that this can
    //be any string
    public static final String SYNC_COMPLETED_ACTION="com.pjmobile.games.fantasyf1.SyncCompleted";

    public ServiceInitialiseData() {
        super("InitialiseDataService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String sJson;
        try {
            sJson = downloadFromServer("Some parsed url");
            int i, x;
            boolean res = false;
            List <ContentValues> bulkValues = new ArrayList <ContentValues>();
            JSONArray entries;
            try {
                entries = new JSONArray(sJson);
                ContentValues cvEntity = null;
                JSONObject entity;
                x = entries.length();
                for (i=0;i<x;i++){
                    entity = entries.getJSONObject(i).getJSONObject("some_json_key");
                    bulkValues.add(cvEntity);
                }
            }
            int qCount = getContentResolver().bulkInsert(uri,
            (ContentValues[])bulkValues.toArray(new
                    ContentValues[bulkValues.size()]));

            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        } catch (ClientProtocolException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    private String downloadFromServer(String url) throws ClientProtocolException, IOException {
        HttpResponse sJson = getJSONEntityFromURL(this, url);
        return EntityUtils.toString(sJson.getEntity());
    }

    private static HttpResponse getJSONEntityFromURL(Context context, String url) throws ClientProtocolException, IOException {
        HttpClient httpclient = new DefaultHttpClient();
        HttpGet httpget = new HttpGet(url);
        httpget.addHeader("Accept", "application/json");
        httpget.addHeader("Content-Type", "application/json; charset=UTF-8");
        HttpResponse response;

        response = httpclient.execute(httpget);
        return response;
    }

要使上述工作正常进行,您必须编写内容提供商的批量插入方法,如下所示

    @Override
    public int bulkInsert(Uri uri, ContentValues[] values) {
        final SQLiteDatabase db = mDB.getWritableDatabase();
        final int match = sURIMatcher.match(uri);
        int numInserted= 0;
//        Util.log_debug_message("@@@@ URI MATCH - " + match);
        switch(match){
            case TEAMS:
                numInserted = insertTeams(db, values);
                break;
            default:
                throw new UnsupportedOperationException("unsupported uri: " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null, false);
        return numInserted;
    }

    private int insertTeams(SQLiteDatabase db, ContentValues[] values) {
        int numInserted = 0;
        db.beginTransaction();
        try {
        //standard SQL insert statement, that can be reused
            SQLiteStatement insert = 
                db.compileStatement(INSERT_OR_REPLACE_STRING + TeamModel.TEAM_TABLE_NAME
                        + "(" + TeamModel.COL_SERVER_ID
                        + "," + TeamModel.COL_BONUS_RACE_ID
                        + "," + TeamModel.COL_POINTS
                        + "," + TeamModel.COL_POSITION
                        + "," + TeamModel.COL_TEAM_NAME + ")"
                        +" values " + "(?,?,?,?,?)");

            for (ContentValues value : values){
    //bind the 1-indexed ?'s to the values specified
                insert.bindString(1, value.getAsString(TeamModel.COL_SERVER_ID));
                insert.bindString(2, value.getAsString(TeamModel.COL_BONUS_RACE_ID));
                insert.bindString(3, value.getAsString(TeamModel.COL_POINTS));
                insert.bindString(4, value.getAsString(TeamModel.COL_POSITION));
                insert.bindString(5, value.getAsString(TeamModel.COL_TEAM_NAME));
                insert.execute();
            }
            db.setTransactionSuccessful();
            numInserted = values.length;
        } finally {
            db.endTransaction();
            db.close();
        }
        return numInserted;
    }

这不是复制和粘贴解决方案。只是从我的一个应用程序中剥离出来的一个示例,您应该查看每一行代码并非常小心地了解发生了什么。

关于android - 从互联网资源更新 ContentProvider 的底层 SQLite 数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15886359/

相关文章:

java - 我如何按字母顺序对 listView 的文件进行排序并集成列表适配器?我正在使用自定义适配器

Android:仅获取更新和删除的联系人

android - 内容提供者 Realm

android:根据服务器响应实现应用程序搜索建议

android - 同时启动两个 Activity

java - 登录无法正常工作

android - 如何在 Android 上测试内容提供者

android - ContentProvider 抛出 SQLiteCantOpenDatabaseException : unable to open database file

android - 来自 FragmentActivity 的 fragment 在一些设备上不显示背景图像

android - ListView 自动滚动键盘弹出android