ListView empties after switching a fragment in fragmentHolder - android

I have a listview in one of my fragments and it empties when I leave that fragment.
Why is it happening?
That fragment:
public class ListActivity extends ListFragment {
public void ToastLoadShout(String msg) {
Toast.makeText(getActivity(), msg.toString(), Toast.LENGTH_LONG).show();
}
private static View View;
HttpClient client;
HttpPost httppost;
HttpGet httpget;
JSONObject json;
List<List<String>> items;
List<item> markers = new ArrayList<item>();
MobileArrayAdapter adapter;
ListView list;
ProgressBar listload;
Button relist;
Preferences pref;
String datadata = "";
String savedlat="0.0";
String savedlon="0.0";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_list, container, false);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
try {
pref = new Preferences(getActivity());
list = (ListView) getView().findViewById(android.R.id.list);
listload = (ProgressBar) getView().findViewById(R.id.listload);
HashMap<String, String> loc = pref.getData();
ToastLoadShout(loc.get(Preferences.LAT) + ","
+ loc.get(Preferences.LON));
if (loc.get(Preferences.LAT) != "0.0" && loc.get(Preferences.LAT) != null)
{
//adapter.deleteList();
//list.destroyDrawingCache();
if (loc.get(Preferences.LAT) != savedlat && loc.get(Preferences.LON)!=savedlon){
new Load().execute();
savedlat=loc.get(Preferences.LAT);
savedlon=loc.get(Preferences.LON);
}
}
else
ToastLoadShout("Get Location First.");
relist = (Button) getView().findViewById(R.id.relist);
relist.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
listload.setVisibility(View.INVISIBLE);
HashMap<String, String> loc = pref.getData();
ToastLoadShout(loc.get(Preferences.LAT) + ","
+ loc.get(Preferences.LON));
if (loc.get(Preferences.LAT) != "0.0" && loc.get(Preferences.LAT) != null){
adapter.deleteList();
list.destroyDrawingCache();
new Load().execute();}
else
ToastLoadShout("Get Location First.");
}});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// get selected items
//String selectedValue = (String) getListAdapter().getItem(position);
String selectedValue = markers.get(position).getTitle();
Toast.makeText(getActivity(), selectedValue, Toast.LENGTH_SHORT).show();
}
}
And the MainActivity which holds the fragments:
public class Fragments extends FragmentActivity {
Fragment newFragment;
Button Add;
public void ToastLoadShout(String msg) {
Toast.makeText(this, msg.toString(), Toast.LENGTH_SHORT).show();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragments);
//Set Custom actionBar<
getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
getActionBar().setCustomView(R.layout.titlebar);
getActionBar().setHomeButtonEnabled(true);
getActionBar().setDisplayHomeAsUpEnabled(true);
//Set Custom actionBar>
ListActivity fragment = new ListActivity();
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.add(R.id.fragment_place, fragment,"Nearby");
transaction.commit();
turnGPSOn();
Add = (Button)findViewById(R.id.add);
Add.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent Intent = new Intent(Fragments.this,Add.class);
Bundle bndlanimation =
ActivityOptions.makeCustomAnimation(getApplicationContext(),
R.anim.animation,R.anim.animation2).toBundle();
startActivity(Intent, bndlanimation);
}
});
/* For putting commas in attractin's checkIns
String number = "1345";
int amount = Integer.parseInt(number);
DecimalFormat formatter = new DecimalFormat("#,###");
ToastLoadShout(formatter.format(amount));*/
}
public void onSelectFragment(View view) {
String fragTag="";
boolean needNew=false;
if (view == findViewById(R.id.map))
{
Fragment f = getSupportFragmentManager().findFragmentByTag("Map");
if (f==null){
newFragment = new MainActivity();
needNew=true;
fragTag="Map";
}
else{
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_place, f, "Map"); //or whatever other string you want to use
transaction.addToBackStack(null);
transaction.commit();
}
}
else if (view == findViewById(R.id.nearby))
{
Fragment f = getSupportFragmentManager().findFragmentByTag("Nearby");
if (f==null){
newFragment = new ListActivity();
needNew=true;
fragTag="Nearby";
}
else{
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_place, f, "Nearby"); //or whatever other string you want to use
transaction.addToBackStack(null);
transaction.commit();
}
}
if (needNew) {
FragmentTransaction transaction = getSupportFragmentManager()
.beginTransaction();
transaction.replace(R.id.fragment_place, newFragment, fragTag);
transaction.addToBackStack(null);
transaction.commit();
}
}
}
Already tried loading the list on OnCreate. Doesn't work at all.
Thanks for your assistance.
EDIT:
Load.Class:
class Load extends AsyncTask<String, Integer, Boolean> {
#Override
protected void onPreExecute() {
listload.setVisibility(View.VISIBLE);
}
#Override
protected Boolean doInBackground(String... params) {
try {
items = DownloadList();
if (items != null)
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
return false;
}
#Override
protected void onPostExecute(Boolean res) {
// TODO Auto-generated method stub
if (res) {
ArrangePutMarkers();
adapter=new MobileArrayAdapter(getActivity(), markers);
list.setAdapter(adapter);
} else {
ToastLoadShout("Error");
ToastLoadShout(datadata);
}
listload.setVisibility(View.INVISIBLE);
}
}

As i can see you recreate the loc object every time the fragment is displayed.
It obviously makes you fragment to reload the data.

Keep your adapter in activity as a field. Destroying everything in your fragment when you leave it is a normal thing. setRetainInstance() works only on configuration changes, such as screen rotating. Recreate your list every time you came back in your fragment (in onActivityCreated(), for example, like you do know) and supply it with your stored adapter with saved data in it. You can gain access to your activity inside a fragment, for example, by casting (MainActivity)getActivity(), as an Activity which is passed to this fragment in this case is actually your activity.

Related

How to open link in a fragment with webview when a specific item is clicked from listview fragment

I have an Android app with a navigation drawer with menu items.This menu contains entry to multiple fragments. One of the fragments has a listview in it with names of websites. My aim is that whenever a name of website is clicked from that list the link associated with the listview item saved in stringarray in strings.xml file is opened in new fragment with webview which opens the site.
So far I have implemented this code for the fragment with listview
class AtlasListFragment extends android.support.v4.app.ListFragment implements AdapterView.OnItemClickListener {
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.atlas_list_fragment, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ArrayAdapter adapter = ArrayAdapter.createFromResource(getActivity(),
R.array.tut_titles, android.R.layout.simple_list_item_1);
setListAdapter(adapter);
getListView().setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
Toast.makeText(getActivity(), "Item: " + position, Toast.LENGTH_SHORT).show();
}}
And the code which launches the fragment from navigation drawer is below
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
android.support.v4.app.Fragment fragment = null;
if (id == R.id.home) {
fragment = frag;
else if (id == R.id.settings) {
fragment=new Settings();
} else if (id == R.id.about_us) {
fragment=new AboutUc();
}
else if(id == R.id.atlas){
fragment = new AtlasListFragment();
}
else{
}
if (fragment!=null)
{
FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction ft=fragmentManager.beginTransaction();
ft.replace(R.id.fragmentview,fragment);
ft.commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
By this mehod you can open a webview in where you want use WebView layout and use this method in your activity
public void openWebView(String url){
webView = (WebView) findViewById(R.id.webView1);
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl(url);
}
Hope it works for you
First of all you will need broadcast so you can send your clicked
URL from adapter to your fragment, and in your main fragment when you
receive the url you can use intent or webview
1- CREATE BroadcastHelper CLASS :
public class BroadcastHelper {
public static final String BROADCAST_EXTRA_METHOD_NAME = "INPUT_METHOD_CHANGED";
public static final String ACTION_NAME = "hassan.hossam";
private static final String UPDATE_LOCATION_METHOD = "updateLocation";
public static void sendInform(Context context, String method) {
Intent intent = new Intent();
intent.setAction(ACTION_NAME);
intent.putExtra(BROADCAST_EXTRA_METHOD_NAME, method);
try {
context.sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void sendInform(Context context, String method, Intent intent) {
intent.setAction(ACTION_NAME);
intent.putExtra(BROADCAST_EXTRA_METHOD_NAME, method);
try {
context.sendBroadcast(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2- Send intent from your adapter
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent url = new Intent("url");
url ("url_adapter",item.get(position).getURL());
BroadcastHelper.sendInform(context,"url",url);
}
});
3- in your fragment this use :
Receiver receiver;
boolean isReciverRegistered = false;
#Override
public void onResume() {
super.onResume();
if (receiver == null) {
receiver = new Receiver();
IntentFilter filter = new IntentFilter(BroadcastHelper.ACTION_NAME);
getActivity().registerReceiver(receiver, filter);
isReciverRegistered = true;
}
}
#Override
public void onDestroy() {
if (isReciverRegistered) {
if (receiver != null)
getActivity().unregisterReceiver(receiver);
}
super.onDestroy();
}
private class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context arg0, Intent arg1) {
Log.v("r", "receive " + arg1.getStringExtra(BroadcastHelper.BROADCAST_EXTRA_METHOD_NAME));
String methodName = arg1.getStringExtra(BroadcastHelper.BROADCAST_EXTRA_METHOD_NAME);
if (methodName != null && methodName.length() > 0) {
Log.v("receive", methodName);
switch (methodName) {
case "url":
String url_adapter = arg1.getStringExtra("url_adapter");
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url_adapter));
startActivity(i);
break;
default:
break;
}
}
}
}
i hope this helped

notifyDataSetChanged stop working after onDestroy in fragment

I've got a fragment with a RecyclerView inside. All is working good but when I press home, navigate in other apps and then go back in my app the view gets recreated and my ArrayList (restored from onSaveInstanceState) is not displayed in my recyclerview that don't work even after updating the List.
Here some code:
-Activity
public class MainActivity extends AppCompatActivity {
FragmentTransaction ft;
BottomNavigationView bottomNavigationView;
int current;
private FirebaseAnalytics mFirebaseAnalytics;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState==null) {
setupFragment();
}
// mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
bottomNavigationView = (BottomNavigationView)
findViewById(R.id.bottom_navigation);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_golden_hour:
changeFragment(new GoldenFragment(), "GOLDEN");
current=0;
break;
case R.id.action_hyperfocal:
changeFragment(new HyperFragment(), "HYPER");
current=1;
break;
case R.id.action_ir:
changeFragment(new IrFragment(), "IR");
current=2;
break;
case R.id.action_nd:
changeFragment(new NdFragment(), "ND");
current=3;
break;
}
return true;
}
});
}
#SuppressLint("CommitTransaction")
private void setupFragment(){
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.main_fragment, new GoldenFragment()).commit();
current=0;
}
#SuppressLint("CommitTransaction")
private void changeFragment(Fragment fragment, String tag){
ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.main_fragment, fragment, tag).commit();
}
-Fragment
public class GoldenFragment extends Fragment implements DatePickerDialog.OnDateSetListener{
SupportPlaceAutocompleteFragment autocompleteFragment;
RecyclerView rv;
CustomAdapter adapter;
ProgressBar pb;
ArrayList<Hours> hours;
CardView cv;
TextView emptyGoldenText;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
thisContext = getContext();
setHasOptionsMenu(true);
ampm = !android.text.format.DateFormat.is24HourFormat(thisContext);
hours = new ArrayList<>();
adapter = new CustomAdapter(thisContext, hours);
if(savedInstanceState!=null) {
Log.d(TAG,"inState not null");
hours.clear();
hours = savedInstanceState.getParcelableArrayList("HoursList");
}
Log.d(TAG,"onCreate() called");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
if(view == null) {
view = inflater.inflate(R.layout.fragment_golden, container, false);
}
Toolbar goldenToolbar = (Toolbar) view.findViewById(R.id.toolbar_golden);
((AppCompatActivity) getActivity()).setSupportActionBar(goldenToolbar);
emptyGoldenText = (TextView) view.findViewById(R.id.empty_golden_text);
autocompleteFragment = (SupportPlaceAutocompleteFragment) getChildFragmentManager()
.findFragmentById(R.id.place_autocomplete_fragment);
if (autocompleteFragment == null) {
autocompleteFragment = (SupportPlaceAutocompleteFragment) SupportPlaceAutocompleteFragment
.instantiate(thisContext, "com.google.android.gms.location.places.ui.SupportPlaceAutocompleteFragment");
}
autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
Log.i(TAG, "Place: " + place.getName());
try {
new GeoCoding()
.execute("https://maps.googleapis.com/maps/api/geocode/json?address="+place.getName()+"&key="+geoKEY);
} catch (Exception e) {
Toast.makeText(thisContext,"Cannot contact Google's servers, please try later.", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
#Override
public void onError(Status status) {
Log.i(TAG, "An error occurred: " + status);
}
});
getChildFragmentManager().beginTransaction()
.replace(R.id.place_autocomplete_fragment, autocompleteFragment).commit();
//Initialize RecyclerView
rv = (RecyclerView)view.findViewById(R.id.list_golden);
rv.setLayoutManager(new LinearLayoutManager(thisContext));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(rv.getContext(),
getActivity().getResources().getConfiguration().orientation);
rv.addItemDecoration(dividerItemDecoration);
rv.setAdapter(adapter);
cv = (CardView) view.findViewById(R.id.cv_golden);
pb = (ProgressBar) view.findViewById(R.id.progress_bar);
if(savedInstanceState==null) {
Log.d(TAG,"New empty data set");
rv.setVisibility(View.GONE);
cv.setVisibility(View.GONE);
pb.setVisibility(View.INVISIBLE);
}
else{
Log.d(TAG,"Old data set");
adapter.notifyDataSetChanged();
pb.setVisibility(View.INVISIBLE);
rv.setVisibility(View.VISIBLE);
cv.setVisibility(View.VISIBLE);
emptyGoldenText.setVisibility(View.INVISIBLE);
}
Log.d(TAG,"onCreateView() called");
return view;
}
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("HoursList",hours);
Log.d(TAG,"onSaveInstanceState called");
}
SOLVED
Solved by moving
adapter = new CustomAdapter(thisContext, hours);
from onCreate() to onCreateView().
In the activity, you have to save the fragment's instance in onSaveInstanceState() and restore in onCreate().
#Override
public void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState != null) {
fragment = getSupportFragmentManager().getFragment(savedInstanceState, "KEY");
changeFragment(fragment, "MY TAG")
} else {
setupFragment();
}
...
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Fragment fragment = getSupportFragmentManager().findFragmentByTag("MY TAG");
if (fragment != null) {
getSupportFragmentManager().putFragment(outState, "KEY", fragment);
}
}
try this code: in onSaveInstanceState put arraylist
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("HoursList",hours);
Log.d(TAG,"onSaveInstanceState called");
}
In onActivityCreated you check the following conditions:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(savedInstanceState! = null) {
//probably orientation change
Log.d(TAG,"inState not null");
hours.clear();
hours = savedInstanceState.getParcelableArrayList("HoursList");
//check if u get the value print log
}
else {
if (hours != null) {
//returning from backstack, data is fine, do nothing
} else {
//newly created, compute data
hours = computeData();
}
}
}

FragmentTabHost getting empty fragments after popBackStack

I have tried every post in StackOverflow and have not been successful, i have a FragmentTabHost activity with tabs A B C D E
When i go to tab A and then go to tab B everything is ok, but if i return to tab A is blank, then return to tab B is also blank!!
A -> B -> A = Blank -> B = blank
I followed this post to get it working Dynamically changing the fragments inside a fragment tab host?, but the transition between tabs is not working.
I have tried changing my BaseContainerFragment to use getSupportFragmentManager instead of getChildFragmentManager but was unsuccessful, also removing addToBackStack(null) at this point im out of ideas, any help here will be appreciated, thanks.
This is the mainActivity that contain code for creating tabs using fragment.
public class ActivityMain extends FragmentActivity {
public static final String TAB_1_TAG = "tab_1";
public static final String TAB_2_TAG = "tab_2";
public static final String TAB_3_TAG = "tab_3";
public static final String TAB_4_TAG = "tab_4";
public static final String TAB_5_TAG = "tab_5";
private FragmentTabHost mTabHost;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
mTabHost.getTabWidget().setDividerDrawable(null);
mTabHost.getTabWidget().setStripEnabled(false);
mTabHost.addTab(mTabHost.newTabSpec(TAB_1_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_account)), FragmentAccountContainer.class, null);
mTabHost.addTab(mTabHost.newTabSpec(TAB_2_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_discounts)), FragmentPromotionsContainer.class, null);
mTabHost.addTab(mTabHost.newTabSpec(TAB_3_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_payment)), FragmentAccountContainer.class, null);
mTabHost.addTab(mTabHost.newTabSpec(TAB_4_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_gas)), FragmentAccountContainer.class, null);
mTabHost.addTab(mTabHost.newTabSpec(TAB_5_TAG).setIndicator("", getResources().getDrawable(R.drawable.tab_rest)), FragmentAccountContainer.class, null);
}
#Override
public void onBackPressed() {
boolean isPopFragment = false;
String currentTabTag = mTabHost.getCurrentTabTag();
Log.e("ActivityMain", "currentTabTag: " + currentTabTag);
if (currentTabTag.equals(TAB_1_TAG)) {
isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_1_TAG)).popFragment();
} else if (currentTabTag.equals(TAB_2_TAG)) {
isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_2_TAG)).popFragment();
} else if (currentTabTag.equals(TAB_3_TAG)) {
isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_3_TAG)).popFragment();
} else if (currentTabTag.equals(TAB_4_TAG)) {
isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_4_TAG)).popFragment();
} else if (currentTabTag.equals(TAB_5_TAG)) {
isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(TAB_5_TAG)).popFragment();
}
Log.e("ActivityMain", "isPopFragment: " + isPopFragment);
if (!isPopFragment) {
finish();
}
}
}
This is my BaseContainerFragment that allows backtracking and replacment of fragments
public class BaseContainerFragment extends Fragment {
public void replaceFragment(Fragment fragment, boolean addToBackStack) {
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
if (addToBackStack) {
transaction.addToBackStack(null);
}
transaction.replace(R.id.container_framelayout, fragment);
transaction.commit();
getChildFragmentManager().executePendingTransactions();
}
public boolean popFragment() {
Log.e("test", "pop fragment: " + getChildFragmentManager().getBackStackEntryCount());
boolean isPop = false;
if (getChildFragmentManager().getBackStackEntryCount() > 0) {
isPop = true;
getChildFragmentManager().popBackStack();
}
return isPop;
}
}
This is container for the first Tab (this tab holds 2 activities, one is main, and another is called on listview Click)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myPrefs = this.getActivity().getSharedPreferences("getLogin", Context.MODE_PRIVATE);
idUser = myPrefs.getInt("idUser", 0);
d(TAG, "idUser: " + idUser);
/*
Map<String,?> keys = myPrefs.getAll();
for(Map.Entry<String,?> entry : keys.entrySet()){
Log.d("map values",entry.getKey() + ": " +
entry.getValue().toString());
}
*/
context = getActivity();
pDialog = new SweetAlertDialog(context, PROGRESS_TYPE);
// Check if Internet present
if (!isOnline(context)) {
// Internet Connection is not present
makeText(context, "Error en la conexion de Internet",
LENGTH_LONG).show();
// stop executing code by return
return;
}
new asyncGetFeedClass(context).execute();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.activity_cardholder, container, false);
toolbar = (Toolbar) v.findViewById(R.id.toolbar);
TextView mTitle = (TextView) toolbar.findViewById(toolbar_title);
mTitle.setText("TARJETAS");
list = (ListView) v.findViewById(R.id.list);
// Click event for single list row
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
FragmentAccount fragment = new FragmentAccount();
// if U need to pass some data
Bundle bundle = new Bundle();
if (listBalance.get(position).get(TAG_ACCOUNT_BANKACCOUNTS_ID) != null) {
bundle.putString("idBankAccount", listBalance.get(position).get(TAG_ACCOUNT_BANKACCOUNTS_ID));
bundle.putString("idGiftCard", "0");
} else if (listBalance.get(position).get(TAG_ACCOUNT_GIFTCARDS_ID) != null) {
bundle.putString("idGiftCard", listBalance.get(position).get(TAG_ACCOUNT_GIFTCARDS_ID));
bundle.putString("idBankAccount", "0");
} else {
bundle.putString("idBankAccount", "0");
bundle.putString("idGiftCard", "0");
}
fragment.setArguments(bundle);
((BaseContainerFragment) getParentFragment()).replaceFragment(fragment, false);
}
});
return v;
}
The main class for Tab #1
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myPrefs = this.getActivity().getSharedPreferences("getLogin", Context.MODE_PRIVATE);
idUser = myPrefs.getInt("idUser", 0);
d(TAG, "idUser: " + idUser);
/*
Map<String,?> keys = myPrefs.getAll();
for(Map.Entry<String,?> entry : keys.entrySet()){
Log.d("map values",entry.getKey() + ": " +
entry.getValue().toString());
}
*/
context = getActivity();
pDialog = new SweetAlertDialog(context, PROGRESS_TYPE);
// Check if Internet present
if (!isOnline(context)) {
// Internet Connection is not present
makeText(context, "Error en la conexion de Internet",
LENGTH_LONG).show();
// stop executing code by return
return;
}
Bundle bundle = this.getArguments();
idBankAccount = Integer.parseInt(bundle.getString(FragmentCardHolder.TAG_ACCOUNT_BANKACCOUNTS_ID, "0"));
idGiftCard = Integer.parseInt(bundle.getString(FragmentCardHolder.TAG_ACCOUNT_GIFTCARDS_ID, "0"));
if(idBankAccount > 0){
new asyncGetBankTransactions(context).execute();
} else if(idGiftCard > 0) {
new asyncGetGiftCardTransactions(context).execute();
} else {
new asyncGetX111Transactions(context).execute();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.activity_account, container, false);
toolbar = (Toolbar) v.findViewById(id.toolbar);
TextView mTitle = (TextView) toolbar.findViewById(toolbar_title);
mTitle.setText("MI CUENTA");
toolbar.setNavigationIcon(R.drawable.icon_user);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
goToCards();
}
});
layoutAccount = (LinearLayout) v.findViewById(id.layoutAccount);
layoutGetCredit = (LinearLayout) v.findViewById(id.layoutGetCredit);
layoutTransactions = (LinearLayout) v.findViewById(id.layoutTransactions);
btnAccount = (Button) v.findViewById(id.btnMyBalance);
btnGetCredit = (Button) v.findViewById(id.btnGetCredit);
btnSendCredit = (Button) v.findViewById(id.btnSendCredit);
btnTransactions = (Button) v.findViewById(id.btnTransactions);
list = (ListView) v.findViewById(id.list);
btnTransactions.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
layoutAccount.setVisibility(View.GONE);
layoutGetCredit.setVisibility(View.GONE);
layoutTransactions.setVisibility(View.VISIBLE);
}
});
btnGetCredit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
layoutAccount.setVisibility(View.GONE);
layoutGetCredit.setVisibility(View.VISIBLE);
layoutTransactions.setVisibility(View.GONE);
}
});
btnAccount.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
layoutAccount.setVisibility(View.VISIBLE);
layoutGetCredit.setVisibility(View.GONE);
layoutTransactions.setVisibility(View.GONE);
}
});
return v;
}
private void goToCards() {
FragmentCardHolder fragment = new FragmentCardHolder();
((BaseContainerFragment) getParentFragment()).replaceFragment(fragment, true);
}
I think the problem is in hidden part of code where you add first fragment to container (FragmentAccountContainer and FragmentPromotionsContainer classes). I suggest you to create abstract method in BaseContainerFragment.class with signature by example
protected abstract Fragment getFirstFragment();
So concrete container class will override this method and return new instance of a first fragment to super class and then in parent class add it to fragment container with using add transaction.
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
addFragment(getFirstFragment(), false);
}
}
Note you should check if savedInstanceState is null before adding fragment to avoid dublicates in case activity recreation by system.
In nested fragments you could use replace like you did it ((BaseContainerFragment) getParentFragment()).replaceFragment(___, true);
Also i have a few suggestions for you code. You couldn't just avoid overriding onBackPressed in activity like #NecipAllef suggests, because of known bug with default back logic and child fragment manager , but you could simplify call to popFragment like
#Override
public void onBackPressed() {
String currentTabTag = mTabHost.getCurrentTabTag();
boolean isPopFragment = ((BaseContainerFragment) getSupportFragmentManager().findFragmentByTag(currentTabTag)).popFragment();
if (!isPopFragment) {
super.onBackPressed();
}
}
And for setting bundles to fragment i suggest use fabric method pattern, like
public class TestFragment extends Fragment {
public static Fragment newInstance(String text){
Fragment fragment = new TestFragment();
Bundle args = new Bundle();
args.putString("text", text);
fragment.setArguments(args);
return fragment;
}
}
Ps: i created for you a simple project with described logic
Why are you keeping track of Fragments and popping them by yourself? You don't need to do that, and you shouldn't override onBackPressed(). Let FragmentManager handle the fragment transactions.
If you have fragments inside an activity, use
FragmentManager fManager = getFragmentManager();
or if you want to support devices prior to Android 3.0, use
FragmentManager fManager = getSupportFragmentManager();
if fragments are inside another fragment, then use
FragmentManager fManager = getChildFragmentManager();
After you have fManager, to show a fragment, use
fManager.beginTransaction().add(R.id.fragment_parent, new FirstTabFragment()).commit();
where fragment_parent is the parent view which you want to place your fragments.
When you want to switch to next fragment, use
fManager.beginTransaction().replace(R.id.fragment_parent, new SecondTabFragment())
.addToBackStack(null)
.commit();
Since you add it to back stack, you will see your first fragment when you press back. That's it.
Moreover, as you can easily realize this will cause your fragments to be created from scratch every time, you can prevent this by initializing them once and reuse them.
HTH

Maintaining fragments instance state between transactions

From all the searches I have found on SO stating that you should save your instance state in the #Override public void onSaveInstanceState(Bundle outState)
However This is tightly coupled with the activities lifestyle.
How can I save the state of my listview in a fragment that gets swapped out with another fragment.
I have one main activity which all the fragments are loaded into.
I have tried this so far:
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
//Save adapter data so that when the fragment is returned to it can be resused.
ArrayList<CategoryMobileDto> categories = new ArrayList<CategoryMobileDto>();
for(int i=0; i < adapter.getCount();i++)
{
categories.add(adapter.getItem(i));
}
String persistData = new Gson().toJson(categories);
outState.putString("Categories", persistData);
}
and then in my OnCreate();
if(savedInstanceState!=null)
{
String data =savedInstanceState.getString("Categories");
Type collectionType = new TypeToken<ArrayList<CategoryMobileDto>>() {
}.getType();
adapter.addAll(gson.<Collection<CategoryMobileDto>>fromJson(data, collectionType));
adapter.notifyDataSetChanged();
}else{
// Make request to server
}
however savedInstanceState is always null. But this makes sense as my activity is not being destroyed and recreated.
This is how I transition from one fragment to another:
fragment.setArguments(args);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.container, fragment, "ProductListFragment");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
Is there a way i can save the state of my listview when the fragment is removed and then restore it again when the fragment is popped from the back-stack?
Move this code from onCreate() to onActivityCreated() of Fragment
if(savedInstanceState!=null)
{
String data =savedInstanceState.getString("Categories");
Type collectionType = new TypeToken<ArrayList<CategoryMobileDto>>() {
}.getType();
adapter.addAll(gson.<Collection<CategoryMobileDto>>fromJson(data, collectionType));
adapter.notifyDataSetChanged();
}else{
// Make request to server
}
If you have any query please let me know.
You can use the Arguments with the Fragment(Only if you have the data to show in fragment before the fragment is loaded means attached). You can setArguments to a fragment which will be persisted when you go to another fragment by fragment transaction and when you come back, load the fragment from the getArguments function.
public void setArguments (Bundle args)
Added in API level 11
Supply the construction arguments for this fragment. This can only be called before the fragment has been attached to its activity; that is, you should call it immediately after constructing the fragment. The arguments supplied here will be retained across fragment destroy and creation.
public final Bundle getArguments ()
Added in API level 11
Return the arguments supplied when the fragment was instantiated, if any.
Please find the sample code below for passing data between fragments :
main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/flContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</FrameLayout>
MainActivity.java
public class MainActivity extends Activity implements IFragContainer {
private static final String FRAG_TAG = "FragTag";
private FragBase mFrag;
private String dataToBePassedBack;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
changeFragment(FragA.class, "Data to Frag A");
}
#Override
public void changeFragment(Class<? extends FragBase> fragClass, String data) {
try {
FragmentTransaction ft = getFragmentManager().beginTransaction();
mFrag = fragClass.newInstance();
Bundle args = new Bundle();
args.putString("DATA", data);
mFrag.setArguments(args);
ft.replace(R.id.flContainer, mFrag, FRAG_TAG);
ft.addToBackStack(mFrag.toString());
ft.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onBackPressed() {
dataToBePassedBack = mFrag.getDataToPassBack();
FragmentManager mgr = getFragmentManager();
mgr.executePendingTransactions();
boolean doCheckAndExit = true;
for (int i = mgr.getBackStackEntryCount() - 1; i > 0; i--) {
BackStackEntry entry = mgr.getBackStackEntryAt(i);
if (!TextUtils.isEmpty(entry.getName())) {
mgr.popBackStackImmediate(entry.getId(),
FragmentManager.POP_BACK_STACK_INCLUSIVE);
doCheckAndExit = false;
break;
}
}
if (doCheckAndExit) {
finish();
} else {
mFrag = (FragBase) mgr.findFragmentByTag(FRAG_TAG);
}
}
#Override
public String getDataToBePassedBack() {
return dataToBePassedBack;
}
}
IFragContainer.java
public interface IFragContainer {
void changeFragment(Class<? extends FragBase> fragClass, String data);
String getDataToBePassedBack();
}
FragBase.java
public abstract class FragBase extends Fragment {
public String getDataToPassBack(){
return null;
}
}
FragA.java
public class FragA extends FragBase {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Button btn = new Button(getActivity());
final IFragContainer fragContainer = (IFragContainer) getActivity();
if (TextUtils.isEmpty(fragContainer.getDataToBePassedBack())) {
btn.setText(getArguments().getString("DATA"));
} else {
btn.setText(fragContainer.getDataToBePassedBack());
}
btn.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
fragContainer.changeFragment(FragB.class, "Data to Frag B");
}
});
return btn;
}
}
FragB.java
public class FragB extends FragBase {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Button btn = new Button(getActivity());
btn.setText(getArguments().getString("DATA"));
btn.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
getActivity().onBackPressed();
}
});
return btn;
}
#Override
public String getDataToPassBack() {
return "Data from Frag B to A";
}
}

android fragment state restored only on back button , not when i select a fragment randomly from listview

Hi i have a listview sidebar and i am displaying fragments based on user selection in listview.
This is how i am replacing fragments
public void switchFragment(Fragment fragment, boolean addBackStack) {
try {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content, fragment);
currentFragment = fragment;
//if (addBackStack)
ft.addToBackStack(null);
ft.commit();
} catch (Exception e) {
}
}
This is my sample fragment code.Now when i replace fragments i am saving instance state in onpause and restoring it in onresume but it only works when i press back button. When i manually navigate back to fragment from listview ,fragment state is not restored.Why?
public class Fragment1 extends BaseFragment {
int currentFragmentInd = 1;
private Button startButton;
private Button endButton;
private long savedStartTime;
private TextView setStartText;
private TextView setEndText;
private String starttime;
private String endtime;
public int getIndex() {
MyApplication.getApplication().setCurrentChild(0);
MyApplication.getApplication().setCurrentGroup(0);
return currentFragmentInd;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState !=null)
{
}
}
#Override
public void onResume() {
super.onResume();
setStartText= (TextView)getActivity().findViewById(R.id.MAtextView2);
setEndText= (TextView)getActivity().findViewById(R.id.MAtextView3);
setEndText.setText(endtime);
setStartText.setText(starttime);
}
#Override
public void onPause() {
super.onPause();
setStartText= (TextView)getActivity().findViewById(R.id.MAtextView2);
setEndText= (TextView)getActivity().findViewById(R.id.MAtextView3);
starttime=setStartText.getText().toString();
endtime=setEndText.getText().toString();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
FrameLayout frameLayout;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View contentView = inflater.inflate(R.layout.layout1, null, false);
((MainActivity) getActivity()).openList(0, 0);
if (savedInstanceState == null) {
}
startButton= (Button) contentView.findViewById(R.id.button);
endButton= (Button) contentView.findViewById(R.id.button2);
endButton.setEnabled(false);
setStartText= (TextView)contentView.findViewById(R.id.MAtextView2);
setEndText= (TextView)contentView.findViewById(R.id.MAtextView3);
startButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Time now = new Time();
now.setToNow();
}
});
endButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Time now = new Time();
now.setToNow();
setEndText.setText(now.hour+" : "+now.minute);
}
});
return contentView;
}
}
Late replay but might help somebody else.
This happens because when you click a listview item you create a new inctance of that fragment.
"I assume the fragment you send to switchFragment(Fragment fragment), is created using a 'new' keyword."
Therefore this new instance of a fragment doesnt hold your old data.
This is how I solved this. There are probably better ways, but since nobody replied, I will give my solution.
When you replace the fragment (ft.replace, fragment), give a string reference to that transaction: -ft.replace(R.id.content, fragment, "FRAGMENT_NAME");
When you add the fragment to the backstack with addToBackStack(null); put the name of your fragment where you have null.: -ft.addToBackStack("FRAGMENT_NAME");
Create a method which tells you if that fragment has already been created, and therefore exists in the back stack.:
public boolean isTagInBackStack(String tag){
Log.i(TAG, "isTagInBackStack() Start");
int x;
boolean toReturn = false;
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
Log.i(TAG, "backStackCount = " + backStackCount);
for (x = 0; x < backStackCount; x++){
Log.i(TAG, "Iter = " + x +" "+ getSupportFragmentManager().getBackStackEntryAt(x).getName());
if (tag == getSupportFragmentManager().getBackStackEntryAt(x).getName()){
toReturn = true;
}
}
Log.i(TAG, "isTagInBackStack() End, toReturn = " + toReturn);
return toReturn;
}
Now before you create a new instance of that fragment check in the backstack if a backstack item named "FRAGMENT_NAME" exists.
if it exists, use that item (fragment) instead of creating a new one.
if (isTagInBackStack("FRAGMENT_NAME")){
Log.i(TAG, "Tag is in BackStack!!!! frag is = " + getSupportFragmentManager().findFragmentByTag("FRAGMENT_NAME"));
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_activity_container, getSupportFragmentManager().findFragmentByTag("FRAGMENT_NAME"));
transaction.addToBackStack("FRAGMENT_NAME");
transaction.commit();
}else{
Create the fragment (this happens the first time.
}

Categories

Resources