java - How do I load data in RecyclerView asynchronously? -
i have blank recycler view inside fragment. upon receiving gcm notification, call webservice. webservice store data blank database. when done, how notify recycler view update new database content?
i stuck @ portion need notify recycler view somehow update itself. implemented https://gist.github.com/skyfishjy/443b7448f59be978bc59, works when there data in database. not work in scenario.
i providing code have better understanding of problem:
package mypackage; import android.app.activity; import android.app.loadermanager; import android.content.contentresolver; import android.content.contentvalues; import android.content.cursorloader; import android.content.loader; import android.database.cursor; import android.net.uri; import android.os.asynctask; import android.os.bundle; import android.os.handler; import android.support.v4.app.fragment; import android.support.v4.view.viewcompat; import android.support.v7.widget.linearlayoutmanager; import android.support.v7.widget.recyclerview; import android.view.layoutinflater; import android.view.view; import android.view.viewgroup; import android.view.animation.overshootinterpolator; import com.squareup.picasso.picasso; import mypackage.r; import mypackage.adapters.newsrecyclerviewadapter; import mypackage.database.newsprovider; import mypackage.models.news; import mypackage.utils.saveimagetask; import java.text.simpledateformat; import java.util.arraylist; import java.util.arrays; import java.util.calendar; import java.util.date; import java.util.list; import java.util.locale; import java.util.random; import butterknife.butterknife; import jp.wasabeef.recyclerview.animators.flipinrightyanimator; import jp.wasabeef.recyclerview.animators.adapters.alphainanimationadapter; import jp.wasabeef.recyclerview.animators.adapters.scaleinanimationadapter; import static mypackage.mydbopenhelper.*; public class newslistfragment extends fragment implements loadermanager.loadercallbacks<cursor> { private newsrecyclerviewadapter madapter; private saveimagetask saveimagetask; private newstype newstype; private activity parent; public static newslistfragment newinstance(newstype newstype, activity container) { newslistfragment fragment = new newslistfragment(); fragment.saveimagetask = new saveimagetask(container); fragment.newstype = newstype; fragment.parent = container; return fragment; } @override public view oncreateview(layoutinflater inflater, viewgroup container, final bundle savedinstancestate) { view view = inflater.inflate(r.layout.recycler_view, container, false); butterknife.bind(this, view); final recyclerview mrecyclerview = (recyclerview) view.findviewbyid(r.id.my_recycler_view); mrecyclerview.sethasfixedsize(true); recyclerview.layoutmanager mlayoutmanager = new linearlayoutmanager(view.getcontext()); mrecyclerview.setlayoutmanager(mlayoutmanager); picasso picasso = new picasso.builder(parent).build(); contentresolver contentresolver = parent.getcontentresolver(); cursor newscursor; if (newstype == newstype.all) { newscursor = contentresolver.query(newsprovider.content_uri, null, null, null, null); } else { newscursor = contentresolver.query(savednewsprovider.content_uri, null, null, null, null); } madapter = new newsrecyclerviewadapter(newscursor); madapter.setpicasso(picasso); alphainanimationadapter alphaadapter = new alphainanimationadapter(madapter); scaleinanimationadapter scaleadapter = new scaleinanimationadapter(alphaadapter); scaleadapter.setfirstonly(false); scaleadapter.setinterpolator(new overshootinterpolator()); mrecyclerview.setitemanimator(new flipinrightyanimator()); mrecyclerview.getitemanimator().setaddduration(300); mrecyclerview.setadapter(scaleadapter); viewcompat.setelevation(view, 50); parent.getloadermanager().initloader(0, null, this); new asynctask<void, void, void>() { @override protected void doinbackground(void... params) { cursor news = parent.getcontentresolver().query(newsprovider.content_uri, null, null, null, null); if (news == null || news.getcount() == 0) { insertnewslist(); } else { news.close(); } return null; } @override protected void onpostexecute(void avoid) { parent.getloadermanager().restartloader(0, null, newslistfragment.this); madapter.notifydatasetchanged(); contentresolver.requestsync(null, newsprovider.authority, new bundle()); mrecyclerview.refreshdrawablestate(); mrecyclerview.postinvalidate(); } }.execute(null, null, null); return view; } private void insertnewslist() { string[] titles = {"web", "java", "android"}; random random = new random(calendar.getinstance().gettimeinmillis()); (string title : titles) { int count = random.nextint(20); list<news> newslist = generatedataset(title, count); (news dataobject : newslist) { contentvalues initialvalues = new contentvalues(); initialvalues.put(news_image_link, dataobject.gettopimagelink()); initialvalues.put(news_image_path, dataobject.gettopimagepath()); initialvalues.put(news_link, dataobject.getlink()); initialvalues.put(news_source, dataobject.getsourcetext()); initialvalues.put(news_source_img_link, dataobject.getsourceimagelink()); initialvalues.put(news_source_img_path, dataobject.getsourceimagepath()); initialvalues.put(news_tags, arrays.tostring(dataobject.gettag())); initialvalues.put(news_text, dataobject.gettext()); initialvalues.put(news_time, getdatetime()); initialvalues.put(news_title, dataobject.gettitle()); parent.getcontentresolver().insert(newsprovider.content_uri, initialvalues); } } } @override public void ondestroy() { super.ondestroy(); } @override public loader<cursor> oncreateloader(int id, bundle args) { return new cursorloader(parent, newsprovider.content_uri, null, null, null, null); } @override public void onloadfinished(loader<cursor> loader, cursor data) { madapter.swapcursor(data); } @override public void onloaderreset(loader<cursor> loader) { madapter.swapcursor(null); } private list<news> generatedataset(string subject, int count) { string title = "neque porro quisquam est qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit..."; string text = "lorem ipsum dolor sit amet, consectetur adipiscing elit. pellentesque porttitor nulla nec nulla fermentum, " + "quis imperdiet ipsum aliquet. phasellus quis odio sit amet nulla rutrum porta. quisque in ultrices metus." + " aliquam gravida et lacus ac vestibulum."; string topimagelink = "http://lorempixel.com/1024/768/"; string[] categories = {"abstract", "city", "people", "transport", "animals", "food", "nature", "business", "nightlife", "sports", "cats", "fashion", "technics"}; string sourceimagelink = "http://thegg.net/wp-content/themes/orizon/css/blue_css/images/rss-icon.png"; string sourcetext = "random blog"; string link = "http://www.google.com"; list<news> results = new arraylist<>(); (int index = 0; index < count; index++) { int imgindex = index % 12; string imgtext = subject + "-card-" + index; string newtitle = imgtext + " " + title; news obj = new news(newtitle); if (index % 2 == 0) { obj.settext(text); } else { obj.settopimagelink(topimagelink + categories[imgindex] + "/" + imgtext); } if (index % 5 != 0) { obj.setsourceimagelink(sourceimagelink); obj.setsourcetext(sourcetext); } if (index % 7 == 0) { obj.settext(text); obj.settopimagelink(topimagelink + categories[imgindex] + "/" + imgtext); obj.setsourceimagelink(sourceimagelink); obj.setsourcetext(sourcetext); } if (obj.gettopimagelink() != null && !"".equalsignorecase(obj.gettopimagelink())) { uri topimageuri = saveimagetask.saveimagefile(obj.gettopimagelink()); obj.settopimagepath(topimageuri.getpath()); } if (obj.getsourceimagelink() != null && !"".equalsignorecase(obj.getsourceimagelink())) { uri sourceimageuri = saveimagetask.saveimagefile(obj.getsourceimagelink()); obj.setsourceimagepath(sourceimageuri.getpath()); } obj.setlink(link); obj.settag(new string[] {subject}); results.add(index, obj); } return results; } private string getdatetime() { simpledateformat dateformat = new simpledateformat( "yyyy-mm-dd hh:mm:ss", locale.getdefault()); date date = new date(); return dateformat.format(date); } public enum newstype { all, favorite } }
my contentprovider
package mypackage.database; import android.content.contentprovider; import android.content.contentvalues; import android.database.sqlite.sqlitedatabase; import android.net.uri; public abstract class newsprovider extends contentprovider { public static final string authority = "myapp.data.newsprovider"; private static final string base_path = "news"; public static final uri content_uri = uri.parse("content://" + authority + "/" + base_path ); // constant identify requested operation private static final int news = 1; private static final int news_id = 2; private static final int news_tag = 3; private static final urimatcher urimatcher = new urimatcher(urimatcher.no_match); static { urimatcher.adduri(authority, base_path, news); urimatcher.adduri(authority, base_path + "/#", news_id); urimatcher.adduri(authority, base_path + "/tag/*", news_tag); } private string tablename; private string basepath; protected sqlitedatabase database; public newsprovider() { this.tablename = table_news; this.basepath = base_path; } @override public boolean oncreate() { mydbopenhelper helper = new mydbopenhelper(getcontext()); database = helper.getwritabledatabase(); return true; } @override public string gettype(uri uri) { return null; } @override public cursor query(uri uri, string[] projection, string selection, string[] selectionargs, string sortorder) { if (urimatcher.match(uri) == news_id) { selection = news_id + "=" + uri.getlastpathsegment(); } if (urimatcher.match(uri) == news_tag) { selection = news_tags + " %'" + uri.getlastpathsegment() + "'%"; } return database.query(table_news, news_all_columns, selection, null, null, null, news_time + " desc"); } @override public uri insert(uri uri, contentvalues values) { long id = database.insert(tablename, null, values); uri newuri = uri.parse(basepath + "/" + id); getcontext().getcontentresolver().notifychange(newuri, null); return newuri; } @override public int delete(uri uri, string selection, string[] selectionargs) { return database.delete(tablename, selection, selectionargs); } @override public int update(uri uri, contentvalues values, string selection, string[] selectionargs) { return database.update(tablename, values, selection, selectionargs); } }
i stuck @ portion need notify recycler view somehow update itself. implemented https://gist.github.com/skyfishjy/443b7448f59be978bc59, works when there data in database. not work in scenario.
if have contentprovider
, using cursorloader, upon notify of correct uri
, framework should query database again. if not using contentprovider, use localbroadcastmanger, broadcast event after insertion of new data in database. fragment should register event , re-query database manually
Comments
Post a Comment