android - Empty intent (nullpointer exception) in master/detail flow when clicking "up" in actionbar -
this might bit of lengthy post apologies in advance.
i'm using master/detail flow display list of items , when clicking on it opens detail view. items loaded webservice. works great on tablet fragments on phone keeps crashing. can display item detail (cheatviewpageindicator.java) when use "up" button on top left in action bar return parent activity (cheatlistactivity.java) app keeps crashing nullpointer exception. think i'm loading data webservice @ wrong location , that's why crashes. i'm going write code here , can give me advice how have correct way.
(i've trimmed classes bit shorten post bit.)
the "master" activity:
public class cheatlistactivity extends fragmentactivity implements cheatlistfragment.callbacks, reportcheatdialoglistener, ratecheatdialoglistener { @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_cheat_list); settings = getsharedpreferences(konstanten.preferences_file, 0); editor = settings.edit(); cm = (connectivitymanager) getsystemservice(context.connectivity_service); cheatprogressdialog = progressdialog.show(this, getstring(r.string.please_wait) + "...", getstring(r.string.retrieving_data) + "...", true); handleintent(getintent()); if (findviewbyid(r.id.cheat_detail_container) != null) { // detail container view present in // large-screen layouts (res/values-large , // res/values-sw600dp). if view present, // activity should in two-pane mode. mtwopane = true; // in two-pane mode, list items should given // 'activated' state when touched. ((cheatlistfragment) getsupportfragmentmanager().findfragmentbyid(r.id.cheat_list)).setactivateonitemclick(true); } cheatprogressdialog.dismiss(); // todo: if exposing deep links app, handle intents here. } private void handleintent(final intent intent) { new thread(new runnable() { @override public void run() { gameobj = new gson().fromjson(intent.getstringextra("gameobj"), game.class); runonuithread(new runnable() { @override public void run() { getactionbar().setdisplayhomeasupenabled(true); getactionbar().settitle(gameobj.getgamename()); getactionbar().setsubtitle(gameobj.getsystemname()); } }); try { if (cm.getactivenetworkinfo() != null) { if (member == null) { cheats = webservice.getcheatlist(gameobj, 0); } else { cheats = webservice.getcheatlist(gameobj, member.getmid()); } cheatsarraylist = new arraylist<cheat>(); if (cheats != null) { (int j = 0; j < cheats.length; j++) { cheatsarraylist.add(cheats[j]); } } else { log.e("cheatlistactivity()", "webservice.getcheatlist() == null"); } (int = 0; < cheats.length; i++) { log.d("cheats", cheats[i].getcheattitle()); } gameobj.setcheats(cheats); // put game object local storage large games // pokemon editor.putstring(konstanten.preferences_temp_game_object_view, new gson().tojson(gameobj)); editor.commit(); } else { log.e("cheattitlelist:getcheats()", "no network"); toast.maketext(cheatlistactivity.this, r.string.no_internet, toast.length_short).show(); } } catch (exception ex) { log.e(getclass().getname(), "error executing getcheats()", ex); } } }).start(); } public cheat[] getcheatsforfragment(final intent intent) { gameobj = new gson().fromjson(intent.getstringextra("gameobj"), game.class); runonuithread(new runnable() { @override public void run() { getactionbar().setdisplayhomeasupenabled(true); getactionbar().settitle(gameobj.getgamename()); getactionbar().setsubtitle(gameobj.getsystemname()); } }); try { if (cm.getactivenetworkinfo() != null) { if (member == null) { cheats = webservice.getcheatlist(gameobj, 0); } else { cheats = webservice.getcheatlist(gameobj, member.getmid()); } cheatsarraylist = new arraylist<cheat>(); if (cheats != null) { (int j = 0; j < cheats.length; j++) { cheatsarraylist.add(cheats[j]); } } else { log.e("cheatlistactivity()", "webservice.getcheatlist() == null"); } (int = 0; < cheats.length; i++) { log.d("cheats", cheats[i].getcheattitle()); } gameobj.setcheats(cheats); // put game object local storage large games pokemon editor.putstring(konstanten.preferences_temp_game_object_view, new gson().tojson(gameobj)); editor.commit(); } else { log.e("cheattitlelist:getcheats()", "no network"); toast.maketext(this, r.string.no_internet, toast.length_short).show(); } } catch (exception ex) { log.e(getclass().getname(), "error executing getcheats()", ex); } return cheats; } /** * callback method {@link cheatlistfragment.callbacks} indicating * item given id selected. */ @override public void onitemselected(int id) { if (mtwopane) { // in two-pane mode, show detail view in activity // adding or replacing detail fragment using // fragment transaction. visiblecheat = cheats[id]; cheatforumfragment = new cheatforumfragment(); cheatdetailmetafragment = new cheatdetailmetafragment(); // view tablets bundle arguments = new bundle(); arguments.putint(cheatdetailtabletfragment.arg_item_id, id); arguments.putstring("cheatobj", new gson().tojson(cheats[id])); arguments.putstring("cheatforumfragment", new gson().tojson(cheatforumfragment)); arguments.putstring("cheatdetailmetafragment", new gson().tojson(cheatdetailmetafragment)); cheatdetailfragment = new cheatdetailtabletfragment(); cheatdetailfragment.setarguments(arguments); getsupportfragmentmanager().begintransaction().replace(r.id.cheat_detail_container, cheatdetailfragment).commit(); } else { // in single-pane mode, start detail activity // selected item id. // intent detailintent = new intent(this, yyydetailactivity.class); // detailintent.putextra(yyydetailfragment.arg_item_id, id); // startactivity(detailintent); editor.putint(konstanten.preferences_page_selected, id); editor.commit(); // using local preferences pass data large game objects // (instead of intent) such pokemon intent explicitintent = new intent(cheatlistactivity.this, cheatviewpageindicator.class); explicitintent.putextra("selectedpage", id); explicitintent.putextra("layoutresourceid", r.layout.activity_cheatview_pager); explicitintent.putextra("pageindicatorcolor", konstanten.cyan_dark); startactivity(explicitintent); } } } and fragment listview.
public class cheatlistfragment extends listfragment { /** * serialization (saved instance state) bundle key representing * activated item position. used on tablets. */ private static final string state_activated_position = "activated_position"; /** * fragment's current callback object, notified of list item * clicks. */ private callbacks mcallbacks = sdummycallbacks; /** * current activated item position. used on tablets. */ private int mactivatedposition = listview.invalid_position; /** * callback interface activities containing fragment must * implement. mechanism allows activities notified of item * selections. */ public interface callbacks { /** * callback when item has been selected. */ public void onitemselected(int position); } /** * dummy implementation of {@link callbacks} interface * nothing. used when fragment not attached activity. */ private static callbacks sdummycallbacks = new callbacks() { @override public void onitemselected(int id) { } }; /** * mandatory empty constructor fragment manager instantiate * fragment (e.g. upon screen orientation changes). */ public cheatlistfragment() { } @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); cheatlistactivity = (cheatlistactivity) getactivity(); fontroboto = tools.getfontrobotoregular(getactivity().getassets()); settings = cheatlistactivity.getsharedpreferences(konstanten.preferences_file, 0); gameobj = new gson().fromjson(settings.getstring(konstanten.preferences_temp_game_object_view, null), game.class); if( gameobj == null) { new getcheatstask().execute(new game()); } else { new getcheatstask().execute(gameobj); } } private class getcheatstask extends asynctask<game, void, void> { @override protected void doinbackground(game... params) { if (params[0].getcheats() == null) { cheats = cheatlistactivity.getcheatsforfragment(cheatlistactivity.getintent()); } else { cheats = params[0].getcheats(); } (int = 0; < cheats.length; i++) { log.d("cheat item ", cheats[i].getcheattitle()); cheatsarraylist.add(cheats[i]); } return null; } @override protected void onpostexecute(void result) { super.onpostexecute(result); cheatadapter = new cheatadapter(getactivity(), r.layout.cheatlist_item, cheatsarraylist); setlistadapter(cheatadapter); } } @override public void onviewcreated(view view, bundle savedinstancestate) { super.onviewcreated(view, savedinstancestate); // restore serialized activated item position. if (savedinstancestate != null && savedinstancestate.containskey(state_activated_position)) { setactivatedposition(savedinstancestate.getint(state_activated_position)); } } @override public void onattach(activity activity) { super.onattach(activity); // activities containing fragment must implement callbacks. if (!(activity instanceof callbacks)) { throw new illegalstateexception("activity must implement fragment's callbacks."); } mcallbacks = (callbacks) activity; } @override public void ondetach() { super.ondetach(); // reset active callbacks interface dummy implementation. mcallbacks = sdummycallbacks; } @override public void onlistitemclick(listview listview, view view, int position, long id) { super.onlistitemclick(listview, view, position, id); // notify active callbacks interface (the activity, if // fragment attached one) item has been selected. // mcallbacks.onitemselected(dummycontent.items.get(position).id); mcallbacks.onitemselected(position); } @override public void onsaveinstancestate(bundle outstate) { super.onsaveinstancestate(outstate); if (mactivatedposition != listview.invalid_position) { // serialize , persist activated item position. outstate.putint(state_activated_position, mactivatedposition); } } /** * turns on activate-on-click mode. when mode on, list items * given 'activated' state when touched. */ public void setactivateonitemclick(boolean activateonitemclick) { // when setting choice_mode_single, listview automatically // give items 'activated' state when touched. getlistview().setchoicemode(activateonitemclick ? listview.choice_mode_single : listview.choice_mode_none); } private void setactivatedposition(int position) { if (position == listview.invalid_position) { getlistview().setitemchecked(mactivatedposition, false); } else { getlistview().setitemchecked(position, true); } mactivatedposition = position; } private class cheatadapter extends arrayadapter<cheat> { private final arraylist<cheat> items; public cheatadapter(context context, int textviewresourceid, arraylist<cheat> items) { super(context, textviewresourceid, items); this.items = items; } @override public view getview(int position, view convertview, viewgroup parent) { view v = convertview; if (v == null) { layoutinflater vi = (layoutinflater) getactivity().getsystemservice(context.layout_inflater_service); v = vi.inflate(r.layout.cheatlist_item, null); } try { cheat cheat = items.get(position); if (cheat != null) { textview tt = (textview) v.findviewbyid(r.id.game_title); tt.settext(cheat.getcheattitle()); tt.settypeface(fontroboto); // durchschnittsrating (nicht member-rating) ratingbar ratingbar = (ratingbar) v.findviewbyid(r.id.small_ratingbar); ratingbar.setnumstars(5); ratingbar.setrating(cheat.getratingaverage() / 2); imageview flag_newaddition = (imageview) v.findviewbyid(r.id.newaddition); if (cheat.getdayage() < konstanten.cheat_day_age_show_newaddition_icon) { flag_newaddition.setimageresource(r.drawable.flag_new); flag_newaddition.setvisibility(view.visible); } else { flag_newaddition.setvisibility(view.gone); } imageview flag_screenshots = (imageview) v.findviewbyid(r.id.screenshots); if (cheat.isscreenshots()) { flag_screenshots.setvisibility(view.visible); flag_screenshots.setimageresource(r.drawable.flag_img); } else { flag_screenshots.setvisibility(view.gone); } imageview flag_german = (imageview) v.findviewbyid(r.id.flag); if (cheat.getlanguageid() == 2) { // 2 = deutsch flag_german.setvisibility(view.visible); flag_german.setimageresource(r.drawable.flag_german); } else { flag_german.setvisibility(view.gone); } } } catch (exception e) { log.e(getclass().getname() + ".getview error:", e.getmessage()); } return v; } } } detail view in two-pane mode (on tablet):
public class cheatdetailtabletfragment extends fragment implements onclicklistener { /** * fragment argument representing item id fragment * represents. */ public static final string arg_item_id = "item_id"; /** * dummy content fragment presenting. */ private cheatcontent.cheatitem mitem; private view rootview; /** * mandatory empty constructor fragment manager instantiate * fragment (e.g. upon screen orientation changes). */ public cheatdetailtabletfragment() { } @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); ca = (cheatlistactivity) getactivity(); cheattitletypeface = tools.getfontrobotothin(getactivity().getassets()); cheattexttypeface = tools.getfontrobotoregular(getactivity().getassets()); settings = getactivity().getsharedpreferences(konstanten.preferences_file, 0); editor = settings.edit(); if (getarguments().containskey(arg_item_id)) { // load dummy content specified fragment // arguments. in real-world scenario, use loader // load content content provider. mitem = cheatcontent.item_map.get(getarguments().getint(arg_item_id)); cheatobj = new gson().fromjson(getarguments().getstring("cheatobj"), cheat.class); cheatforumfragment = new gson().fromjson(getarguments().getstring("cheatforumfragment"), cheatforumfragment.class); cheatdetailmetafragment = new gson().fromjson(getarguments().getstring("cheatdetailmetafragment"), cheatdetailmetafragment.class); } } @override public view oncreateview(layoutinflater inflater, viewgroup container, bundle savedinstancestate) { rootview = inflater.inflate(r.layout.fragment_cheat_detail, container, false); // ... // show dummy content text in textview. if (mitem != null) { ((textview) rootview.findviewbyid(r.id.text_cheat_before_table)).settext(mitem.getcheattitle()); ((textview) rootview.findviewbyid(r.id.text_cheat_title)).settext(mitem.getcheatid()); } // ... populateview(); return rootview; } /** * create layout */ private void populateview() { // fills view. no problems here. } /** * populate table layout */ private void filltablecontent() { // filling table content here. no problems here. } private void fillsimplecontent() { // filling other content. works fine, too. } } detail view in one-pane mode (on phone):
public class cheatviewpageindicator extends fragmentactivity implements reportcheatdialoglistener, ratecheatdialoglistener { // define variables... public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); layoutinflater inflater = layoutinflater.from(this); intent = getintent(); viewlayout = inflater.inflate(intent.getintextra("layoutresourceid", r.layout.activity_cheatview_pager), null); setcontentview(viewlayout); settings = getsharedpreferences(konstanten.preferences_file, 0); editor = settings.edit(); getactionbar().sethomebuttonenabled(true); getactionbar().setdisplayhomeasupenabled(true); try { gameobj = new gson().fromjson(settings.getstring(konstanten.preferences_temp_game_object_view, null), game.class); if (gameobj == null) { gameobj = new gson().fromjson(intent.getstringextra("gameobj"), game.class); } editor.putstring(konstanten.preferences_temp_game_object_view, new gson().tojson(gameobj)); editor.commit(); pageselected = intent.getintextra("selectedpage", 0); activepage = pageselected; pageindicatorcolor = intent.getintextra("pageindicatorcolor", konstanten.cyan_dark); cheatobj = gameobj.getcheats(); visiblecheat = cheatobj[pageselected]; getactionbar().settitle(gameobj.getgamename()); getactionbar().setsubtitle(gameobj.getsystemname()); initialisepaging(); } catch (exception e) { log.e(cheatviewpageindicator.class.getname(), e.getmessage() + ""); } } private void initialisepaging() { // ... } @override public boolean oncreateoptionsmenu(menu menu) { getmenuinflater().inflate(r.menu.handset_cheatview_menu, menu); // search getmenuinflater().inflate(r.menu.search_menu, menu); // associate searchable configuration searchview searchmanager searchmanager = (searchmanager) getsystemservice(context.search_service); searchview searchview = (searchview) menu.finditem(r.id.search).getactionview(); searchview.setsearchableinfo(searchmanager.getsearchableinfo(getcomponentname())); return super.oncreateoptionsmenu(menu); } @override protected void onresume() { super.onresume(); invalidateoptionsmenu(); } public connectivitymanager getconnectivitymanager() { if (cm == null) { cm = (connectivitymanager) getsystemservice(context.connectivity_service); } return cm; } @override public boolean onoptionsitemselected(menuitem item) { switch (item.getitemid()) { case android.r.id.home: // id represents home or button. in case of // activity, button shown. use navutils allow users // navigate 1 level in application structure. // more details, see navigation pattern on android design: // // http://developer.android.com/design/patterns/navigation.html#up-vs-back // onbackpressed(); // return true; intent upintent = new intent(this, cheatlistactivity.class); navutils.getparentactivityintent(this); if (navutils.shoulduprecreatetask(this, upintent)) { // activity not part of app's task, create new // task when navigating up, synthesized stack. taskstackbuilder.create(this) // add of activity's parents stack .addnextintentwithparentstack(upintent) // navigate closest parent .startactivities(); } else { // activity part of app's task, // navigate logical parent activity. // navutils.navigateupto(this, upintent); upintent.addflags(intent.flag_activity_clear_top); startactivity(upintent); finish(); } return true; } return super.onoptionsitemselected(item); } } so in 1 pane mode (on phone) when click "up" button in action bar cheatviewpageindicator.java 1 cheatlistactivity.java nullpointer exception pointing line:
gameobj = new gson().fromjson(intent.getstringextra("gameobj"), game.class); seems "intent" null when going back. i'm wondering why is? need keep data in intent? (or other solution how rid of nullpointer fine me, too). i'm bit desperate, i've been searching solution long.
thanks lot help.
i'm sure problem comes onoptionsitemselected() in cheatviewpageindicator. don't need start new activity there, in master-detail pattern there's 1 , same activity @ time. fragments changing.
to provide ability use "up" button should call fragmenttransaction.addtobackstack(null) while adding fragments. android handle stack logic itself. don't @ in android.r.id.home case, don't need it.
Comments
Post a Comment