Good day, I am developing sql cashing mechanism for my news feed application and I have some troubles with realization.
I am working with RecyclerView (ListView) and I created class "DataHelper" in witch I have method "getNode":
public NewsNode getNode(int id, int hash, String tableName, DbHelper.NodeLoadCallback callback) {
nodeCallback = callback;
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = db.rawQuery("Select * FROM " + newsTableName + " WHERE id = '" + Integer.toString(id) +"';", null);
if (c.moveToFirst()) {
// exist in db
int hashColIndex = c.getColumnIndex("hash");
if (hash == c.getInt(hashColIndex)) {
// dont need change
return new NewsNode(c.getInt(c.getColumnIndex("id")), c.getInt(c.getColumnIndex("hash")), c.getString(c.getColumnIndex("title")), c.getString(c.getColumnIndex("description")), c.getString(c.getColumnIndex("image")));
} else {
new LoadNodeAsync().execute();
return null;
}
} else {
new LoadNodeAsync().execute();
return null;
}
}
private class LoadNodeAsync extends AsyncTask<Integer, Void, NewsNode> {
@Override
protected void onPreExecute() { }
@Override
protected NewsNode doInBackground(Integer... id) {
JSONObject json = JsonParser.downloadJson(getNewsNodeUrl); // по API сгенерировать id getter
if (json != null) {
try {
JSONObject node = json.getJSONObject("node");
DbHelper dbHelper = new DbHelper(context);
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues args = new ContentValues();
args.put("id", node.getInt("id"));
args.put("hash", node.getInt("hash"));
args.put("title", node.getString("title"));
args.put("description", node.getString("description"));
args.put("image", WorkWithImage.saveToInternalStorage(WorkWithImage.downloadImage(node.getString("image")), newsTableName + id.toString(), context)); // !!!
Cursor c = db.rawQuery("Select * FROM " + newsTableName + " WHERE id = '" + id.toString() + "';", null);
if (c.moveToFirst()) {
// need change row
db.update(newsTableName, args, "id" + "=" + id.toString(), null);
} else {
// need create new row in db
db.insert(newsTableName, null, args);
}
return new NewsNode(node.getInt("id"), node.getInt("hash"), node.getString("title"), node.getString("description"), newsTableName + id.toString()); // link to image
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onPostExecute(NewsNode node) {
if (node != null) {
nodeCallback.nodeLoadCallback(node);
} else {
// error
}
}
}
It is called in RecyclerView.Adapter -> onBindViewHolder method, i.e. every time, when user scrolled to specific node in my list:
public void onBindViewHolder(ViewHolder holder, int position) {
if (this.nodes.get(position).isNeedLoad()) {
NewsNode node = dbHelper.getNode(this.nodes.get(position).getId(),this.nodes.get(position).getHash(), DbHelper.newsTableName, activity);
// еif not null => load from cash, else handle result in callback method
if (node != null) {
holder.title.setText(node.getTitle());
holder.description.setText(node.getDescription());
holder.image.setImageBitmap(WorkWithImage.loadImageFromStorage(node.getImage()));
}
} else {
holder.title.setText(this.nodes.get(position).getTitle());
holder.description.setText(this.nodes.get(position).getDescription());
holder.image.setImageBitmap(WorkWithImage.loadImageFromStorage(this.nodes.get(position).getImage()));
}
}
In my "getNode" method I checked first if there is a local copy of node and if it doesn't need to be changed (via hash condition), then I just go to my sqlite db and return value, thats okay. But if I need to update data, I have to start async task and load data from internet. So the question is: how can I handle result in my ListView? I can't return download value from "getNode" method, bcs I am using another Thread and don't want to freeze UI. All what I thought at the moment is to create callback interface and when data is loaded notify adapter about changes:
public void nodeLoadCallback(NewsNode callbackNode) {
for (int i = 0; i< nodes.size(); i++) {
if (nodes.get(i).getId() == callbackNode.getId()) {
nodes.set(i, callbackNode);
}
}
mAdapter.notifyDataSetChanged(); // ??? reload all ??
}
But in my opinion it is too rough. I am hoping some1 understand my problem and will help with some tips. Thx!!
Aucun commentaire:
Enregistrer un commentaire