What I need to achieve
A screen displaying a ListView, which can be replaced by an error screen in case of problems (missing connection, server unavailable and the like).
I need to be able to switch (programmatically) back and forth between these two screens.
Requirements
The main screen must be a Fragment.
This is because my application is composed of several sections, each one accessible from the navigation drawer.
What I have done so far
The main fragment class is named AllQueuesFragment: its XML layout consists of a FrameLayout, which I use in combination with the FragmentManager to switch between ErrorFragment (containing the error message) and QueuesViewFragment (containing the ListView).
public class AllQueuesFragment extends Fragment
{
public AllQueuesFragment()
{
super();
}
#Override
public void onStart()
{
super.onStart();
// Show the right fragment based on connectivity status
checkConnection();
}
public void checkConnection()
{
final NetworkManager netManager = NetworkManager.getInstance(this.getActivity());
if (netManager.isConnected())
showQueues();
else
showNoConnection();
}
public void showNoConnection()
{
ErrorFragment fragNoConnection = new ErrorFragment();
displayFragment(fragNoConnection);
fragNoConnection.setTitle(R.string.text_no_connection);
fragNoConnection.setIcon(R.drawable.thatfeel);
fragNoConnection.setLoaderVisibility(false);
}
public void showQueues()
{
QueuesViewFragment fragQueuesView = new QueuesViewFragment();
displayFragment(fragQueuesView);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the view
View rootView = inflater.inflate(R.layout.fragment_allqueues, container, false);
return rootView;
}
// Displays a new fragment
public void displayFragment(Fragment fragment)
{
if (fragment != null)
{
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();
}
}
}
The error screen is the following:
public class ErrorFragment extends Fragment
{
private TextView textTitle;
public ErrorFragment()
{
super();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the view
View rootView = inflater.inflate(R.layout.fragment_error, container, false);
// Get the widgets
textTitle = (TextView)rootView.findViewById( R.id.fragment_error_text );
return rootView;
}
// Set methods
public void setTitle(int id) { textTitle.setText(id); }
}
The problem
The setTitle() method gets called before the layout is ready, and as a result, a NullPointerException is thrown.
class AllQueuesFragment
{
....
public void displayFragment(Fragment fragment)
{
if (fragment != null)
{
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();
}
}
public void showNoConnection()
{
ErrorFragment fragNoConnection = new ErrorFragment();
displayFragment(fragNoConnection);
// PROBLEM HERE: Before calling setTitle(), I must be sure that ErrorFragment's
// layout is inflated!
fragNoConnection.setTitle(R.string.text_no_connection);
}
....
}
class ErrorFragment
{
....
public void setTitle(String value) { textTitle.setText(value); }
....
}
I can't call setTitle() directly from ErrorFragment::onCreateView(), because I don't know beforehand which message I need to show.
How can I ensure that fragNoConnection has completed its layouting?
Is there a better way to achieve my goal?
Unsatisfying workaround
The only workaround I can think of is to use a buffer to defer the actual call:
class ErrorFragment
{
// This string will hold the title until the layout is inflated
private String titleBuffer;
private TextView textTitle = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the view
View rootView = inflater.inflate(R.layout.fragment_error, container, false);
// Get the widgets
textTitle = (TextView)rootView.findViewById( R.id.fragment_error_text );
// Do the actual set
setTitle(titleBuffer);
return rootView;
}
....
public void setTitle(String value)
{
titleBuffer = value;
// If the layout is not inflated, defer the actual set
if (textTitle != null)
textTitle.setText(titleBuffer);
}
....
}
but I don't like this solution very much (the code above is simplified; ErrorFragment has more properties).
Advices?
Thanks in advance
This is exactly the type of thing arguments are supposed to be used for:
public void showNoConnection() {
ErrorFragment fragNoConnection = new ErrorFragment();
Bundle args = new Bundle();
//you can also use putInt here if you'd rather pass a string resource id, along with anything else you can stick into a Bundle
args.putString("title", "some title");
fragNoConnection.setArguments(args);
displayFragment(fragNoConnection);
}
Then in ErrorFragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_error, container, false);
TextView textTitle = (TextView)rootView.findViewById( R.id.fragment_error_text );
//now retrieve the argument...
textTitle.setText(getArguments().getString("title"));
return rootView;
}
The Fragment will even remember it's arguments after an orientation change.
If you feel like being pedantic, you can create a static factory method within ErrorFragment that takes the title as an argument and then creates the Fragment and adds the argument, that way you can achieve proper encapsulation :)
You need to have a callback method in your ErrorFragment and when the view is inflated you then call the method in your callback interface in the onViewCreated and set the title.
sample:
in ErroFragment
public class ErroFragment extends Fragment
{
static interface ErrorDone{
public void doneInflating();
}
private TextView textTitle;
private ErrorDone ed;
public ErroFragment()
{
super();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the view
View rootView = inflater.inflate(R.layout.fragment_error, container, false);
// Get the widgets
textTitle = (TextView)rootView.findViewById( R.id.fragment_error_text );
return rootView;
}
// Set methods
public void setTitle(int id) { textTitle.setText(id); }
public void setInterFace(ErrorDone er){ this.ed = er; }
}
Then you implement the interface in your AllQueuesFragment
public class AllQueuesFragment extends Fragment implements ErroFragment.ErrorDone
It will generate method doneInflating
and you need to set the interface:
public void showNoConnection()
{
ErrorFragment fragNoConnection = new ErrorFragment();
displayFragment(fragNoConnection);
fragNoConnection.setInterFace(this);
}
And in the generated method(doneInflating) of the AllQueuesFragment you then set the title in there:
public void doneInflating(){
fragNoConnection.setTitle(R.string.text_no_connection);
fragNoConnection.setIcon(R.drawable.thatfeel);
fragNoConnection.setLoaderVisibility(false);
}
If you want to be sure that the FragmentTransaction is commited and effective, you can use the executePendingTransactions method:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, fragment).commit();
fragmentManager.executePendingTransactions();
But, the right way to do it is to send the title value to the Fragment when instantiating it. This is the default pattern when you create a Fragment from your IDE (eclipse or Android Studio)
Related
I'm struggling with a puzzling sequence of events relating to a Fragment. I'm trying to add a fragment to an Activity, and then call a method inside the fragment to update some text. However, what I am finding is that the method is being processed in the fragment before onCreateView() finishes, which leaves me with a null View object, and my method fails. Here is the Activity code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log_entry_details);
fragmentManager = getSupportFragmentManager();
titleBarFragment = new TitleBarVerticalFragment();
fragmentTransaction = fragmentManager.beginTransaction ();
fragmentTransaction.add(R.id.log_entry_title_frame, titleBarFragment);
fragmentTransaction.commit();
titleBarFragment.updateTitleBar("Edit Log Entry", 20, false);
}
Seems simple enough. Here is the TitleBarVerticalFragment class:
public class TitleBarVerticalFragment extends TitleBarFragment {
#Inject SharedVisualElements sharedVisualElements;
View view;
TextView titleLabel;
public TitleBarVerticalFragment() {
// add this line for any class that want to use any of the singleton objects
Injector.INSTANCE.getAppComponent().inject(this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Log.d(Constants.TAG, "title fragment onCreateView()");
view = inflater.inflate(R.layout.fragment_title_bar_vertical, container, false);
ImageView logoImage = (ImageView) view.findViewById(R.id.logo_vertical);
titleLabel = (TextView) view.findViewById(R.id.verticalTitleLabel);
titleLabel.setTextColor(sharedVisualElements.secondaryFontColor());
titleLabel.setTypeface(sharedVisualElements.font());
titleLabel.setTextSize(20);
logoImage.setImageDrawable(sharedVisualElements.logoImage());
logoImage.setBackgroundColor(Color.TRANSPARENT);
return view;
}
public void updateTitleBar(String text, int textSize, boolean titleLabelIsHidden) {
Log.d(Constants.TAG, "about to update title bar text");
if (view == null) {
Log.d(Constants.TAG, "vertical title fragment is null");
return;
}
if (titleLabel == null)
titleLabel = (TextView) view.findViewById(R.id.verticalTitleLabel);
if (titleLabel == null) {
Log.d(Constants.TAG, "vertical title label is null");
return;
}
Log.d(Constants.TAG, "updating title text: " + text);
titleLabel.setText(text);
titleLabel.setTextSize(textSize);
}
Note the order of this logcat output. Notice how onCreateView() seems to run after the updateTitleBar() method? How can that be?
about to update title bar text vertical title fragment is null
title fragment onCreateView()
How can I ensure that onCreateView() runs before I call any of the fragment's other methods? Thank you.
Try running fragmentManager.executePendingTransactions() after fragmentTransaction.commit(); and before titleBarFragment.updateTitleBar("Edit Log Entry", 20, false);
Just use onStart() on your activity
Define a listener interface and implement it in your Activity.
interface LyfecycleListener {
void onCreatedView();
}
in your Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
...
this.titleBarFragment = new TitleBarVerticalFragment();
this.titleBarFragment.setListener(this)
...
}
#Override
public void onCreatedView() {
titleBarFragment.updateTitleBar("Edit Log Entry", 20, false);
}
in your Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
...
this.listener.onCreatedView();
}
I created a tabbed app where the main acitvity contains two layouts. The top layout contains the actual tabbar (which is a fragment). Underneth the content layout contains another fragments depending on which tabbar button the user has clicked. In order to stay compatible with older android versions I use android.support.v4.app.Fragment.
So, in the tabbar menu I added two buttons and each button triggers another fragment in the content. This is what the code looks like:
public class TabbarMenuFragment extends Fragment implements View.OnClickListener {
LiveFragment liveFragment;
OddsFragment oddsFragment;
FragmentTransaction fragmentTransaction;
Button liveButton;
Button oddsButton;
public TabbarMenuFragment() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
liveFragment = new LiveFragment();
oddsFragment = new OddsFragment();
fragmentTransaction = getFragmentManager().beginTransaction().add(R.id.content_view, oddsFragment);
fragmentTransaction.commit();
View rootView = (View) inflater.inflate(R.layout.tabbar_menu, container, false);
liveButton = (Button) rootView.findViewById(R.id.liveButton);
liveButton.setOnClickListener(this);
oddsButton = (Button) rootView.findViewById(R.id.oddsButton);
oddsButton.setOnClickListener(this);
return rootView;
}
public void updateUIInTabs() {
liveFragment.updateUI();
}
#Override
public void onClick(View v) {
if(v == liveButton) {
fragmentTransaction = getFragmentManager().beginTransaction().replace(R.id.content_view, liveFragment);
fragmentTransaction.commit();
}
if(v == oddsButton) {
fragmentTransaction = getFragmentManager().beginTransaction().replace(R.id.content_view, oddsFragment);
fragmentTransaction.commit();
}
updateUIInTabs();
}
}
The important thing is that the liveFragment is a Fragment that contains a ListView:
public class LiveFragment extends Fragment {
LiveMainAdapter adapter;
ListView list;
LayoutInflater inflater;
View rootView;
public LiveFragment() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
this.inflater = inflater;
rootView = (View) inflater.inflate(R.layout.live_fragment, container, false);
adapter = new LiveMainAdapter(inflater);
list = (ListView) rootView.findViewById(R.id.live_fragment_ListView);
list.setAdapter(adapter);
list.setDivider(null);
list.setDividerHeight(0);
return rootView;
}
public void updateUI() {
if(list != null) {
list.invalidate();
adapter.createRowObjects();
adapter.notifyDataSetChanged();
}
}
}
The oddsFragment is so far just a dummy with a TextView:
public class OddsFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = (View) inflater.inflate(R.layout.odds_fragment, container, false);
return rootView;
}
}
Now there are two settings which are important:
First:
As described above: I start the app and the oddsFragment is initally shown. Now, when I click on the liveFragment button the liveFragment's ListView is not updated.
Clicking again on the button for oddsFragment the oddsFragment is properly shown. Clicking back to liveFragment I get nothing - no ListView is shown.
The second setting:
Is exactly the same as the first, but instead I set the liveFragment as the intial view that is in TabbarMenuFragment I replace:
fragmentTransaction = getFragmentManager().beginTransaction().add(R.id.content_view, oddsFragment);
with
fragmentTransaction = getFragmentManager().beginTransaction().add(R.id.content_view, liveFragment);
Then the ListView is properly shown and the data in the list view is updated and displayed correctly. However, if I click on oddsFragement and then again on liveFragement the ListView has disappeared.
I already tried different things for over two hours now and I'm pretty desperated because I have not clue what might be the reason for this wired behaviour.
Anybody got an idea what is going on here?
Give this a try...
In your LiveFragment add a Handler and a Runnable and update the UI from your Runnable.
Handler handler = new Handler();
Runnable updater = new Runnable()
{
public void run()
{
if(list != null) {
list.invalidate();
adapter.createRowObjects();
adapter.notifyDataSetChanged();
}
}
};
and then change your updateUI() method in LiveFragment
public void updateUI()
{
handler.post(updater);
}
I have seen Link1 for this issue but could understand it right. I have a fragment that loads a list. When i click the list item it opens another activity. But i press back button it loads the list again. I want it to be at the same scroll position where it was before. In above mentioned link it specifies to use flag but i haven't got the point.
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
android.app.Fragment fragment = new MeFragment();
getFragmentManager().beginTransaction().replace(R.id.layout_FragmentsContainer, fragment).addToBackStack(null).commit();
}
}
public class MeFragment extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_me, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
meLV = (ListView) getView().findViewById(R.id.lv_Inbox);
loadingListProgress = (ProgressBar) getView().findViewById(R.id.progress_LoadingList);
meList = new ArrayList<Message>();
meAdapter = new MessagesListAdapter(getActivity(), meList);
//addFooter();
meLV.setAdapter(meAdapter);
meLV.setOnItemClickListener(this);
pageCount = 0;
loadmoreProgressDialog = new ProgressDialog(getActivity());
loadmoreProgressDialog.setTitle("Please wait ...");
loadmoreProgressDialog.setMessage("Loading more ...");
loadmoreProgressDialog.setCancelable(true);
loadUserMessages();
meLV.setOnScrollListener(new EndlessScrollListener() {
#Override
public void onLoadMore(int page, int totalItemsCount) {
// TODO Auto-generated method stub
//addFooter();
loadmoreProgressDialog.show();
loadUserMessages();
}
});
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// TODO Auto-generated method stub
Utils.showToast_msg(getActivity(), "MessageItemClicked");
ReferralDetailFragment fragment = new ReferralDetailFragment();
getFragmentManager().beginTransaction().replace(R.id.layout_FragmentsContainer, fragment).addToBackStack(null).commit();
}
}
public class ReferralDetailFragment extends Fragment implements OnClickListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_referraldetail,container, false);
linkToAcknowledge = (TextView) view.findViewById(R.id.lbl_Link_to_Acknowledge);
return view;
}
}
I implemented a simple solution for this in my app, basically when you press back to go to the fragment again, onCreateView() is called. Here in onCreateView() you have done all initialization, so we change
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_me, container, false);
/*
*Whatever you want to do
*
*/
return view;
}
to:
View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if(view==null){
view = inflater.inflate(R.layout.fragment_me, container, false);
/*
*Whatever you want to do
*
*/
}
else{
((ViewGroup)view.getParent()).removeView(view);
}
return view;
}
Here, we move View view outside and make it a class variable. So if it is the first time the fragment is called, it is null and the initialization occurs, otherwise it goes to else black. Else block is required because onCreateView() adds whatever it returns as a child of the view's parent, so since view is already there, we remove it and onCreateView automatically adds it again.
According to our exchange in the comments, I completely deletde my answer and re-write a new one.
I copy/paste the code from one of my apps and removing the useless things and changing the names. Hope there is not too many typing mistakes, at that it is the minimum required to have it working.
When I pop back to FirstFragment from SecondFragment, the scroll position of FirstFragment is the same as when I clicked an item to load the SecondFragment.
Note that I don't extend FragmentActivity. I have an activity which loads the fragments.
Extend/modify to match your needs.
MainActivity :
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
}
}
FirstFragment Class :
public class FirstFragment extends Fragment implements OnItemClickListener {
private ListView mListView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.first_fragment_layout, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mListView = (ListView) getView().findViewById(R.id.listview_first_fragment);
mListView.setAdapter(mAdapter); // depends on your adapter
mListView.setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mListView.setItemChecked(position, true);
//in case you need, set the bundle here, for example pass the position
Bundle arguments = new Bundle();
arguments.putInt("position", position);
SecondFragment secondFragment = new SecondFragment();
secondFragment.setArguments(arguments);
getFragmentManager().beginTransaction().replace(R.id.fragment_container, secondFragment).addToBackStack(null).commit();
}
}
SecondFragment Class :
public class SecondFragment extends Fragment {
private Integer mPosition;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.second_fragment_layout, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle arguments = getArguments();
if (arguments == null) {
mPosition= 0;
} else {
mPosition= arguments.getInt("Position");
}
}
}
What you are trying to achieve may be done with help of savedInstanceState. i also had this kind of problem which i resolved by using add() method instead of replace() in transition.
If you can change your method or already not using add() than give it a shot.
and if add() method didn't do the trick then check the implementation of savedInstanceState.
correctly save instance state.
How to save states of fragment views.
I'm using loader in my ListView fragment, and it's getting recreated on pressing "back" button. Can you tell me how to handle this senario?
Here is my ListView fragment code. Here I have a boolean variable that I'm setting as true on clicking on list item. but once the back button is pressed onCreateView will get called so the backbutton will be false.
public class GTFragment extends SherlockFragment implements LoaderCallbacks<Cursor>{
ListView mTListview = null;
GoogleTasksAdapter mGTasksAdapter = null;
private SQLiteCursorLoader mTLoader=null;
private LoaderManager mTLoaderManager;
private String mSelectedListID = null;
private boolean mIsBackbuttonisPressed = false;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.task_home_activity, container, false);
if(!mIsBackbuttonisPressed)
getLoaderManager().initLoader(0, null, this);
mTListview = (ListView) view.findViewById(R.id.id_task_list_home_activity);
mGTasksAdapter = new GoogleTasksAdapter(getActivity());
mTListview.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listview,
View clickedview, int position, long arg3) {
// TODO Auto-generated method stub
GoogleTaskItem item = new GoogleTaskItem();
Cursor coursor = ((GoogleTasksAdapter)listview.getAdapter()).getCursor();
if(coursor.moveToPosition(position))
{
mIsBackbuttonisPressed = true;
GoogleTaskController.get_googletask_controllerObj()
.LaunchTaskPreviewActivity();
}
}
});
mTListview.setAdapter(mGTasksAdapter);
mIsBackbuttonisPressed = false;
return view;
}
My fragment activity class code
public class TLActivity extends SherlockFragmentActivity {
LeftSliderTaskListOptions mTaskOptionsFragment = null;
GoogleTasksFragment mTFragment = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
setContentView(R.layout.layout_gt_list);
// FragmentTransaction tfragment = this.getSupportFragmentManager().beginTransaction();
mTFragment = new GTasksFragment();
t.replace(R.id.id_tfragment, mTFragment);
t.commit();
}
instead of
t.replace(R.id.id_tfragment, mTFragment);
use
t.add(R.id.id_tfragment, mTFragment);
It worked for me
I don't think that the accepted answer is right because Fragment.onSaveInstanceState will not be called until the activity hosting it needs to save its state: The docs states:
There are many situations where a fragment may be mostly torn down
(such as when placed on the back stack with no UI showing), but its
state will not be saved until its owning activity actually needs to
save its state.
In other words: if you're using a Activity with multiple fragments for each screen (which is very common), the fragment state will not be saved when you move the next screen.
You also can't use Fragment.setRetainInstance because he's meant only to fragments that aren't on the back stack.
Most of the time, you don't have to think about this but sometimes it's important. Like when you have scrolled a list and want to "remember" the scroll location.
I took a long time to realize that the fragments put on the back stack are kind of saved and you can reuse the view that you already created instead of creating one every time the fragment calls onCreateView. My setup is something like this:
public abstract class BaseFragment extends Fragment {
private boolean mSaveView = false;
private SoftReference<View> mViewReference;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (mSaveView) {
if (mViewReference != null) {
final View savedView = mViewReference.get();
if (savedView != null) {
if (savedView.getParent() != null) {
((ViewGroup) savedView.getParent()).removeView(savedView);
return savedView;
}
}
}
}
final View view = inflater.inflate(getFragmentResource(), container, false);
mViewReference = new SoftReference<View>(view);
return view;
}
protected void setSaveView(boolean value) {
mSaveView = value;
}
}
public class MyFragment extends BaseFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
setSaveView(true);
final View view = super.onCreateView(inflater, container, savedInstanceState);
ListView placesList = (ListView) view.findViewById(R.id.places_list);
if (placesList.getAdapter() == null) { // this check is important so you don't restart your adapter
placesList.setAdapter(createAdapter());
}
}
}
You have multiple options to rectify this issue.
Override onSaveInstanceState like this:
#Override
public void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("mIsBackbuttonisPressed", mIsBackbuttonisPressed);
}
and then in your onCreateView you can get your variable back by:
if (savedInstanceState != null)
mIsBackbuttonisPressed = savedInstanceState.getBoolean("mIsBackbuttonisPressed", false);
You can set this.setRetainInstance(true); in your onCreate method of your fragment.
If you could post your Activity code with creates your fragment I can also tell you other options. (P.S I cannot write it as a comment so posting it in the answer.)
I am trying to implement Fragments in my Project using the https://github.com/JakeWharton/Android-ViewPagerIndicator plugin.
My Fragment
public final class NearByFragment extends Fragment {
private static String TAG = "bMobile";
public static NearByFragment newInstance(String content) {
NearByFragment fragment = new NearByFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
return inflater.inflate(R.layout.fragment_search_nearby, null);
}
}
Now I want to execute some code like start start a new thread and download a JSON from the server and then assign a list view from the content I download. In fragments we are assigning views in onCreateView. so where should I write the
listview = (ListView) findViewById(R.id.list_items);
((TextView) findViewById(R.id.title_text))
.setText(R.string.description_blocked);
and other code to generate the Fragment view ?
You can search within the view that you just inflated:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView");
View v = inflater.inflate(R.layout.fragment_search_nearby, null);
listview = (ListView)v.findViewById(R.id.list_items);
((TextView)v.findViewById(R.id.title_text))
.setText(R.string.description_blocked);
return v;
}
You can also use the Fragment.getView() function elsewhere in your code and call that view's findViewById() member.
You can use getActivity().findByView() from the Fragment if you want to have access to the layout elements. Alternatively, you can just put the findByView() call in the main Activity.