how to avoid Fragments Overlap in android with Navigation Drawer - android

i am creating a application in which i am using preference Fragment with navigation Drawer my problem is i am created navigation Drawer and in which i am added some menu item in which i want to load the preference Fragment as a first element when the app loads.it is does as i don to display. when i am changing the options I-e.when i am changing the drawer menu options like second element the in the drawer menu fist view is not replacing with the second,it is overlapping an the first
my navigation drawer xml is as follow
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.koteswara.wise.NavigationDrawerMainActivity" >
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="#+id/drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_gravity="start" >
<ListView
android:id="#+id/drawer_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
tools:context="com.koteswara.wise.NavigationDrawerFragment" />
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
my preference fragment is like this
public class AutoAnswerPreferenceActivity extends PreferenceFragment implements OnSharedPreferenceChangeListener {
private AutoAnswerNotifier mNotifier;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preference);
mNotifier = new AutoAnswerNotifier(getActivity());
mNotifier.updateNotification();
SharedPreferences sharedPreferences = getPreferenceManager().getSharedPreferences();
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onDestroy() {
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onDestroy();
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals("enabled")) {
mNotifier.updateNotification();
}
}
}
my fragment class which is adding to load the PreferenceFragment is
public class AutoAnswarFragment extends Fragment {
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
getActivity().getFragmentManager().beginTransaction().replace(R.id.container, new AutoAnswerPreferenceActivity()) .commit();
}
the navigation Drawer class in which show fragment method is
protected void showFragment(int position) {
// TODO Auto-generated method stub
Fragment fragment = null;
switch (position) {
case 0:
fragment = new AutoAnswarFragment();
break;
case 1:
fragment = new Tab2();
break;
case 2:
// fragment = new BhajanaFragment();
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragment).commit();
// update selected item and title, then close the drawer
// mDrawerList.setItemChecked(position, true);
// mDrawerList.setSelection(position);
mTitle = mDrawer_title[position];
// mDrawerLayout.closeDrawer(mDrawerList);
} else {
// error in creating fragment
// Log.e("MainActivity", "Error in creating fragment");
}
}
}
if i will call the fragment other than the preference Fragment like below it will works please help me
public class Tab1 extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v =inflater.inflate(R.layout.tab_1,container,false);
return v;
}
}
i am struggling to clear the solution for it please any body solve it and please tell me the solution .i will be the thank full please help me

Be sure the root layout of all your fragments are having
android:background="#color/your_favorite_color"
In that way they will be hiding other fragments below.

on so many days of research and searching on the web i have found a solution its working fine for me for the above problem there is a link on the web as http://www.michenux.net/android-preferencefragmentcompat-906.html in this i found a sample apk and a source code regarding the apk . as this apk has a functionality as it solves my problem . i cleared the errors of the source code which will comes when you import and after that i added the library to my project. I used the PreferenceCompatFragment rather than PreferenceFragmentCompat, it solved my problem if anybody needs help it may help them also so that i am posting my solution to the above problem. and i thank who are all helped me who and all given some valuable suggestion for the above problem.
The below class below i have used instead of PreferenceFragmentCompat of v7 support library
public abstract class PreferenceCompatFragment extends Fragment {
private static final int FIRST_REQUEST_CODE = 100;
private static final int MSG_BIND_PREFERENCES = 1;
private static final String PREFERENCES_TAG = "android:preferences";
private boolean mHavePrefs;
private boolean mInitDone;
private ListView mList;
private PreferenceManager mPreferenceManager;
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_BIND_PREFERENCES:
bindPreferences();
break;
}
}
};
final private Runnable mRequestFocus = new Runnable() {
public void run() {
mList.focusableViewAvailable(mList);
}
};
private void bindPreferences() {
PreferenceScreen localPreferenceScreen = getPreferenceScreen();
if (localPreferenceScreen != null) {
ListView localListView = getListView();
localPreferenceScreen.bind(localListView);
}
}
private void ensureList() {
if (mList == null) {
View view = getView();
if (view == null) {
throw new IllegalStateException("Content view not yet created");
}
View listView = view.findViewById(android.R.id.list);
if (!(listView instanceof ListView)) {
throw new RuntimeException("Content has view with id attribute 'android.R.id.list' that is not a ListView class");
}
mList = (ListView)listView;
if (mList == null) {
throw new RuntimeException("Your content must have a ListView whose id attribute is 'android.R.id.list'");
}
mHandler.post(mRequestFocus);
}
}
private void postBindPreferences() {
if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) {
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
}
}
private void requirePreferenceManager() {
if (this.mPreferenceManager == null) {
throw new RuntimeException("This should be called after super.onCreate.");
}
}
public void addPreferencesFromIntent(Intent intent) {
requirePreferenceManager();
PreferenceScreen screen = inflateFromIntent(intent, getPreferenceScreen());
setPreferenceScreen(screen);
}
public void addPreferencesFromResource(int resId) {
requirePreferenceManager();
PreferenceScreen screen = inflateFromResource(getActivity(), resId, getPreferenceScreen());
setPreferenceScreen(screen);
}
public Preference findPreference(CharSequence key) {
if (mPreferenceManager == null) {
return null;
}
return mPreferenceManager.findPreference(key);
}
public ListView getListView() {
ensureList();
return mList;
}
public PreferenceManager getPreferenceManager() {
return mPreferenceManager;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListView().setScrollBarStyle(0);
if (mHavePrefs) {
bindPreferences();
}
mInitDone = true;
if (savedInstanceState != null) {
Bundle localBundle = savedInstanceState.getBundle(PREFERENCES_TAG);
if (localBundle != null) {
PreferenceScreen screen = getPreferenceScreen();
if (screen != null) {
screen.restoreHierarchyState(localBundle);
}
}
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
dispatchActivityResult(requestCode, resultCode, data);
}
#Override
public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
mPreferenceManager = createPreferenceManager();
}
#Override
public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) {
return paramLayoutInflater.inflate(R.layout.preference_list_content, paramViewGroup, false);
}
#Override
public void onDestroy() {
super.onDestroy();
dispatchActivityDestroy();
}
#Override
public void onDestroyView() {
mList = null;
mHandler.removeCallbacks(mRequestFocus);
mHandler.removeMessages(MSG_BIND_PREFERENCES);
super.onDestroyView();
}
#Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
PreferenceScreen screen = getPreferenceScreen();
if (screen != null) {
Bundle localBundle = new Bundle();
screen.saveHierarchyState(localBundle);
bundle.putBundle(PREFERENCES_TAG, localBundle);
}
}
#Override
public void onStop() {
super.onStop();
dispatchActivityStop();
}
/** Access methods with visibility private **/
private PreferenceManager createPreferenceManager() {
try {
Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class);
c.setAccessible(true);
return c.newInstance(this.getActivity(), FIRST_REQUEST_CODE);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private PreferenceScreen getPreferenceScreen() {
try {
Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen");
m.setAccessible(true);
return (PreferenceScreen) m.invoke(mPreferenceManager);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void setPreferenceScreen(PreferenceScreen preferenceScreen) {
try {
Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class);
m.setAccessible(true);
boolean result = (Boolean) m.invoke(mPreferenceManager, preferenceScreen);
if (result && preferenceScreen != null) {
mHavePrefs = true;
if (mInitDone) {
postBindPreferences();
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void dispatchActivityResult(int requestCode, int resultCode, Intent data) {
try {
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class);
m.setAccessible(true);
m.invoke(mPreferenceManager, requestCode, resultCode, data);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void dispatchActivityDestroy() {
try {
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy");
m.setAccessible(true);
m.invoke(mPreferenceManager);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void dispatchActivityStop() {
try {
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop");
m.setAccessible(true);
m.invoke(mPreferenceManager);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void setFragment(PreferenceFragment preferenceFragment) {
try {
Method m = PreferenceManager.class.getDeclaredMethod("setFragment", PreferenceFragment.class);
m.setAccessible(true);
m.invoke(mPreferenceManager, preferenceFragment);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public PreferenceScreen inflateFromResource(Context context, int resId, PreferenceScreen rootPreferences) {
PreferenceScreen preferenceScreen ;
try {
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
m.setAccessible(true);
preferenceScreen = (PreferenceScreen) m.invoke(mPreferenceManager, context, resId, rootPreferences);
} catch (Exception e) {
throw new RuntimeException(e);
}
return preferenceScreen;
}
public PreferenceScreen inflateFromIntent(Intent queryIntent, PreferenceScreen rootPreferences) {
PreferenceScreen preferenceScreen ;
try {
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class);
m.setAccessible(true);
preferenceScreen = (PreferenceScreen) m.invoke(mPreferenceManager, queryIntent, rootPreferences);
} catch (Exception e) {
throw new RuntimeException(e);
}
return preferenceScreen;
}
}

Related

Can't change the view depending on the size of the list

I have problem with change view on my layout on my RecycleView.I have list dream. This view contains two state myDreamEmptyLayout witch show Text "For now you don\'t have dream. \n Add dream!" when myDreamList is empty and size is equals 0. But when myDreamList size more than 1 show list dream.
Problem is when have myDream on list and delete all can't show my view myDreamEmptyLayout.
What is problem ?
This is my fragment_my_dream.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/colorBackground"
>
<LinearLayout
android:id="#+id/myDreamEmptyLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="#string/for_now_you_don_t_have_dream_n_add_dream"
android:textColor="#color/colorWhite"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="#+id/myDreamRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
</FrameLayout>
This is my fragment class
public class MyDreamFragment extends Fragment {
public static final int REQUEST_CODE_CREATE = 1;
#BindView(R.id.myDreamRecyclerView)
RecyclerView myDreamRecyclerView;
#BindView(R.id.myDreamEmptyLayout)
LinearLayout myDreamEmptyLayout;
private MyDreamAdapter myDreamAdapter;
private List<MyDream> myDreamList;
String idUserString;
private DbHelper dbHelper;
private Unbinder unbinder;
private Dao<MyDream, Integer> myDreamDao;
private Dao<User, Integer> myUserDao;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_my_dream, container, false);
unbinder = ButterKnife.bind(this, rootView);
TextView title = (TextView) getActivity().findViewById(R.id.toolbarTextView);
title.setText(R.string.title_my_dreams);
return rootView;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Application application = (Application) getApplicationContext();
idUserString = application.getFirebaseId();
dbHelper = new DbHelper(getActivity());
try {
myDreamDao = dbHelper.getDao(MyDream.class);
} catch (SQLException e) {
e.printStackTrace();
}
try {
myUserDao = dbHelper.getDao(User.class);
} catch (SQLException e) {
e.printStackTrace();
}
QueryBuilder<User, Integer> userQa = myUserDao.queryBuilder();
try {
userQa.where().eq(User.Columns.FIREBASE_ID, idUserString);
} catch (SQLException e) {
e.printStackTrace();
}
QueryBuilder<MyDream, Integer> myDreamQa = myDreamDao.queryBuilder();
try {
myDreamList = myDreamQa.join(userQa).query();
} catch (SQLException e) {
e.printStackTrace();
}
if (myDreamList != null && myDreamList.size() > 0) {
myDreamRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
myDreamAdapter = new MyDreamAdapter(myDreamList, getActivity());
myDreamRecyclerView.setAdapter(myDreamAdapter);
}
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_add, menu);
}
#Override
public void onResume() {
super.onResume();
if (myDreamList.size() == 0) {
myDreamEmptyLayout.setVisibility(View.VISIBLE);
myDreamRecyclerView.setVisibility(View.GONE);
} else {
myDreamEmptyLayout.setVisibility(View.GONE);
myDreamRecyclerView.setVisibility(View.VISIBLE);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_addream:
Intent intent = new Intent(getActivity(), AddEditDreamActivity.class);
startActivityForResult(intent, REQUEST_CODE_CREATE);
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == AddEditDreamActivity.RESULT_OK) {
if (requestCode == REQUEST_CODE_CREATE) {
if (data != null) {
MyDream myDream = data.getParcelableExtra("dream");
myDreamAdapter.addMyDream(myDream);
Toast.makeText(getActivity(), "Dream was added", Toast.LENGTH_SHORT).show();
}
}
}
}
#Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}
Your myDreamList will not react to pending changes and as such myDreamEmptyLayout will not get informed of that new information (such as size reached zero) is available. To counter this look at this ObservableArrayList and its OnListChangedCallback. After changing the myDreamList to ObservableArrayList move onResume code (without super of course) to OnListChangedCallback and add this callback via addOnListChangedCallback. This way the changes done to the list will be reflected on the layout as you desire.
The code:
//this goes to onCreate. DISCLAIMER : code written without testing, please confirm that it works.
myDreamList.addOnListChangedCallback(new ObservableList.OnListChangedCallback() {
/*snipped useless methods*/
#Override
public void onChanged(ObservableList<T> sender) {
if (sender.size() == 0) {
myDreamEmptyLayout.setVisibility(View.VISIBLE);
myDreamRecyclerView.setVisibility(View.GONE);
} else {
myDreamEmptyLayout.setVisibility(View.GONE);
myDreamRecyclerView.setVisibility(View.VISIBLE);
}
}
}

How to support pre-honeycomb versions of Android for Using Preference Headers

I am following this guide to learn about 'Creating App Settings using Preference Headers'. This question deals with "Supporting older (than HoneyComb) versions with preference headers".
I think I have followed all the steps, but still am getting this exception. So what am I missing?
LOG:
...
07-10 18:45:31.935: E/AndroidRuntime(1285): FATAL EXCEPTION: main
07-10 18:45:31.935: E/AndroidRuntime(1285): java.lang.RuntimeException: Unable to start activity ComponentInfo{practice_projects.minimalpreferencesusingpreferenceheadersoldversions/practice_projects.minimalpreferencesusingpreferenceheadersoldversions.MyPreferenceActivity}: java.lang.ClassCastException: practice_projects.minimalpreferencesusingpreferenceheadersoldversions.MyPreferenceFragment cannot be cast to android.app.Fragment
...
07-10 18:45:31.935: E/AndroidRuntime(1285): Caused by: java.lang.ClassCastException: practice_projects.minimalpreferencesusingpreferenceheadersoldversions.MyPreferenceFragment cannot be cast to android.app.Fragment
...
07-10 18:45:31.935: E/AndroidRuntime(1285): at practice_projects.minimalpreferencesusingpreferenceheadersoldversions.MyPreferenceActivity.onCreate(MyPreferenceActivity.java:16)
...
MainActivity.java:
public class MainActivity extends FragmentActivity implements DrawerLayout.DrawerListener, ListView.OnItemClickListener {
private static final String TAG = MainActivity.class.getSimpleName();
private final String [] drawerListItems = {"Settings"};
private DrawerLayout drawerLayout;
private FrameLayout frameLayout;
private ListView drawerListView;
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);//******LINE # 16***********
drawerListView = (ListView) findViewById(R.id.mainActivity_listView);
drawerListView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, drawerListItems));
drawerListView.setOnItemClickListener(this);
drawerLayout = (DrawerLayout) findViewById(R.id.mainActivity_drawerLayout);
drawerLayout.setDrawerListener(this);
frameLayout = (FrameLayout) findViewById(R.id.mainActivity_frameLayout);
textView = (TextView) findViewById(R.id.mainActivity_textView);
}
/****************************************************************************************************************************************/
/************************************************DrawerLayout.DrawerListener IMPLEMENTATION**********************************************/
/****************************************************************************************************************************************/
#Override
public void onDrawerClosed(View arg0) {
frameLayout.setBackgroundColor(Color.parseColor("#6A0888")); /* Dark Purple Color */
}
#Override
public void onDrawerOpened(View arg0) {
frameLayout.setBackgroundColor(Color.parseColor("#FE642E")); /* Orange Color */
}
#Override
public void onDrawerSlide(View arg0, float arg1) {}
#Override
public void onDrawerStateChanged(int arg0) {}
/****************************************************************************************************************************************/
/************************************************OnDrawerClickListener IMPLEMENTATION**********************************************/
/****************************************************************************************************************************************/
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
frameLayout.setBackgroundColor(Color.parseColor("#F7FE2E")); /* Yellow Color */
startActivity(new Intent(this, MyPreferenceActivity.class));
drawerListView.setItemChecked(position, true);
drawerLayout.closeDrawer(drawerListView);
}
}
MyPreferenceActivity.java:
public class MyPreferenceActivity extends PreferenceActivity {
private static final String TAG = MyPreferenceActivity.class.getSimpleName();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate of MyPreferenceActivity called.");// check
String intentAction = getIntent().getAction();
Log.i(TAG, "The action retrieved from the intent is " + intentAction + ".");// check
if (intentAction != null && intentAction.equals("practice_projects.minimalpreferencesusingpreferenceheadersoldversions.DB")) {
Log.i(TAG, "YES intentAction!=null && intentAction.equals(\"practice_projects.minimalpreferencesusingpreferenceheadersoldversions.DB\"");// check
addPreferencesFromResource(R.xml.db_preferences);
Log.i(TAG, "Added preferences from R.xml.db_preferences.");// check
} else if (intentAction != null && intentAction.equals("practice_projects.minimalpreferencesusingpreferenceheadersoldversions.UI")) {
Log.i(TAG, "YES intentAction!=null && intentAction.equals(\"practice_projects.minimalpreferencesusingpreferenceheadersoldversions.UI\"");// check
addPreferencesFromResource(R.xml.ui_preferences);
Log.i(TAG, "Added preferences from R.xml.ui_preferences.");// check
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
Log.i(TAG, "Build version is LESS than honeycomb.");// check
// Load the preference_headers_legacy.xml
addPreferencesFromResource(R.xml.preference_headers_legacy);
Log.i(TAG, "Added preferences from R.xml.preference_headers_legacy.");// check
} else {
Log.i(TAG, "Build version is HIGHER than honeycomb. "
+ "NO *******intentAction!=null && intentAction.equals(\"practice_projects.minimalpreferencesusingpreferenceheadersoldversions"
+ ".DB\"*******."
+ " NO *******intentAction!=null && intentAction.equals(\"practice_projects.minimalpreferencesusingpreferenceheadersoldversions"
+ ".UI\"*******.");// check
}
}
// Called only on HoneyComb and later
// Although the #TargetApi annotation is not for compiler, and is for Lint only, but no problem, as the system will call this method for honeycomb and later
// only
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.preference_headers, target);
}
}
MyPreferenceFragment.java:
public class MyPreferenceFragment extends PreferenceFragment {
private static final String TAG = MyPreferenceFragment.class.getSimpleName();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String preferenceHeaderExtraValue = getArguments().getString("preference_extra_key");
if (preferenceHeaderExtraValue!=null) {
if (preferenceHeaderExtraValue.equals("db")) {
//getView().setBackgroundColor(Color.parseColor("#81F7BE")); /* Aqua towards green */ //NPE because the layout is not created yet**********
Log.i(TAG, "The value of the preference intent with the key "+preferenceHeaderExtraValue+" is \"db\".");
addPreferencesFromResource(R.xml.db_preferences);
} else if (preferenceHeaderExtraValue.equals("ui")) {
//getView().setBackgroundColor(Color.parseColor("#A9D0F5")); /* Aqua towards blue */ //NPE because the layout is not created yet**********
Log.i(TAG, "The value of the preference intent with the key "+preferenceHeaderExtraValue+" is \"ui\".");
addPreferencesFromResource(R.xml.ui_preferences);
} else {
Log.i(TAG, "The value of the preference intent with the key "+preferenceHeaderExtraValue+" is neither \"db\" nor \"ui\".");
}
} else {
Log.i(TAG, "getArguments() returns null.");
}
}
}
PreferenceFragment.java (Taken from PreferenceFragment for Pre-HoneyComb by Christophe Beyls):
/**
* A PreferenceFragment for the support library. Based on the platform's code with some removed features and a basic ListView layout.
*
* #author Christophe Beyls https://gist.github.com/cbeyls/7475726
*
*/
public abstract class PreferenceFragment extends Fragment {
private static final int FIRST_REQUEST_CODE = 100;
private static final int MSG_BIND_PREFERENCES = 1;
private static final int MSG_REQUEST_FOCUS = 2;
private static final String PREFERENCES_TAG = "android:preferences";
private static final float HC_HORIZONTAL_PADDING = 16;
#SuppressLint("HandlerLeak")
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_BIND_PREFERENCES:
bindPreferences();
break;
case MSG_REQUEST_FOCUS:
mList.focusableViewAvailable(mList);
break;
}
}
};
private boolean mHavePrefs;
private boolean mInitDone;
private ListView mList;
private PreferenceManager mPreferenceManager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class);
c.setAccessible(true);
mPreferenceManager = c.newInstance(this.getActivity(), FIRST_REQUEST_CODE);
} catch (Exception ignored) {
}
}
#Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup viewGroup, Bundle savedInstanceState) {
ListView listView = new ListView(getActivity());
listView.setId(android.R.id.list);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
final int horizontalPadding = (int) (HC_HORIZONTAL_PADDING * getResources().getDisplayMetrics().density);
listView.setPadding(horizontalPadding, 0, horizontalPadding, 0);
}
return listView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (mHavePrefs) {
bindPreferences();
}
mInitDone = true;
if (savedInstanceState != null) {
Bundle container = savedInstanceState.getBundle(PREFERENCES_TAG);
if (container != null) {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
preferenceScreen.restoreHierarchyState(container);
}
}
}
}
public void onStop() {
super.onStop();
try {
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop");
m.setAccessible(true);
m.invoke(mPreferenceManager);
} catch (Exception ignored) {
}
}
public void onDestroyView() {
mList = null;
mHandler.removeCallbacksAndMessages(null);
super.onDestroyView();
}
public void onDestroy() {
super.onDestroy();
try {
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy");
m.setAccessible(true);
m.invoke(mPreferenceManager);
} catch (Exception ignored) {
}
}
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
Bundle container = new Bundle();
preferenceScreen.saveHierarchyState(container);
outState.putBundle(PREFERENCES_TAG, container);
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try {
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class);
m.setAccessible(true);
m.invoke(mPreferenceManager, requestCode, resultCode, data);
} catch (Exception ignored) {
}
}
public PreferenceManager getPreferenceManager() {
return mPreferenceManager;
}
public void setPreferenceScreen(PreferenceScreen screen) {
try {
Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class);
m.setAccessible(true);
boolean result = (Boolean) m.invoke(mPreferenceManager, screen);
if (result && (screen != null)) {
mHavePrefs = true;
if (mInitDone) {
postBindPreferences();
}
}
} catch (Exception ignored) {
}
}
public PreferenceScreen getPreferenceScreen() {
try {
Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen");
m.setAccessible(true);
return (PreferenceScreen) m.invoke(mPreferenceManager);
} catch (Exception e) {
return null;
}
}
public void addPreferencesFromIntent(Intent intent) {
requirePreferenceManager();
try {
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class);
m.setAccessible(true);
PreferenceScreen screen = (PreferenceScreen) m.invoke(mPreferenceManager, intent, getPreferenceScreen());
setPreferenceScreen(screen);
} catch (Exception ignored) {
}
}
public void addPreferencesFromResource(int resId) {
requirePreferenceManager();
try {
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
m.setAccessible(true);
PreferenceScreen screen = (PreferenceScreen) m.invoke(mPreferenceManager, getActivity(), resId, getPreferenceScreen());
setPreferenceScreen(screen);
} catch (Exception ignored) {
}
}
public Preference findPreference(CharSequence key) {
if (mPreferenceManager == null) {
return null;
}
return mPreferenceManager.findPreference(key);
}
private void requirePreferenceManager() {
if (this.mPreferenceManager == null) {
throw new RuntimeException("This should be called after super.onCreate.");
}
}
private void postBindPreferences() {
if (!mHandler.hasMessages(MSG_BIND_PREFERENCES)) {
mHandler.sendEmptyMessage(MSG_BIND_PREFERENCES);
}
}
private void bindPreferences() {
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
preferenceScreen.bind(getListView());
}
}
public ListView getListView() {
ensureList();
return mList;
}
private void ensureList() {
if (mList != null) {
return;
}
View root = getView();
if (root == null) {
throw new IllegalStateException("Content view not yet created");
}
View rawListView = root.findViewById(android.R.id.list);
if (rawListView == null) {
throw new RuntimeException("Your content must have a ListView whose id attribute is 'android.R.id.list'");
}
if (!(rawListView instanceof ListView)) {
throw new RuntimeException("Content has view with id attribute 'android.R.id.list' that is not a ListView class");
}
mList = (ListView) rawListView;
mHandler.sendEmptyMessage(MSG_REQUEST_FOCUS);
}
preference_headers.xml:
<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" >
<header
android:fragment="practice_projects.minimalpreferencesusingpreferenceheadersoldversions.MyPreferenceFragment"
android:title="#string/preferenceHeaders_title1"
android:summary="#string/preferenceHeaders_summary1" >
<extra android:name="preference_extra_key" android:value="db" />
</header>
<header
android:fragment="practice_projects.minimalpreferencesusingpreferenceheadersoldversions.MyPreferenceFragment"
android:title="#string/preferenceHeaders_title2"
android:summary="#string/preferenceHeaders_summary2" >
<extra android:name="preference_extra_key" android:value="ui" />
</header>
</preference-headers>
ui_preferences.xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<EditTextPreference
android:title="#string/UIPreferences_editTextPreference_title"
android:summary="#string/UIPreferences_editTextPreference_summary"
android:key="preferences_UIPditTextPreference_key"
android:defaultValue="UIPreferences_editTextPreference_defaultValue" />
<EditTextPreference
android:title="#string/UIPreferences_editTextPreference_title1"
android:summary="#string/UIPreferences_editTextPreference_summary1"
android:key="UIPreferences_editTextPreference_key1"
android:defaultValue="UIPreferences_editTextPreference_defaultValue1" />
</PreferenceScreen>
db_preferences.xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<CheckBoxPreference
android:title="#string/DBPreferences_checkBoxPreference_title"
android:summary="#string/DBPreferences_checkBoxPreference_summary"
android:key="DBPreferences_checkBoxPreference_key"
android:defaultValue="DBPreferences_checkBoxPreference_defaultValue" />
<CheckBoxPreference
android:title="#string/DBPreferences_checkBoxPreference_title1"
android:summary="#string/DBPreferences_checkBoxPreference_summary1"
android:key="DBPreferences_checkBoxPreference_key1"
android:defaultValue="DBPreferences_checkBoxPreference_defaultValue1" />
</PreferenceScreen>
preference_headers_legacy:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<Preference
android:title="#string/preferenceHeaders_title1"
android:summary="#string/preferenceHeaders_summary1" >
<intent
android:targetPackage="practice_projects.minimalpreferencesusingpreferenceheadersoldversions"
android:targetClass="practice_projects.minimalpreferencesusingpreferenceheadersoldversions.MyPreferenceActivity"
android:action="practice_projects.minimalpreferencesusingpreferenceheadersoldversions.DB" />
</Preference>
<Preference
android:title="#string/preferenceHeaders_title2"
android:summary="#string/preferenceHeaders_summary2" >
<intent
android:targetPackage="practice_projects.minimalpreferencesusingpreferenceheadersoldversions"
android:targetClass="practice_projects.minimalpreferencesusingpreferenceheadersoldversions.MyPreferenceActivity"
android:action="practice_projects.minimalpreferencesusingpreferenceheadersoldversions.UI" />
</Preference>
</PreferenceScreen>
strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Minimal Preferences Using Preference headers OLD VERSIONS</string>
<string name="mainActivity_textView">I am a TextView.</string>
<string name="preferenceHeaders_title">Preference Header Title</string>
<string name="preferenceHeaders_summary">Preference Header Summary</string>
<string name="preferenceHeaders_title1">Preference Header Title</string>
<string name="preferenceHeaders_summary1">Preference Header Summary</string>
<string name="preferenceHeaders_title2">Preference Header Title</string>
<string name="preferenceHeaders_summary2">Preference Header Summary</string>
<string name="DBPreferences_checkBoxPreference_title">Preference Title</string>
<string name="DBPreferences_checkBoxPreference_summary">Preference Summary</string>
<string name="DBPreferences_checkBoxPreference_defaultValue">DBPreferences_checkBoxPreference_defaultValue</string>
<string name="DBPreferences_checkBoxPreference_title1">Preference Title</string>
<string name="DBPreferences_checkBoxPreference_summary1">Preference Summary</string>
<string name="DBPreferences_checkBoxPreference_defaultValue1">DBPreferences_checkBoxPreference_defaultValue1</string>
<string name="UIPreferences_editTextPreference_title">Preference Title</string>
<string name="UIPreferences_editTextPreference_summary">Preference Summary</string>
<string name="UIPreferences_editTextPreference_defaultValue">UIPreferences_editTextPreference_defaultValue</string>
<string name="UIPreferences_editTextPreference_title1">Preference Title</string>
<string name="UIPreferences_editTextPreference_summary1">Preference Summary</string>
<string name="UIPreferences_editTextPreference_defaultValue1">UIPreferences_editTextPreference_defaultValue1</string>
<string name="title_activity_my_preference">MyPreferenceActivity</string>
<string name="hello_world">Hello world!</string>
</resources>
You can't use my PreferenceFragment to display headers or anything Honeycomb-specific. It's just a hack to allow showing a single Preferences set in an ActionBarActivity, because previously it was not possible to have a compatibility ActionBar in a PreferenceActivity (it's now possible since AppCompat 22.1 so you don't need this class).
I think the support library will soon provide support for preferences on older versions so keep an eye on it.
From the link that you have provided, it looks like the PreferenceFragment that you are using uses android.support.v4.app.Fragment. See you have this line in the imports section in the GitHub page:
import android.support.v4.app.Fragment;
What this does is use the Fragment class from the support library. But somewhere within you code you are expecting an instance of the regular Fragment class found in package android.app.Fragment (see this from your stack trace). You are using the fragment from the support library in a class from the regular library - they are incompatible with each other and will throw the exception that you are seeing. What you really have is a workaround that is not supported.
As a suggestion, see the following answer for more info on backwards compatibility of PreferenceActivity.
EDIT: Including link in answer
PreferenceActivity Android 4.0 and earlier

Android Activity State Loss

Can somebody answer this question for me:
For testing purposes I have created an activity with a for loop in which I'm creating 10 AlertDialogs or 10 DialogFragments.
Immediately after the activity is started I'm pressing the home button to send the app in the background.
If I'm running the showDialog() method to create the DialogFragments the app will crash with:
IllegalStateException: Can not perform this action after onSaveInstanceState
this is expected behavior.
But if I run the showAlert() method to create the AlertDialogs and same as before I'm sending the app to the background the app doesn't crash. When I return to the activity I can see all 10 AlertDialogs.
The question is why does the activity state loss happen with DialogFragment and not with AlertDialog?
I am still changing the UI after the activity's state has been saved. The platform on which I have tested is Android 4.4.2
public class Main extends FragmentActivity
{
private FragmentActivity activity = this;
private MyAsynk myAsynk;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_main);
myAsynk = new MyAsynk();
myAsynk.execute();
}
private class MyAsynk extends AsyncTask<Void, Void, Void>
{
private boolean run = false;
public MyAsynk()
{
run = true;
}
#Override
protected Void doInBackground(Void... params)
{
for(int i = 0; i < 10 && run; i++)
{
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// showAlert("loop " + i);
showDialog("loop " + i);
}
return null;
}
public void stop()
{
run = false;
}
}
#Override
public void onBackPressed()
{
super.onBackPressed();
if(null != myAsynk)
{
myAsynk.stop();
myAsynk = null;
}
}
private void showAlert(final String txt)
{
try
{
Main.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
new AlertDialog.Builder(activity).setMessage(txt)
.setPositiveButton("Ok", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which)
{
try
{
if(null != dialog)
{
dialog.dismiss();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
})
.show();
}
});
}
catch(Exception e)
{
e.printStackTrace();
}
}
private void showDialog(final String txt)
{
try
{
Main.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
MyDialogFragment newFragment = MyDialogFragment.newInstance(txt);
FragmentTransaction ft = Main.this.getSupportFragmentManager().beginTransaction();
newFragment.show(ft, "newFragment");
}
});
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
MyDialogFragment.java :
public class MyDialogFragment extends DialogFragment
{
private MyDialogFragment instance;
public static MyDialogFragment newInstance(String text)
{
MyDialogFragment f = new MyDialogFragment();
Bundle args = new Bundle();
args.putString("text", text);
f.setArguments(args);
return f;
}
public MyDialogFragment()
{
instance = this;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.my_dialog_fragment, container, false);
TextView tv = (TextView) v.findViewById(R.id.tv);
Button bu = (Button) v.findViewById(R.id.bu);
bu.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
try
{
if(null != instance && instance.isVisible())
{
instance.dismiss();
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
tv.setText(getArguments().getString("text"));
return v;
}
}
The answer is very simple, though a bit underwhelming.
The oft-seen java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState exception is actually thrown by the FragmentManager class. The reason why is explained very well in this post by Alex Lockwood.
DialogFragments are Fragments (and thus managed by FragmentManager). Therefore, showing dialogs in this way can provoke the exception. However, the implementation of AlertDialog is completely different: it doesn't use Fragments at all (indeed, it actually predates Fragments). Hence, no exceptions.

Call method of interface implements with child fragment From container activity Android

I'm stuck with communication between activity and fragment using interface. I have created activity with child fragment. I wanna do some stuff with continuous thread defined in activity and during that thread when I'm getting some result at that time I wanna trigger to child fragment to do something.
My Container Activity
public class MySpaceActivity extends BaseDrawerActivity {
private OnSetLastSeenListener mListner;
public static Thread mThread = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setHeaders(Const.MY_SPACE);
super.setSubmenus(Const.MY_SPACE,
Utils.getSubmenuList(Const.MY_SPACE, MySpaceActivity.this),
submenuBean);
// super.attachFragment(submenuBean);
}
#Override
public void setHeaderSubMenu(SubmenuBean subMenuBean) {
// txt_submenu.setText(subMenuBean.getSubmenu_name());
this.submenuBean = subMenuBean;
Log.print("::::: setHeaderSubMenu ::::");
super.attachFragment(submenuBean);
}
public void setsubFragment(SubmenuBean subMenuBean) {
this.submenuBean = subMenuBean;
super.attachSubFragment(submenuBean);
}
#Override
public void onBackPressed() {
super.onBackPressed();
popLastFragment();
}
private void popLastFragment() {
if (super.getNumberOfChilds() > 1) {
super.popSubFragment();
} else {
finish();
}
}
#Override
protected Fragment getFragement() {
StudentsFragment fragment = new StudentsFragment(Const.MY_SPACE,
getSubmenubean());
return fragment;
}
public SubmenuBean getSubmenubean() {
return submenuBean;
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
mThread = new Thread(new CountDownTimer(MySpaceActivity.this));
mThread.start();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
if (mThread.isAlive()) {
mThread.interrupt();
mThread = null;
}
}
public void updateLastSeen(){
Log.print("::::::Call Interface::::::");
mListner.updateLastSeen();
}
class CountDownTimer implements Runnable {
private Context mContext;
private JSONObject mJsonObject;
private JSONArray mJsonArray;
public CountDownTimer(Context mContext) {
this.mContext = mContext;
}
// #Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
HttpChatLastSeen mChat = new HttpChatLastSeen();
mJsonObject = mChat.Http_ChatLastSeen(mContext);
String mResult = mJsonObject.getString("Result");
if (mResult.equalsIgnoreCase(String
.valueOf(Const.RESULT_OK))) {
mJsonArray = mJsonObject.getJSONArray("UserData");
for (int i = 0; i < mJsonArray.length(); i++) {
mJsonObject = mJsonArray.getJSONObject(i);
new DbStudentMasterBll(mContext).update(
"last_seen", mJsonObject
.getString("LastSeen"), Integer
.parseInt(mJsonObject
.getString("UserId")));
}
} else {
Log.print("MY LAST SEEN Response : "
+ mJsonObject.toString());
}
updateLastSeen();
Thread.sleep(15000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (Exception e) {
Log.print("ChatLastSeenThread : ", e.getMessage());
}
}
}
}
}
My Child Fragment With Interface :
public class StudentsFragment extends Fragment implements OnSetLastSeenListener{
TextView txt_submenu;
ListView list_students;
SubmenuBean submenuBean;
int Mainmenu;
MySpaceActivity mMySpaceActivity;
ArrayList<DbStudentMasterBean> studentsList;
StudentsAdapter mAdapter = null;
OnSetLastSeenListener mListner;
public StudentsFragment() {
super();
}
public StudentsFragment(int Mainmenu, SubmenuBean submenuBean) {
this.submenuBean = submenuBean;
this.Mainmenu = Mainmenu;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_students, container,
false);
mMySpaceActivity = (MySpaceActivity) getActivity();
txt_submenu = (TextView) view.findViewById(R.id.txt_submenu);
txt_submenu.setText(submenuBean.getSubmenu_name());
txt_submenu.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mMySpaceActivity.openDrawer();
}
});
list_students = (ListView) view.findViewById(R.id.list_colleagues);
studentsList = new DbStudentMasterBll(getActivity()).getAllRecords();
mAdapter = new StudentsAdapter(getActivity(), studentsList, handler);
list_students.setAdapter(mAdapter);
list_students.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
DbStudentMasterBean bean = (DbStudentMasterBean) parent
.getAdapter().getItem(position);
Message msg = new Message();
msg.what = CHAT;
msg.obj = bean;
handler.sendMessage(msg);
}
});
return view;
}
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case CHAT:
submenuBean.setTag(VIEWCHATSTUDENT);
DbStudentMasterBean bean = (DbStudentMasterBean) msg.obj;
mMySpaceActivity.setsubFragment(submenuBean);
break;
}
};
};
#Override
public void updateLastSeen() {
// TODO Auto-generated method stub
Log.print("!!!!!!!!!Refresh Adapter!!!!!!!!!!!");
mAdapter.notifyDataSetChanged();
}
}
My Interface :
public interface OnSetLastSeenListener {
public void updateLastSeen();
}
So I have implemented interface OnSetLastSeenListener with my child fragment StudentsFragment . Now I'm calling method of tht interface updateLastSeen() from my container activity with thread. But it is not getting trigger to child fragment where I have implemented interface. So I don't know whether it is good way to communicate or not? Let me take your help to suggest on this solution or best way to communicate from child fragment to parent activity.
Thanks,
It is better to use interface when you want to communicate something from Fragment to Activity and not vice versa.
In your case, you can directly call the method in Fragment from Activity through fragment object. No need to use interface.
Something like this (For static fragments)
StudentsFragment fragment = (StudentsFragment) getFragmentManager()
.findFragmentById(R.id.fragmentid);
if (fragment != null && fragment.isInLayout()) {
fragment.updateLastSeen();
}
For dynamic fragment you can use the fragment object directly.

How to maintain fragment's state in the application

How to maintain fragment's state when it is shown within FragmentTabHost?
Thanks to this tutorial, I'm able to implement FragmentTabHost in my application.
My intention is to create an app whose main activity contains some tabs (which sticks on the top throughout the app). Clicking each tab opens a new fragment below the tabs.
Issue is when I click on a tab do something, then go to anther tab which opens a new fragment, then comes back to first tab - my changes here are not maintained.
Flow:
I really need to implement this logic. If my approach is wrong, please suggest alternative.
Thanks
Code:
Main Activity
public class FagTabHostMain extends FragmentActivity {
FragmentTabHost mTabHost;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fag_tab_host_main);
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
mTabHost.addTab(mTabHost.newTabSpec("audio").setIndicator("Audio"),
AudioContainerFragmentClass.class, null);
mTabHost.addTab(mTabHost.newTabSpec("video").setIndicator("Video"),
VideoContainerFragmentClass.class, null);
}
#Override
public void onBackPressed() {
boolean isPopFragment = false;
String currentTabTag = mTabHost.getCurrentTabTag();
if (currentTabTag.equals("audio")) {
isPopFragment = ((AudioContainerFragmentClass) getSupportFragmentManager()
.findFragmentByTag("audio")).popFragment();
} else if (currentTabTag.equals("video")) {
isPopFragment = ((VideoContainerFragmentClass) getSupportFragmentManager()
.findFragmentByTag("video")).popFragment();
}
// Finish when no more fragments to show in back stack
finish();
}
}
Main activity layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<android.support.v4.app.FragmentTabHost
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Not Using this one right now -->
<FrameLayout
android:id="#android:id/tabcontent"
android:layout_width="0dip"
android:layout_height="0dip"
android:layout_weight="0" />
</android.support.v4.app.FragmentTabHost>
<FrameLayout
android:id="#+id/realtabcontent"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" />
</LinearLayout>
AudioContainerFragmentClass
public class AudioContainerFragmentClass extends Fragment implements
OnClickListener {
final String TAG = "AudioContainerFragmentClass";
private Boolean mIsViewInitiated = false;
private boolean addToBackStack = true;
private Button bNextFragment;
private LinearLayout linearLayout;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
try {
Log.e("AudioContainerFragmentClass", "onCreateView called");
linearLayout = (LinearLayout) inflater.inflate(
R.layout.audio_fragment_container, container, false);
} catch (Exception e) {
printException(e.toString());
}
return linearLayout;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
try {
super.onActivityCreated(savedInstanceState);
Log.e("AudioContainerFragmentClass", "onActivityCreated called");
if (!mIsViewInitiated) {
mIsViewInitiated = true;
initView();
}
} catch (Exception e) {
printException(e.toString());
}
}
private void initView() {
try {
Log.e("AudioContainerFragmentClass", "initView called");
bNextFragment = (Button) linearLayout
.findViewById(R.id.bNextFragment);
bNextFragment.setOnClickListener(this);
replaceFragment(new AudioFragment(), false);
} catch (Exception e) {
printException(e.toString());
}
}
private void replaceFragment(AudioFragment audioFragment, boolean b) {
try {
FragmentTransaction ft = getChildFragmentManager()
.beginTransaction();
if (addToBackStack) {
ft.addToBackStack(null);
}
ft.replace(R.id.audio_sub_fragment, audioFragment);
ft.commit();
getChildFragmentManager().executePendingTransactions();
} catch (Exception e) {
printException(e.toString());
}
}
// Called from FagTabHostMain Activity
public boolean popFragment() {
boolean isPop = false;
try {
Log.e("AudioContainerFragmentClass", "popFragment called");
if (getChildFragmentManager().getBackStackEntryCount() > 0) {
isPop = true;
getChildFragmentManager().popBackStack();
}
} catch (Exception e) {
printException(e.toString());
}
return isPop;
}
#Override
public void onClick(View arg0) {
TextView tv = (TextView)getActivity().findViewById(R.id.tvaudioTitle);
tv.setText("Text changed");
}
private void printException(String string) {
Log.e("__ERRORR__", string);
}
}
AudioFragment
public class AudioFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.audio_sub_fragment, container,
false);
return view;
}
}
Had the same thing in my app.
You will need to copy the FragmentTabHost to your project, point your code to use the new custom FragmentTabHost and then change the code of doTabChanged to following implementation:
private FragmentTransaction doTabChanged(String tabId, FragmentTransaction ft) {
TabInfo newTab = null;
for (int i=0; i<mTabs.size(); i++) {
TabInfo tab = mTabs.get(i);
if (tab.tag.equals(tabId)) {
newTab = tab;
}
}
if (newTab == null) {
throw new IllegalStateException("No tab known for tag " + tabId);
}
if (mLastTab != newTab) {
if (ft == null) {
ft = mFragmentManager.beginTransaction();
}
if (mLastTab != null) {
if (mLastTab.fragment != null) {
ft.hide(mLastTab.fragment);
}
}
if (newTab != null) {
if (newTab.fragment == null) {
newTab.fragment = Fragment.instantiate(mContext,
newTab.clss.getName(), newTab.args);
ft.add(mContainerId, newTab.fragment, newTab.tag);
findViewById(mContainerId).setContentDescription("DEBUG. add fragment to this container");
} else {
if (newTab.fragment.isHidden()){
ft.show(newTab.fragment);
}
else{
ft.attach(newTab.fragment);
}
}
}
mPreviousTab = mLastTab;
mLastTab = newTab;
}
return ft;
}
The change that was made is that instead of deattach/attach the fragment, we are doing hide/show
I believe your fragment is being re-instantiated each time you switch tab, which means that your field variables are reset.
You probably could use the saveInstance bundle to manage the state of your fragment but I find it more useful and simpler to use SharedPreferences. This also has the benefit of keeping the saved state even if your application is restarted.
To read and write variables to SharedPreferences I use this small helper class:
public class PreferencesData {
public static void saveString(Context context, String key, String value) {
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(context);
sharedPrefs.edit().putString(key, value).commit();
}
public static void saveInt(Context context, String key, int value) {
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(context);
sharedPrefs.edit().putInt(key, value).commit();
}
public static void saveBoolean(Context context, String key, boolean value) {
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(context);
sharedPrefs.edit().putBoolean(key, value).commit();
}
public static int getInt(Context context, String key, int defaultValue) {
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(context);
return sharedPrefs.getInt(key, defaultValue);
}
public static String getString(Context context, String key, String defaultValue) {
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(context);
return sharedPrefs.getString(key, defaultValue);
}
public static boolean getBoolean(Context context, String key, boolean defaultValue) {
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(context);
return sharedPrefs.getBoolean(key, defaultValue);
}
}
Now, as an example, to save your mIsViewInitiated variable, then in onPause:
#Override
protected void onPause() {
PreferencesData.saveBoolean(this, "isViewInitiated", mIsViewInitiated);
super.onPause();
}
And to retrieve it again:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
try {
super.onActivityCreated(savedInstanceState);
Log.e("AudioContainerFragmentClass", "onActivityCreated called");
// will now be true if onPause have been called
mIsViewInitiated = PreferencesData.getBoolean(this, "isViewInitiated", false);
if (!mIsViewInitiated) {
mIsViewInitiated = true;
initView();
}
} catch (Exception e) {
printException(e.toString());
}
}
Since this example variable tells whether some UI has been loaded, then you might want to set it to false when the activity is destroyed.
#Override
protected void onDestroy() {
PreferencesData.saveBoolean(this, "isViewInitiated", false);
super.onDestroy();
}
This answer is just a single option and shows my personal preference, whereas other options might suit your situation better. I would suggest taking a look at http://developer.android.com/guide/topics/data/data-storage.html
Modify your Activity to override onSaveInstanceState and your onCreate method to restore from a "savedInstanceState".
public static final String TAB_STATE = "TAB_STATE";
#Override
protected void onSaveInstanceState(Bundle outState) {
outstate.putParcelable(TAB_STATE, mTabHost.onSaveInstanceState());
super.onSaveInstanceState(outState);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fag_tab_host_main);
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
if(savedInstanceState==null || savedInstanceState.getParcelable(TAB_STATE)==null){
mTabHost.addTab(mTabHost.newTabSpec("audio").setIndicator("Audio"),
AudioContainerFragmentClass.class, null);
mTabHost.addTab(mTabHost.newTabSpec("video").setIndicator("Video"),
VideoContainerFragmentClass.class, null);
} else{
mTabHost.onRestoreInstanceState(savedInstanceState.getParcelable(TAB_STATE));
}
}
As stated above you can save and then restore your data via the Bundle, Shared Preferences, or a SQLite db. You may also want to call setRetainInstance(true) on your Fragment. This will stop your fragments from being re-created repeatedly.

Categories

Resources