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