I'm developing an app that uses fragment. In one of these fragments I retrieve data from a remote server and populate a listview. But I noticed that if a user inserts a new value and then goes back to the fragment it doesn't show it. The fragment shows the new value only after the user closes and reopens the app... How can I solve it? I need a way to refresh the fragment every time the user swipes and views it...
This is the code:
public class Page2Fragment extends Fragment {
TestImmagineAdapter adp2;
Archivio archivio;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// fragment not when container null
if (container == null) {
return null;
}
// inflate view from layout
View view = (LinearLayout)inflater.inflate(R.layout.page2,container,false);
ListView mylist = (ListView) view.findViewById(R.id.listView);
archivio = new Archivio();
adp2 = new TestImmagineAdapter(archivio.retTitle(), archivio.retArt(), this.getActivity().getApplicationContext());
mylist.setAdapter(adp2);
/*mylist.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Intent service = new Intent(view.getContext(), Web.class);
service.putExtra("href", archivio.getLink(position));
startActivity(service);
// TODO Auto-generated method stub
}
});*/
return view;
}
}
You need to notify your adapter of the change.
On the update of your data you use:
adp2.notifyDataSetChanged();
Related
I am moving my code from Activity to use it under Fragment view. The grid has multiple images which gets successfully displayed inside the fragment.I am trying to display detailed view based on the image clicked. But I am unable to get to do this, tried different ways but resulting one or other error.Earlier I used to have setContentView which does not seem to work when used for Fragment. I am already inflating the Fragment under OnCreateView method but not sure how load with the detailed view upon the image click.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_one, container, false);
int iconSize=getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
CustomGrid adapter = new CustomGrid(view.getContext(), iconSize);
GridView gridview = (GridView) view.findViewById(R.id.grid);
gridview.setAdapter(adapter);
gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Toast.makeText(view.getContext(), "You Clicked at " +web[+ position], Toast.LENGTH_SHORT).show();
//setContentView(R.layout.list_item_main);
mListView = (ListView) view.findViewById(R.id.item_list_view);
Item.getRecipesFromDB(OneFragment.this, DBReference);
}
});
return view;
}
#Override
public void newDataReceived(ArrayList<Item> itemList) {
ItemAdapter adapter = new ItemAdapter(mListView.getContext(), itemList);
mListView.setAdapter(adapter);
}
Open a new Fragment when a gridView is clicked and then pass the position from the bundle parameters. Then in NewFragment show the listview and the data from database.
gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
NextFragment nextFrag= new NextFragment();
Bundle bundle = new Bundle();
bundle.putInt("POSITION",position);
this.getFragmentManager().beginTransaction()
.replace(R.id.Layout_container, nextFrag,TAG_FRAGMENT)
.addToBackStack(null)
.commit();
}
});
In the NextFragment get the reference of listView and then update the data from database using proper adapter.
I have an app with a single activity that contains 7 fragments. In one of the fragments, I have a ListView that uses an Adapter to get a list of people from the database. I would like to be able to touch one of the people in "Fragment A" and have the app switch to "Fragment B", and have the information about that person populated in Fragment B.
I already have most of this working. My Fragment A reads the database and gets a list of people. If I hard code a name in Fragment B, it will successfully read the database and populate the information about the person.
What I am having trouble figuring out is, (1) how to isolate an individual row in Fragment A in order to place an onclicklistener on it, and (2) how to send that name from Fragment A to be picked up by Fragment B.
In Fragment A I have:
public class PeopleList extends Fragment {
private View rootView;
private DatabaseHelper myDatabaseHelper;
private SimpleCursorAdapter = mySimpleCursorAdapter;
private Cursor personCursor;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
rootView = inflater.inflate(R.layout.peoplelayout, container, false);
myDBHelper = new DatabaseHelper(getActivity());
personCursor = myDBHelper.getPeopleCursor();
String[] fromColumns = {"_id", "firstname", "lastname"};
int toViews = {R.id.person_id, R.id.person_firstname, R.id.person_lastname};
mySimpleCursorAdapter = new SimpleCursorAdapter(getActivity(), R.layout.people_layout, personCursor, fromColumns, toViews, 0);
ListView myListView = (ListView) rootView.findViewById(R.id.people_row);
myListView.setAdapter(mySimpleCursorAdapter);
myDBHelper.close();
return rootView;
}
}
Fragment B is similar to Fragment A, except I [want to] pass in the person ID
demographicDataCursor = myDBHelper.getDemographicDataCursor(person_id);
However, currently, the person_id is hard coded for each person I want to view.
Like I said, I'm not sure how to isolate each person in the ListView of Fragment A in order to attach an onclicklistener to it, and how to send the person_id to Fragment B. I am aware of intents, but I have read several pages that say not to use intents when communicating from one fragment to another within the same activity.
In PeopleList set OnItemClickListener on ListView and on click of item put values to Bundle and Add that Bundle to Fragment and Done transaction of Fragment.
myListView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// TODO Auto-generated method stub
Cursor cursor = (Cursor) mySimpleCursorAdapter.getItem(position);
String name = cursor.getString(cursor
.getColumnIndex("firstname"));
FragmentB frag = new FragmentB();
Bundle b = new Bundle();
b.putString("name",name);
frag.setArguments(b);
getFragmentManager().beginTransaction().add(R.id.yourContainer, frag)
.commit();
}
});
Now in FragmentB receive the values from Bundle as below
public class FragmentB extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
// TODO Auto-generated method stub
View v = inflater.inflate(R.layout.fragment_b, container, false);
String name = getArguments().getString("name", "");
if(!name.equals("")){
Log.e("Name", name);
}
return v;
}
}
The context is:
I have an activity consisting of a fragment where there is a form to enter a date and a flight number. There are no other fragments there.
On click of a button, a request is made to a webservice.
A List of Flight Objects is returned from the webservice.
A custom ArrayAdapter is created for each row in the listFragment.
Show the results in a ListFragment in the same Activity on the frontend.
FlightResultAdapter.java:
public class FlightResultAdapter extends ArrayAdapter<Flight>{
public FlightResultAdapter(Context context, List<Flight> flights) {
super(context, R.layout.item_flight, flights);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Flight flight = getItem(position);
if (convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_flight, parent, false);
}
//Set the content of the custom row layout
TextView tvFlightNum = (TextView) convertView.findViewById(R.id.tvFlightNum);
tvFlightNum.setText(flight.getNumber());
return convertView;
}
}
Note: ListFragment has a default layout that consists of a single list view. Source
So I do not need a layout file for the list.
MyActivity.java: A list of objects (flightList.getFlight) is used to create the CustomListAdapter. This code is inside a function that is triggered on an OnClick.
FlightResultAdapter adapter =
new FlightResultAdapter(getApplicationContext(), flightList.getFlight());
FlightFragment.java
public class FlightFragment extends ListFragment {
private List<Flight> flight_items;
public FlightFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
flight_items = new ArrayList<Flight>();
//Initialise the list adapter and set
FlightResultAdapter adapter = new FlightResultAdapter(getActivity(), flight_items);
setListAdapter(adapter);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
Flight flight = flight_items.get(position);
Toast.makeText(getActivity(), flight.getNumber(), Toast.LENGTH_LONG).show();
}
}
So what I'm not getting is how to Show the FlightFragment on MyActivity.
Furthermore how to connect it so results are displayed: I think setListAdapter is used?
Update: Connecting the Fragment to the Activity
1. Add a FrameLayout to the activity layout, or other fragment layout
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
2. Use the FragmentManager to call the Fragment programmatically:
//Create the adapter here
FlightResultAdapter adapter = new FlightResultAdapter(getApplicationContext(), flightList.getFlight());
//Get the Fragment here and set the ListAdapter
FlightFragment ff = new FlightFragment();
// In case this activity was started with special instructions from an
// Intent, pass the Intent's extras to the fragment as arguments
ff.setArguments(getIntent().getExtras());
ff.setListAdapter(adapter);
if (findViewById(R.id.fragment_container) != null) {
//Send the Data to the fragment - Need Help Here
Bundle bundle = new Bundle();
//Show the Fragment
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container, ff);
fragmentTransaction.commit();
}
So the Fragment's OnCreate Method is being called, but the list is empty because I am not passing the Flight Object to the Fragment. How can I do this?
How can I pass the List object to the Fragment?
Because List contains Flight custom class object. so it's not possible to pass it directly.
To pass List<Flight> object:
1. Implement Serializable in Flight class.
2. Use Bundle.putSerializable for sending object from Activity to FlightFragment :
Bundle bundle = getIntent().getExtras();
bundle.putSerializable("flightList", flightList.getFlight());
ff.setArguments(bundle);
...
3. In FlightFragment class override onCreateView method and getArguments method:
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
Bundle args = getArguments();
List<Flight> flightList=(List<Flight>)args.getSerializable("flightList");
....
return super.onCreateView(inflater, container, savedInstanceState);
}
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 have nested fragments. I have activity A that has fragment B which has List fragment, when user clicks item from ListFragment I want to open new fragment using onListItemClick method.
But I am getting no view found for id error.
Code looks like this:
private ArrayAdapter arrayAdapter;
private ArrayList warnings;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
warnings = new ArrayList();
for(int i=0;i<10;i++) {
warnings.add(i);
}
arrayAdapter = new ArrayAdapter(inflater.getContext(), android.R.layout.simple_list_item_1, warnings);
setListAdapter(arrayAdapter);
//View view = inflater.inflate(R.layout.activity_other, container, false);
return super.onCreateView(inflater,container,savedInstanceState);
}
#Override
public void onItemClick(AdapterView adapter, View view, int position, long id) {
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
ListItemFragment listItemFragment = new ListItemFragment();
FragmentManager manager = getChildFragmentManager();
android.support.v4.app.FragmentTransaction ft = manager.beginTransaction();
ft.replace(android.R.id.tabcontent, listItemFragment);
ft.attach(listItemFragment).addToBackStack(null).commit();
}
it doesn't seem to like android.R.id.tabcontent.
I have other child fragments working fine.
Please help.
Are you nesting the fragments in xml? You can only add nested fragments programmatically. See the documentation here.
The problem I was having, I was trying to attach fragment when I am already in fragment.
This should be done by detaching current fragment and attaching another one.
Now my app works just fine.
Something like this:
ft.detach(getParentFragment()).replace(android.R.id.tabcontent, fragment);
ft.attach(fragment).addToBackStack(null).commit();