How to implement a listview into a fragment? [duplicate] - android

This question already has answers here:
Android ListView in Fragment
(2 answers)
Closed 9 years ago.
I am a beginner in android development.
For a project, I would like to know how to implement a listview into a fragment ?
In my project, I have 3 fragments.
I have to retrieve all the contacts which are in my phone.
(I am using this example => http://samir-mangroliya.blogspot.fr/p/android-read-contact-and-display-in.html).
Then, I'll put them into one af the fragment, which contains a listview.
I am searching for many example, but it is only listview into ACTIVITY example.
Can you please help me ?
Best regards,
Tofuw
PS : Sorry for my bad english, I'm french :/
EDIT
Here is my code :
public class PhoneFrag extends ListFragment
{
private List<Contact>listecontact=new ArrayList<Contact>();
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
public void onActivityCreated(Bundle savedInstanceState, Context context)
{
super.onActivityCreated(savedInstanceState);
String[]values=new String[]{};
Cursor phones=context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);
while(phones.moveToNext())
{
String name=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String num=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Contact contact=new Contact();
contact.setName(name);
contact.setNum(num);
listecontact.add(contact);
}
phones.close();
ArrayAdapter<String>adapter=new ArrayAdapter<String>(getActivity(), android.R.layout.simple_expandable_list_item_2, listecontact);
setListAdapter(adapter);
}
I have an error at the third last line :
the constructor ArrayAdapter(FragmentActivity, int,
List) is undefined
Can you help me please ?
Tofuw

Get your Fragment to extend ListFragment instead of Fragment.If you have used or looked at examples with ListActivity there is no need to associate this fragment with an xml layout file using setContentView(layout) anymore,Android creates a readymade Fragment with a ListView within it for your conveniance.Instead conveniance methods like setListAdapter(adapter) are available to you.However,in case you would like to access the ListView instance use the getListView().The Fragment seems to use onActivityCreated to do this:
I am guessing that you know fragments well enough to understand that this in ListActivity mean getActivity() in your ListFragment.
Here is the code that I found in the Android Fragment Documentation:
public static class TitlesFragment extends ListFragment {
boolean mDualPane;
int mCurCheckPosition = 0;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Populate list with our static array of titles.
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));
// Check to see if we have a frame in which to embed the details
// fragment directly in the containing UI.
View detailsFrame = getActivity().findViewById(R.id.details);
mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
if (mDualPane) {
// In dual-pane mode, the list view highlights the selected item.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Make sure our UI is in the correct state.
showDetails(mCurCheckPosition);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
}
/**
* Helper function to show the details of a selected item, either by
* displaying a fragment in-place in the current UI, or starting a
* whole new activity in which it is displayed.
*/
void showDetails(int index) {
mCurCheckPosition = index;
if (mDualPane) {
// We can display everything in-place with fragments, so update
// the list to highlight the selected item and show the data.
getListView().setItemChecked(index, true);
// Check what fragment is currently shown, replace if needed.
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(index);
// Execute a transaction, replacing any existing fragment
// with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (index == 0) {
ft.replace(R.id.details, details);
} else {
ft.replace(R.id.a_item, details);
}
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
// Otherwise we need to launch a new activity to display
// the dialog fragment with selected text.
Intent intent = new Intent();
intent.setClass(getActivity(), DetailsActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
}
You can also use methods like setEmptyText and setListShown to display a message in case your Cursor has no rows and toggle the visibility of your listView respectively.Also,Android's Loader Framework is only supported with a Fragment and not an Activity in the support library.

Related

Fragment in viewpager savedinstancestate is always null

I know this question has been asked before but none of the answers given so far is of any help to me.
I have a viewpager which is populated with fragments (android.support.v4.app.Fragment) from a FragmentStatePagerAdapter . Some of these fragments contain logic that needs to be retained when the orientation changes, such as keeping track of which view is currently selected.
However, although I save the data in question in onSaveInstanceState the savedInstanceState is always null. I can solve this by storing the data in a static variable (which since I only have one instance of each fragment would work for me) but i found this to be a quite ugly solution and there has to be a proper way of doing this.
This is one of the fragments that doesn't retain it's state on rotation:
public class PriceSelectFragment extends Fragment {
private TableRow mSelected;
private int mSelectedPos = 0;
// newInstance constructor for creating fragment with arguments
public static PriceSelectFragment newInstance() {
PriceSelectFragment fragmentFirst = new PriceSelectFragment();
return fragmentFirst;
}
public PriceSelectFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_price_select, container, false);
TableLayout mTable = (TableLayout)view.findViewById(R.id.price_table);
List<PriceGroup> mPriceGroups = ((MainActivity) getActivity()).getPriceGroups();
int i = 0;
for (final PriceGroup group : mPriceGroups) {
//Create row from layout and access child TextViews
TableRow r = (TableRow)inflater.inflate( R.layout.price_group, mTable, false);
TextView size = (TextView)r.getChildAt(0);
TextView dimension = (TextView)r.getChildAt(1);
TextView weight = (TextView)r.getChildAt(2);
TextView price = (TextView)r.getChildAt(3);
//Populate row with PriceGroup Data
size.setText(group.sizeIndicator);
dimension.setText(String.format("%2.0fx%2.0fx%2.0f", group.length, group.width, group.height));
weight.setText(Float.toString(group.weight));
price.setText(Integer.toString(group.price));
//Alternate background color every other row
if (i % 2 == 0) {
r.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_1));
}
else {
r.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_2));
}
mTable.addView(r); // Add to table
r.setTag(i);
r.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectRow((TableRow) v);
}
});
i++;
}
mSelected = (TableRow)view.findViewWithTag(mSelectedPos);
selectRow(mSelected);
return view;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("selected", mSelectedPos);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
mSelectedPos = savedInstanceState.getInt("selected");
}
}
private void selectRow(TableRow row) {
if ((int) mSelected.getTag() % 2 == 0) {
mSelected.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_1));
}
else {
mSelected.setBackgroundDrawable(getResources().getDrawable(R.drawable.price_selector_2));
}
mSelected = row;
mSelectedPos = (int) mSelected.getTag();
mSelected.setBackgroundColor(getResources().getColor(R.color.light_blue));
}
}
How do I solve this without having to save my states in static variables?
Edit
I should point out that all of the fragments are programatically created and as such they do not have an id and I read that that might be the problem but I don't know how to solve that either.
Also my application is structured like this:
MainActivity with NavigationDrawer
Fragment1
ViewPager
subfragment1 - subfragment5
Fragment2
Fragment3
The fragments whose states I'm having trouble with are the subfragments.
In your Activity which is hosting your Fragment you need to store a refernce to the fragment in the Bundle.
Something like this should work for you
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
//Restore your fragment instance
fragment1 = getSupportFragmentManager().getFragment(
savedInstanceState, "fragment");
}
}
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "fragment", fragment1);
}
fragment1 is the instance of the Fragment1 that you mentioned in your question that needs to get recreated.
I haven't done this with a structure like yours before but this is how I would start:
In the onSaveInstanceState in your Fragment1 I believe you would need to do the same with each of the fragments in your ViewPager. Then in the onCreateView on your Fragment1 get the fragments from the fragment manager and recreate your ViewPager.
I have found this answer here which is pretty much the same but has a little more detail: https://stackoverflow.com/a/17135346/1417483
FragmentPagerAdapter is not calling onSaveInstanceState in frgments that are not visible anymore. Maybe this is what causing your issues.
Try to use FragmentStatePagerAdapter instead.
I finally got a solution and explanation why this is happening. I had a very similar problem. I recognized that when I was scrolling right to my 3rd subfragment and then back to the 1st then the state of the 1st got saved. But not on Orientation Change.
I figured that the state is only saved if the adapter's destroyItem(..) is called. That is not called automatically if orientation changes.
So now onSaveInstanceState of the MainFragment (which holds the ViewPager) I call destroyItem for each active fragment. I check for activity.isChangingConfigurations() because onSaveInstanceState is called too if I turn off the screen, but in that case all the fragments just stay active and nothing has to be changed.
I extended the adapter with an onDestroy(boolean retain) which is called then:
//in the main-fragment which holds the ViewPager:
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(getActivity()!=null && getActivity().isChangingConfigurations())
{
if (pager != null) {
try {
Log.w(TAG, TAG + " pager.onDestroy(true)");
pager.onDestroy(true);
} catch (Exception e) {
e.printStackTrace();
}
}
And the implementation in MyFragmentStatePagerAdapter:
public void onDestroy(boolean retain)
{
this.m_allowDynamicLoading = false;
if(retain)
{
try{
if(getAdapter()!=null)
{
int limit = this.getOffscreenPageLimit();
int currentIndex = this.getCurrentItem();
if(currentIndex <0 || getAdapter().getCount() <= 0)
return;
//active fragments = fragments that are (less or equal) then
//offscreenPageLimit awaw from the currently displayed one.
for(int i = Math.min(currentIndex+limit, getAdapter().getCount()-1);
i>= Math.max(0, currentIndex-limit);//erstes aktives fragment ist current - offscreen limit, aber nicht unter 0..
i--)
{
getAdapter().destroyItem(MessagingViewPager.this, i, getAdapter().instantiateItem(MessagingViewPager.this, i)); //this saved the state of that fragment, that will be restored after orientation change
Log.e(TAG,TAG + " orientation-change: destroying item " + i);
}
}
}catch(Exception e){}
}
else{ //retain = false is called onDestroy of the Fragment holding this Pager.
try{
this.setAdapter(null);
//this will destroy all fragments and forget the position
}catch(Exception e){}
}
}
Some other things are to be said:
Adapter takes the ChildFragmentManager not the normal one
The SubFragments must NOT use setRetainInstance(true) (Exception otherwise)
The MainFragment can (and in my case does) use setRetainInstance(true)
Create the adapter in onCreate of the MainFragment, so it will NOT be recreated on Orientation change. Setting adapter to pager should be done in onCreateView.
OnDestroy (or onDestroyView) of the MainFragment use setAdapter(null) to terminate all fragments and release resources. (This is done by MyViewPager.onDestroy(false) in my case)
et voiá: now you get your savedInstanceState bundle in the SubFragments after the orientation change. And it will not destroy the items if you only switch the screen off.

ArrayAdapter notifyDataSetChanged() not working in fragment

I have an array adapter and associated code that worked fine when in an activity. I'm migrating to using fragments and now it doesn't update. Using action bar tabs, if I go to my tab the first time the list populates and shows fine. If I go to a different tab and come back, the list is populated but the list view is empty.
If I add something to the list during the first visit, the list is updated fine. If I leave, come back, and add an item it does not show up. An item is added to the list by saving an image to the database and then calling refreshGallery().
#Override
public onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.inspection_images, container, false);
mListView = (ListView) v.findViewById(R.id.inspection_images_list);
setInspectionImages(mInspection.getInspectionImages());
return v;
}
#Override
public void onResume() {
refreshGallery();
}
public void refreshGallery() {
mInspectionImages = mInspection.getInspectionImages();
setInspectionImages(mInspectionImages());
}
public void setInspectionImages(ArrayList<InspectionImage> images) {
if (null == mArrayAdapter) {
mArrayAdapter = new InspectionImageAdapter(getActivity().getApplicationContext(), R.layout.inspection_image_list_item, images);
mListView.setAdapter(mArrayAdapter);
}
else {
mArrayAdapter.clear();
addInspectionImagesToList(images);
}
}
public void addInspectionImagesToList(ArrayList<InpsectionImage> images) {
mArrayAdapter.addAll(images);
mArrayAdapter.notifyDataSetChanged();
}
Assuming you've implemented onTabSelected() as per the Android developers guide, i.e.:
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// Check if the fragment is already initialized
if (mFragment == null) {
// If not, instantiate and add it to the activity
mFragment = Fragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content, mFragment, mTag);
} else {
// If it exists, simply attach it in order to show it
ft.attach(mFragment);
}
}
What happens when you show the fragment the first time:
in onTabSelected(), mFragment is null and a new one is instantiated
the created fragment is attached to mActivity
the fragment's onCreateView() is called, mListView is created, mArrayAdapter is created and populated and attached to mListView and mListView is returned
the list view items are visible and everything is dandy
What happens after you switched out to another tab then switched back to that same one:
in onTabSelected(), mFragment exists so only ft.attach(mFragment); is executed (on the same fragment as before, i.e. no new fragment is created)
the existing fragment is attached to mActivity once more
the fragment's onCreateView() is called (check the fragment lifecycle and what happens when a fragment is attached if you wonder why), a new mListView is created, setInspectionImages() is called and the old mArrayAdapter is present so it's populated but never attached to the new mListView
the mListView shown in the layout doesn't have any adapter attached, and all of your actions populate a now unrelated array adapter
For one thing you don't have to repopulate the adapter on each onResume(). Do it once at creation time (I would put it in onActivityCreated()) and just update it when necessary.
And then you don't need to check for the existence of mArrayAdapter, just create it every time in onActivityCreated().
If you want to keep your current design though, just be sure to nullify its reference when the list view disappears:
#Override
public void onDestroyView () {
mArrayAdapter = null;
mListView = null;
}

Fragments view is null when orientation changed

Im having some problems when it comes to porting my app from the normal activity style to the fragment style. Im beginning to notice that when a fragment gets recreated, or popped from the backstack it loses its views. When I say that Im talking about a listview in particular. What im doing is im loading items into the listview, then rotating the screen. When it goes back through, it gets a nullpointerexception. I debug it and sure enough the listview is null. Here is the relevant code to the fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
return inflater.inflate(R.layout.sg_question_frag, viewGroup, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
list = (ListView)getActivity().findViewById(R.id.sgQuestionsList);
if (savedInstanceState != null) {
catId = savedInstanceState.getInt("catId");
catTitle = savedInstanceState.getString("catTitle");
}
populateList(catId, catTitle);
}
And here is how it is called (keep in mind there are a few other fragments that im working with as well)
#Override
public void onTopicSelected(int id, String catTitle) {
// TODO Auto-generated method stub
FragmentManager fm = this.getSupportFragmentManager();
SGQuestionFragment sgQuestFrag = (SGQuestionFragment) fm.findFragmentByTag("SgQuestionList");
FragmentTransaction ft = fm.beginTransaction();
//If the fragment isnt instantiated
if (sgQuestFrag == null) {
sgQuestFrag = new SGQuestionFragment();
sgQuestFrag.catId = id;
sgQuestFrag.catTitle = catTitle;
//Fragment isnt there, so we have to put it there
if (mDualPane) {
//TO-DO
//If we are not in dual pane view, then add the fragment to the second container
ft.add(R.id.sgQuestionContainer, sgQuestFrag,"SgQuestionList").commit();
} else {
ft.replace(R.id.singlePaneStudyGuide, sgQuestFrag, "SqQuestionList").addToBackStack(null).commit();
}
} else if (sgQuestFrag != null) {
if (sgQuestFrag.isVisible()) {
sgQuestFrag.updateList(id, catTitle);
} else {
sgQuestFrag.catId = id;
sgQuestFrag.catTitle = catTitle;
ft.replace(R.id.sgQuestionContainer, sgQuestFrag, "SgQuestionList");
ft.addToBackStack(null);
ft.commit();
sgQuestFrag.updateList(id, catTitle);
}
}
fm.executePendingTransactions();
}
What I would ultimately want it to do is to completely recreate the activity, forget the fragments and everything and just act like the activity was started in landscape mode or portrait mode. I dont really need the fragments there, I can recreate them progmatically with some saved variables
If you want to get a reference to a view from within a Fragment always look for that View in the View returned by the getView() method. In your case, at the time you look for the ListView the Fragment's view probably isn't yet attached to the activity so the reference will be null. So you use:
list = (ListView) getView().findViewById(R.id.sgQuestionsList);

Dynamic UI with sliding menu and actionbarsherlock

Trying to achieve a dynamic UI with facebook like sliding menu and actionbarsherlock
.First i have look into android documentation which introduce fragment to handle dynamic button. But with no luck and a week time , i still can't get it to work anyhow , i guess is my misunderstand on android concept.The slidingbar and actionbarsherlock work without any problem.
I have a HomeScreen.java which contain all my menu and presetation stage
and so far i have created a pagerAdapter1.java that extends FragmentPagerAdapter
, and three example fragment class that handle my work which is task1.java,task2.java
,task3.java simple enough
here is part of my code
HomeScreen.java
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.slidingmenu.lib.SlidingMenu;
import com.slidingmenu.lib.app.SlidingFragmentActivity;
public class HomeScreen extends SlidingFragmentActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_screen);
setBehindContentView(R.layout.menu_frame);
}
PagerAdapter1.java
public class PagerAdapter1 extends FragmentPagerAdapter {
private List<Fragment> fragments;
public PagerAdapter1(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
public Fragment getItem(int position) {
return this.fragments.get(position);
}
public int getCount() {
return this.fragments.size();
}
}
and three task1.java,2,3
import android.support.v4.app.Fragment;
public class Tab1Fragment extends Fragment{
onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
return null;
}
return (LinearLayout)inflater.inflate(R.layout.tab_frag1_layout, container, false);
}
I think its better to explain my problem with picture
A homescreen which is a presetation stage , whenever user click on menu , this page will change to the page he want
and this is my menu
My problem is how do i include this 3 fragment into my homescreen ? i have tried so many tutorial but it doesn't work in my situation.Most tutorial are creating fragment with code, i just want to include my 3 task into it
I´ll try to explain this sample code and you use for your need.
This is the ListFragment of your BehindContent (SlidingMenu):
public class ColorMenuFragment extends ListFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.list, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String[] colors = getResources().getStringArray(R.array.color_names);
ArrayAdapter<String> colorAdapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, android.R.id.text1, colors);
setListAdapter(colorAdapter);
//This array is only to fill SlidingMenu with a Simple String Color.
//I used MergeAdapter from Commonsware to create a very nice SlidingMenu.
}
#Override
public void onListItemClick(ListView lv, View v, int position, long id) {
//This switch case is a listener to select wish item user have been selected, so it Call
//ColorFragment, you can change to Task1Fragment, Task2Fragment, Task3Fragment.
Fragment newContent = null;
switch (position) {
case 0:
newContent = new ColorFragment(R.color.red);
break;
case 1:
newContent = new ColorFragment(R.color.green);
break;
case 2:
newContent = new ColorFragment(R.color.blue);
break;
case 3:
newContent = new ColorFragment(android.R.color.white);
break;
case 4:
newContent = new ColorFragment(android.R.color.black);
break;
}
if (newContent != null)
switchFragment(newContent);
}
// the meat of switching the above fragment
private void switchFragment(Fragment fragment) {
if (getActivity() == null)
return;
if (getActivity() instanceof FragmentChangeActivity) {
FragmentChangeActivity fca = (FragmentChangeActivity) getActivity();
fca.switchContent(fragment);
} else if (getActivity() instanceof ResponsiveUIActivity) {
ResponsiveUIActivity ra = (ResponsiveUIActivity) getActivity();
ra.switchContent(fragment);
}
}
}
Here is your BaseActivity Class:
It dont have swipe, as I could understand, you don't need this.
public class FragmentChangeActivity extends BaseActivity {
private Fragment mContent;
public FragmentChangeActivity() {
super(R.string.changing_fragments);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set the Above View
if (savedInstanceState != null)
mContent = getSupportFragmentManager().getFragment(savedInstanceState, "mContent");
if (mContent == null)
mContent = new ColorFragment(R.color.red);
// set the Above View
//This will be the first AboveView
setContentView(R.layout.content_frame);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, mContent)
.commit();
// set the Behind View
//This is the SlidingMenu
setBehindContentView(R.layout.menu_frame);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.menu_frame, new ColorMenuFragment())
.commit();
// customize the SlidingMenu
//This is opcional
getSlidingMenu().setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "mContent", mContent);
}
public void switchContent(Fragment fragment) {
// the meat of switching fragment
mContent = fragment;
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content_frame, fragment)
.commit();
getSlidingMenu().showContent();
}
}
Ok, So If you want to change the ColorFragment to anything else, do this:
First, choice the item that you want to use:
case 0:
newContent = new ColorFragment(R.color.red);
break;
to:
case 0:
newContent = new ArrayListFragment();
break;
I have made just a arraylist, it is just a simple example, you can do a lot of thing, then you can read about Fragment to learn how to do different things.
public class ArrayListFragment extends ListFragment {
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, Listnames.TITLES));
//Listnames is a class with String[] TITLES;
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Log.i("FragmentList2", "Item clicked: " + id);
String item = (String) getListAdapter().getItem(position);
Toast.makeText(getActivity(), item, Toast.LENGTH_LONG).show();
}
}
Well, if you misunderstood something, just tell me.
My problem is how do i include this 3 fragment into my homescreen ?
It really depends on how do you want them to behave.
Do you want them to appear only one at a time without allowing swipeing between them? If yes then add/insert a container layout(for example a simple FrameLayout) in your Activity on which you'll add the Fragments. I didn't worked with the SlidingMenu library but it should have a callback called when you click one of the items in the menu. In that callback you'll attach the proper fragment to the container layout(the FrameLayout) I mention earlier.
Do you want to show only one Fragment but you want to allow the user to swipe between them? If yes use a ViewPager in the activity layout and in the callback triggered by the SlidingMenu library's menu selection set the current page of the ViewPager with the setCurrentItem() method.
If you want something different then this provide more details.
Most tutorial are creating fragment with code, i just want to include
my 3 task into it
This, I don't quite understand. If you want to "include" your task fragments directly in your xml layout, you can but you'll be limited on what you can do with them(not to mention that all the fragments will be on one single screen) and I would avoid it. If you want something else provide more details.
I don't think it will work like that with Fragments, I was looking for a solution as well and ended up adding the fragments by hand.
I'm working on something similar like this, but for me there was also the case of opening WebViews to designated URL's. So the "above" screen would always update on any click.
To control the behaviour of this I created a MenuItemResource object, which basically holds the properties, like the ID of the icon, the name of the menu item and the URL.
public class MenuItemResource {
private int aValue;
private int aUrl;
private int aIconIdle;
private int aIconActive;
public MenuItemResource(int value, int url, int iconIdle, int iconActive) {
aValue = value;
aUrl = url;
aIconIdle = iconIdle;
aIconActive = iconActive;
}
}
The behaviour is handled by an OnItemClickListener which checks with a switch which values are in the MenuItemResource that is being clicked. For the WebView it's quite straightforward:
newFragment = new WebViewFragment();
final Bundle arguments = new Bundle();
arguments.putString(Constants.KEY_URL, getString(item.getUrl()));
newFragment.setArguments(arguments);
startFragment(newFragment, false);
// boolean is used to add the fragment to the backstack
The startFragment method just uses the FragmentManager and FragmentTransaction to replace the current Fragment. This works the same for other MenuItemResources that do start regular fragments.
newFragment = new Task1Fragment();
startFragment(newFragment, false);
I don't refer to the fragments in the MenuItemResource (yet), but it works pretty well for URLs and WebViews. The fragments are started based on the value in the MenuItemResource
I'm not sure how you would refer to the fragments like you did in the comments (Task1.java, etc), since you don't start them with Intents like Activities. Also I'm not sure why you would want to do this dynamically for Fragments (I can imagine this case being dynamic for WebViews though) as they need to be compiled anyway, so that's why my menu items are added by hand.

Problems when switching ListView ChoiceMode on screen rotation

I am trying to build a split pane based on the example code provided at the end of the Android documentation about Fragments, basically a LinearLayout containing two fragments (all the details can be found in the above link):
TitlesFragment to display a list of titles
DetailsFragment to display the details of the currently selected title
My problem is that the following unexpected behavior happens:
I start the application in Landscape orientation: the titles list is displayed on the left and the details of the currently selected title (the first one at the beginning) are displayed on the right.
I select item X from the titles list: the title becomes highlighted since the ListView is set to CHOICE_MODE_SINGLE and its items implement the Checkable interface.
I switch to Portrait orientation (by rotating the device or emulator): as expected, only the titles list is shown and no item is selected in this configuration, because the ListView gets recreated and, by default, it is set to CHOICE_MODE_NONE.
I select item Y from the titles list: as expected, an activity showing only the DetailsFragment corresponding to the selection made is shown.
I switch back to Landscape orientation (here's where the unexpected behavior happens): the DetailsFragmenton the right correctly shows the details of item Y (which was selected in portrait orientation) but the TitlesFragment still shows item X as selected (i.e. the one which was selected BEFORE the first screen rotation).
Of course, I would like that the last selection made in Portrait orientation was correctly shown also within the TitlesFragment, otherwise I end up with an inconsistent highlighting which shows item X as selected while displaying the details of item Y.
I post the relevant code where the ListView mode is changed (within 'onActivityCreated') and the selected item is set (within the 'showDetails' method):
public static class TitlesFragment extends ListFragment {
boolean mDualPane;
int mCurCheckPosition = 0;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Populate list with our static array of titles.
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_activated_1, Shakespeare.TITLES));
// Check to see if we have a frame in which to embed the details
// fragment directly in the containing UI.
View detailsFrame = getActivity().findViewById(R.id.details);
mDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
if (mDualPane) {
// In dual-pane mode, the list view highlights the selected item.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Make sure our UI is in the correct state.
showDetails(mCurCheckPosition);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
}
/**
* Helper function to show the details of a selected item, either by
* displaying a fragment in-place in the current UI, or starting a
* whole new activity in which it is displayed.
*/
void showDetails(int index) {
mCurCheckPosition = index;
if (mDualPane) {
// We can display everything in-place with fragments, so update
// the list to highlight the selected item and show the data.
getListView().setItemChecked(index, true);
// Check what fragment is currently shown, replace if needed.
DetailsFragment details = (DetailsFragment)
getFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
// Make new fragment to show this selection.
details = DetailsFragment.newInstance(index);
// Execute a transaction, replacing any existing fragment
// with this one inside the frame.
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
// Otherwise we need to launch a new activity to display
// the dialog fragment with selected text.
Intent intent = new Intent();
intent.setClass(getActivity(), DetailsActivity.class);
intent.putExtra("index", index);
startActivity(intent);
}
}
Does anyone have an idea about how to solve such issue?
Thanks in advance.
Two years later, here I am working with the Fragment Layout sample from Android's v4 support library and I'm stuck with this exact same issue!
Here's the only fix I came up with that doesn't require using CHOICE_MODE_SINGLE all the time:
just add a call to getListView().setItemChecked(mCurCheckPosition, true); in the onResume() method of TitlesFragment. And... that's it!
Maybe you should set the value of outState BEFORE you call super.onSaveInstanceState?
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putInt("curChoice", mCurCheckPosition);
super.onSaveInstanceState(outState);
}
I've encountered the same problem on that code and as workaround I call setItemChecked on the onStart method:
#Override
public void onStart() {
super.onStart();
if (mDualPane) {
getListView().setItemChecked(mCurCheckPosition, true);
}
}
Or as LearningNerd said do it in onResume()
If you place android:configChanges="orientation" in your activity tag in the manifest file, your app will ignore the rotations but still render the relevant layouts.

Categories

Resources