使用ContentProvider,多线程app取到值不一致

在安卓中四大组件之一ContentProvider进程就不一致,于是我就改自己这边逻辑,也取和改数据通过我的大家一定不陌生,我最近在优化自己的模块时发生一个BUG,我是提供Provider数据的app,但是其他来取我数据的app和我保存的值不一样。

成都创新互联公司长期为近千家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为坡头企业提供专业的网站建设、网站设计,坡头网站改版等技术服务。拥有10多年丰富建站经验和众多成功案例,为您定制开发。

后来发现因为我是用SharedPreferences+ContentProvider的方式存储数据提供给各个APP的,原来我的主程序代码和Provider在一个进程下,但调我Provider的APP太多了,导致我的程序即使退出在后台也占用内存不会杀死,于是把Provider独立了另一个进程,于是主进程就能释放内存了。但是引起了以上问题。

经过查了很多文章,推敲应该是由于SharedPreferences在多线程下的确会取得数据不一致,看到一个大佬的回答有所启发。我以前取数据都是直接从自己目录下SharedPreferences里拿的,那进程就是我主程序的进程,和提供其他APP数据的Provider进程就不一致,于是我就改自己这边逻辑,也取和改数据通过我的Provider来操作,终于解决了这个问题。

public static UserInfoBean getLoginedUserInfo () {

    UserInfoBean userInfo = null;

    ContentResolver cr = UcApp.sCtx.getContentResolver();
    Cursor cursor = cr.query(Const.URI.USER_INFO,
            null, null, null, null);

    if ( null == cursor ) {
        LogUtils.w("getLoginedUserInfo cursor == null");
        return userInfo;
    }

    Bundle bundle = cursor.getExtras();

    boolean isLogined = bundle.getBoolean(Const.SpUser.Key.IS_LOGINED, false);
    if ( ! isLogined ) {
        LogUtils.w("getLoginedUserInfo isLogined = false");
        return userInfo;
    }

    userInfo = new UserInfoBean();
    userInfo.isLogined = true;
    userInfo.username = bundle.getString(Const.SpUser.Key.USERNAME, "");
    userInfo.token = bundle.getString(Const.SpUser.Key.TOKEN, "");

    cursor.close();

    LogUtils.w(userInfo.toString());

    return userInfo;
}

        public static void saveLoginedUserInfo (UserInfoBean userInfo, boolean isSaveToken) {

    if ( null == userInfo ) {
        return;
    }

    ContentResolver cr = UcApp.sCtx.getContentResolver();
    ContentValues values = new ContentValues();

    values.put(Const.SpUser.Key.IS_LOGINED, true);
    values.put(Const.SpUser.Key.USERNAME, userInfo.username);
    values.put(Const.SpUser.Key.TOKEN, userInfo.token);

    userInfo.usernameEncode = ComUtils.URLEncoder(userInfo.username);
    values.put(Const.SpUser.Key.USERNAME_ENCODE, userInfo.usernameEncode);

    cr.update(Const.URI.USER_INFO, values, null, null);
}

        @Override
public Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs,
                     String sortOrder) {

    Cursor cursor = new MatrixCursor(new String[]{});
    Bundle bundle = new Bundle();

        UserInfoBean userInfo = getLoginedUserInfo();

        if ( null != userInfo ) {
            bundle.putBoolean(Const.SpUser.Key.IS_LOGINED, true);
            bundle.putString(Const.SpUser.Key.USERNAME, userInfo.username);
            bundle.putString(Const.SpUser.Key.TOKEN, userInfo.token);
        } else {
            bundle.putBoolean(Const.SpUser.Key.IS_LOGINED, false);
        }
    }

    LogUtils.w(bundle.toString());

    return cursor;
}

@Override
public int update (Uri uri, ContentValues values, String selection,
                   String[] selectionArgs) {

    if ( null == values ) {
        return 0;
    }

    LogUtils.w(values.toString());

    SpUtils spUtils = new SpUtils(Const.SpUser.NAME);
    Set keys = values.keySet();
    for ( String key : keys ) {
        Object obj = values.get(key);
        if ( null != obj ) {
            spUtils.add(key, obj);
        }
    }
    spUtils.apply();

    notifyChangeUserInfo();

    return 1;
}

private UserInfoBean getLoginedUserInfo () {

    UserInfoBean userInfo = null;
    SpUtils spUtils = new SpUtils(Const.SpUser.NAME);

    boolean isLogined = (boolean) spUtils.get(Const.SpUser.Key.IS_LOGINED, false);
    if ( ! isLogined ) {
        LogUtils.w("isLogined = false");
        return userInfo;
    }

    userInfo = new UserInfoBean();
    userInfo.isLogined = true;
    userInfo.username = (String) spUtils.get(Const.SpUser.Key.USERNAME, "");
    userInfo.token = (String) spUtils.get(Const.SpUser.Key.TOKEN, "");

    return userInfo;
}

新闻标题:使用ContentProvider,多线程app取到值不一致
网页网址:http://myzitong.com/article/ihecdo.html