在我的示例项目中,我从服务器读取数据,将它们存储在sqlite中并通过内容提供程序读取它们。数据以网格视图显示。 例如,我在CMS中插入了一个带有标题的新图像并显示出来。但是,当我从服务器中删除此图像并再次运行应用程序时,删除的图像仍然存在!!
这是我使用装载程序的片段。
public class MainActivityFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{
static public ArrayList<MyCity> cityList;
public String [] MY_CITY_PROJECTIONS = {MyCityContract.MyCityEntry._ID,
MyCityContract.MyCityEntry.COLUMN_NAME,
MyCityContract.MyCityEntry.COLUMN_ICON};
public final static int COL_IMAGE_ID = 0;
public final static int COL_NAME = 1;
public final static int COL_ICON = 2;
private static final String LOG_TAG = MainActivityFragment.class.getSimpleName();
public static MyCityAdpapter myCityAdpapter;
private static final int CURSOR_LOADER_ID = 0;
private GridView mGridView;
public MainActivityFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// inflate fragment_main layout
final View rootView = inflater.inflate(R.layout.fragment_main_activity, container, false);
cityList = new ArrayList<>();
myCityAdpapter = new MyCityAdpapter(getActivity(), null, 0, CURSOR_LOADER_ID);
// initialize mGridView to the GridView in fragment_main.xml
mGridView = (GridView) rootView.findViewById(R.id.flavors_grid);
// set mGridView adapter to our CursorAdapter
mGridView.setAdapter(myCityAdpapter);
getActivity().getSupportLoaderManager();
// initialize loader
updateCityData();
super.onCreate(savedInstanceState);
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this);
super.onActivityCreated(savedInstanceState);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case CURSOR_LOADER_ID:
return new CursorLoader(getActivity(),
MyCityContract.MyCityEntry.CONTENT_URI,
MY_CITY_PROJECTIONS,
null,
null,
null);
default:
throw new IllegalArgumentException("id not handled!");
}
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
myCityAdpapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader){
myCityAdpapter.swapCursor(null);
}
public void updateCityData() {
MyCitySyncAdapter.syncImmediately(getActivity());
}
}
我读取了json数据并将它们插入我的SynAdapter
中的sqlite中 public class MyCitySyncAdapter extends AbstractThreadedSyncAdapter {
public static final int SYNC_INTERVAL = 60 * 180;
public static final int SYNC_FLEXTIME = SYNC_INTERVAL/3;
public String [] MY_CITY_PROJECTIONS = {MyCityContract.MyCityEntry._ID,
MyCityContract.MyCityEntry.COLUMN_NAME,
MyCityContract.MyCityEntry.COLUMN_ICON};
public MyCitySyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
}
@Override
public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) {
cityList.clear();
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(getContext());
// Request a string response from the provided URL.
JsonArrayRequest jsObjRequest = new JsonArrayRequest(Request.Method.GET, API.API_URL, new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
//hidePD();
// Parse json data.
// Declare the json objects that we need and then for loop through the children array.
// Do the json parse in a try catch block to catch the exceptions
try {
for (int i = 0; i < response.length(); i++) {
JSONObject post = response.getJSONObject(i);
MyCity item = new MyCity();
item.setName(post.getString("title"));
item.setImage(API.IMAGE_URL + post.getString("image"));
ContentValues imageValues = new ContentValues();
imageValues.put(MyCityContract.MyCityEntry._ID, post.getString("id"));
imageValues.put(MyCityContract.MyCityEntry.COLUMN_NAME, post.getString("title"));
imageValues.put(MyCityContract.MyCityEntry.COLUMN_ICON, post.getString("image"));
getContext().getContentResolver().insert(MyCityContract.MyCityEntry.CONTENT_URI, imageValues);
cityList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
// Update grid by notifying the adapter of changes
myCityAdpapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
//hidePD();
}
});
queue.add(jsObjRequest);
}
public static void configurePeriodicSync(Context context, int syncInterval, int flexTime) {
Account account = getSyncAccount(context);
String authority = context.getString(R.string.content_authority);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// we can enable inexact timers in our periodic sync
SyncRequest request = new SyncRequest.Builder().
syncPeriodic(syncInterval, flexTime).
setSyncAdapter(account, authority).
setExtras(new Bundle()).build();
ContentResolver.requestSync(request);
} else {
ContentResolver.addPeriodicSync(account,
authority, new Bundle(), syncInterval);
}
}
/**
* Helper method to have the sync adapter sync immediately
* @param context The context used to access the account service
*/
public static void syncImmediately(Context context) {
Bundle bundle = new Bundle();
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
bundle.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
ContentResolver.requestSync(getSyncAccount(context),
context.getString(R.string.content_authority), bundle);
}
public static Account getSyncAccount(Context context) {
// Get an instance of the Android account manager
AccountManager accountManager =
(AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
// Create the account type and default account
Account newAccount = new Account(
context.getString(R.string.app_name), context.getString(R.string.sync_account_type));
// If the password doesn't exist, the account doesn't exist
if ( null == accountManager.getPassword(newAccount) ) {
/*
* Add the account and account type, no password or user data
* If successful, return the Account object, otherwise report an error.
*/
if (!accountManager.addAccountExplicitly(newAccount, "", null)) {
return null;
}
/*
* If you don't set android:syncable="true" in
* in your <provider> element in the manifest,
* then call ContentResolver.setIsSyncable(account, AUTHORITY, 1)
* here.
*/
onAccountCreated(newAccount, context);
}
return newAccount;
}
private static void onAccountCreated(Account newAccount, Context context) {
/*
* Since we've created an account
*/
MyCitySyncAdapter.configurePeriodicSync(context, SYNC_INTERVAL, SYNC_FLEXTIME);
/*
* Without calling setSyncAutomatically, our periodic sync will not be enabled.
*/
ContentResolver.setSyncAutomatically(newAccount, context.getString(R.string.content_authority), true);
/*
* Finally, let's do a sync to get things started
*/
syncImmediately(context);
}
}
或者您可以查看github中的项目。
我猜我应该把getContext().getContentResolver().delete
放在某个地方..
请建议,以便我可以从sqlite删除记录,
谢谢Theo。
修改
这是一件有趣的事情。我修复了旧的数据删除问题!到现在为止还挺好。但是,当我关闭wifi时,没有显示任何内容。
@Override
public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) {
cityList.clear();
deleteOldData();
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(getContext());
// Request a string response from the provided URL.
JsonArrayRequest jsObjRequest = new JsonArrayRequest(Request.Method.GET, API.API_URL, new Response.Listener<JSONArray>() {
@Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
//hidePD();
// Parse json data.
// Declare the json objects that we need and then for loop through the children array.
// Do the json parse in a try catch block to catch the exceptions
try {
for (int i = 0; i < response.length(); i++) {
JSONObject post = response.getJSONObject(i);
MyCity item = new MyCity();
item.setName(post.getString("title"));
item.setImage(API.IMAGE_URL + post.getString("image"));
ContentValues imageValues = new ContentValues();
imageValues.put(MyCityContract.MyCityEntry._ID, post.getString("id"));
imageValues.put(MyCityContract.MyCityEntry.COLUMN_NAME, post.getString("title"));
imageValues.put(MyCityContract.MyCityEntry.COLUMN_ICON, post.getString("image"));
getContext().getContentResolver().insert(MyCityContract.MyCityEntry.CONTENT_URI, imageValues);
}
} catch (JSONException e) {
e.printStackTrace();
}
// Update grid by notifying the adapter of changes
myCityAdpapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
//hidePD();
}
});
queue.add(jsObjRequest);
}
public void deleteOldData(){
int deleted =
getContext().getContentResolver()
.delete(MyCityContract.MyCityEntry.CONTENT_URI,
null,
null);
Log.d(LOG_TAG, "Movie Review Data Deleting, " + deleted + " rows deleted.");
}
我进入wifi-off模式的logcat是:
D/Volley: [1] 2.onErrorResponse: ContentValues
我在网上模式重复一切都很完美。
答案 0 :(得分:0)
在图像删除之前和图像删除之后如果得到完整的响应然后而不是更新SQLite表,则需要从SQLite表中删除所有数据并再次插入。这是离线缓存的好习惯
在此代码执行之前,删除SQLite表中的所有数据
try {
// Clear Table before insert
for (int i = 0; i < response.length(); i++) {
JSONObject post = response.getJSONObject(i);
MyCity item = new MyCity();
item.setName(post.getString("title"));
item.setImage(API.IMAGE_URL + post.getString("image"));
ContentValues imageValues = new ContentValues();
imageValues.put(MyCityContract.MyCityEntry._ID, post.getString("id"));
imageValues.put(MyCityContract.MyCityEntry.COLUMN_NAME, post.getString("title"));
imageValues.put(MyCityContract.MyCityEntry.COLUMN_ICON, post.getString("image"));
getContext().getContentResolver().insert(MyCityContract.MyCityEntry.CONTENT_URI, imageValues);
cityList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
例如,如果您收到此回复
"city" : [
{
"value" : "city1"
},
{
"value" : "city2"
},
{
"value" : "city3"
}
]
你在SQLite中插入它。在此之后,如果“city2”删除,您将得到此回复
"city" : [
{
"value" : "city1"
},
{
"value" : "city3"
}
]
然后你开始使用insertWithOnConflict
插入,但是city1和city3得到了更新,但是city2
对于此问题,您需要删除所有城市数据并重新插入