How do I call findViewById() in ListFragment without overriding onCreateView? - android

I don't want to override onCreateView because there is no need. With a ListFragment all I am doing is taking an array of data, putting it in an ArrayAdapter and calling setListAdapter(arrayGoesHere) and then I have my populated ListFragment.
I am calling findViewById inside onActivityCreated() as it is the recommended place to find and store references to your views. And as you know, this is called after onCreateView() in the Android framework.
I can't do viewReturnedFromOnCreateView.findViewById because I'm not using onCreateView.
getActivity().findViewById doesnt work, because I'm actually not sure why.
getListView().findViewById doesnt work (because the element im trying to access is not a child of getListView()).
Edit 1: getView() didn't work either, I forgot to mention I am using the support library, android.support.v4.app.ListFragment. not sure if that matters
This is my code:
public class SomeFragment extends ListFragment {
private int someButtonId;
private Button someButton;
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String[] someList = getResources().getStringArray(R.array.someData);
ArrayAdapter<String> someAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_activated_1, someList);
setListAdapter(someAdapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
context = getActivity().getApplicationContext();
someButtonId = context.getResources().getIdentifier("someButton", "id", context.getPackageName());
someButton = (Button) getActivity().findViewById(someButtonId);
Log.i("hello", someButton.toString()); //Null pointer exception
}
}

Related

Communicate between Adapter, fragments and Sqlite Data base to refresh Fragments

I have three fragments that contains three ListView created using a BaseAdapter. Like the image below:
Anyway my listView is fetching data from an SqliteDatabase. What I need to know is: when I delete an item from my ListView My(Favorite,Rejected) Fragments ListViews are not notified and are not refreshing.
What I have tried so far is :
Call listView.invalidateViews() after notifyDataSetChanged() in the onResume() Method of my fragments .
I tried these solution two Android ListView not refreshing after notifyDataSetChanged
My code is :
In My BaseAdapter I'am using these method to refresh my adapter :
public void UpdateView(List<Voiture> items)
{
this.voitureList = items;
notifyDataSetChanged();
}
In My fragments I'am using these method to notify the adapter :
#Override
public void onResume() {
super.onResume();
adapterLogin.UpdateView(databaseHelper.getAllVoiture(username,currentLength));
listView.setAdapter(new AdapterLogin(getActivity(),voitureList,username,currentLength,1));
}
In the OncreateView() Method I'am using :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
inflate = inflater ;
x = inflater.inflate(R.layout.fragemnt_favoris,null);
empty = (TextView) x.findViewById(R.id.texteempty);
listView = (ListView) x.findViewById(R.id.list);
activity = (Main2Activity) getActivity() ;
username = activity.getUsername();
databaseHelper = new DatabaseHelper(getActivity());
databaseHelper.InsertActivity(2,username);
voitureList = databaseHelper.getAllVoitureFavourite(1,username);
adapterLogin = new AdapterLogin(getActivity(),voitureList,username,currentLength,2);
if (voitureList.size()>0)
{
listView.setAdapter(adapterLogin);
((BaseAdapter)listView.getAdapter()).notifyDataSetChanged();
}
else
{
empty.setVisibility(View.VISIBLE);
}
// Inflate the layout for this fragment
return x;
}
Any help would be greatly appreciated.
Thanks to Paul answer the idea was to add the notifyDataSetInvalidated in my UpdateView() Method in my adapter and it works just fine and my fragments are refreshing correctly now :
void notifyDataSetInvalidated ()
the method Notifies the attached observers that the underlying data is no longer valid or available. Once invoked this adapter is no longer valid and should not report further data set changes.
refer link :
notifyDataSetInvalidated

Updating adapter with AsyncTaskLoader in a regular (support) Fragment not updating ListView

I'm having trouble using the AsyncTaskLoader callbacks to update an adapter in a regular Fragment. I'm using the fragment support library, version 19.1.0.
In my onLoadFinished() callback I simply do an mAdapter.addAll(data). I used the debugger to verify that the callback is called and that all of the data is added to the adapter. The problem is that the list view simply won't update.
I've already tried notifyDataSetChanged() and invalidateViews() - no effect.
All examples or tutorials I've seen so far use a ListFragment or ListActivity without a custom layout; I've tried this and it works fine. In particular, I've tried the sample program from Android Design Patterns loader tutorial. Unfortunately, I can't use ListFragment because I'm using the StickyListHeaders library (but even trying this with a regular ListView doesn't work).
I get the same results when modifying the above sample program to use a Fragment instead of ListFragment by removing the ListFragment-specific method calls and inflating a custom view. The relevant code boils down to this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAdapter = new AppListAdapter(getActivity());
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.list_layout, container, false);
ListView listView = (ListView) v.findViewById(android.R.id.list);
listView.setAdapter(mAdapter);
return v;
}
#Override
public void onLoadFinished(Loader<List<AppEntry>> loader, List<AppEntry> data) {
mAdapter.setData(data);
}
As I said before, the adapter gets updated but the list view simply won't redraw, even if you add in notifyDataSetChanged and call invalidateViews on the listView. I'm finding it hard to figure out what's going wrong here.
Turns out that the problem was initializing the adapter in onActivityCreated, as it's called after onCreateView - so setAdapter was being passed a null value (and it doesn't complain about that). This wasn't a problem in the ListFragment and ListActivity implementations I'd looked at as you can use their setListAdapter method to associate the adapter with the list view, without keeping your own explicit reference to it. A silly mistake :\
I've run into similar problems before. The root of mine seemed to be not calling notifyDataSetChanged from the ui thread. Your problem may be similar, try:
yourContext.runOnUiThread(new Runnable() {
public void run() {
mAdapter.notifyDataSetChanged();
}
});
And let me know if it works for you.

How do I update ListView in another Fragment?

I have an Activity which holds a ViewPager with 2 Fragments. One fragment is for adding items to ListView and another fragment is holding the ListView.
I've been trying for almost 3 days now without any positive results. How do I update the other fragment's ListView from the first fragment?
I'm trying to call the method that updates ListView from the Activity that holds ViewPager but it doesn't work.
Calling the method from ViewPager activity :
#Override
public void onPageSelected(int position) {
library.populateListView(getApplicationContext());
aBar.setSelectedNavigationItem(position);
}
This is the populateListView method:
public void populateListView(Context context){
CustomListViewAdapter customAdapter = new CustomListViewAdapter(getDatabaseArrayList(context), getActivity());
if (lView != null)
{
lView.setAdapter(customAdapter);
}
customAdapter.notifyDataSetChanged();
}
However this doesn't work because the lView variable (ListView) is null because the fragment isn't shown at the moment when this is being called.
I am assuming that function populateListView() is a function of the Fragment containing the ListView. You are calling populateListView() on every call to onPageSelected. Should you not check what is the position that is being selected. Anyway the populateListView() method should be a public method of the Fragment containing ListView. And You Can Instantiate The Fragment from the Viewpager adapter in the Activity and than call this method. In That way the listView should not be null.
#Override
public void onPageSelected(int position) {
ListViewFragment frag=(ListViewFragment)adapter.instantiateItem(viewPager, 1);
//here adapter is the ViewPager Adapter and you must supply the viewpager that contains
//the fragments and also the position of the fragment to instantiate.
//For example 0 or 1 etc.
frag.populateListView(getApplicationContext());
aBar.setSelectedNavigationItem(position);
}
Understand Fragments
Please see this link. I have gone in great detail explaining the concept of fragments.
Pay particular attention to the definition of rootview:
public void onActivityCreared(Bundle savedInstanceState){
super.onActivityCreated(savedInstanceState);
// Do stuff on creation. This is usually where you add the bulk of your code. Like clickListners
// You can define this object as any element in any of your xml's
View rootview = inflater.inflate(R.layout.xml_the_fragment_uses container,false);
rootview.findViewById(R.id.your_id).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Do something
}
});
}
In the above case I defined a button for an on click listener, but you can just as easily define a ListView along with its appropriate methods.
Alternate Solution
A second method could be using getView or getActivity (check the communicating with activity section).
For example:
ListView listView = (ListView) getView().findViewById(R.id.your_listView_id);
OR (more likely solution for your problem)
View listView = getActivity().findViewById(R.id.list);
Please read this post for additional information.
Good Luck.
To do this safely, you have to keep your listview data in a higher level Parent-Activity not the fragments. Make your MainActivityclass singleton class by making the constructor private and create a getInstance method that return the only initialized instance of your `MainActivity.
This will allow you to keep your data instance safe from being re-initialized or lost. Then, in onResume of your fragment re-set the data (get it from the MainActivity) to your listview adapter and call notifyDataSetChanged() method from the adapter instance.
This will do the trick.

When is populated the listview associated to a ListFragment

I have this code inside a ListFragment:
TextView tv = (TextView) this.getListView().getChildAt(0);
tv.setBackgroundColor(getResources().getColor(R.color.White));
tv.setTextColor(getResources().getColor(R.color.OtherColor));
I wanted write this code onActivityCreated, but tv is null.
If I write this code inside onListItemClick, it works perfectly.
Is it imposible what I want?
code:
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String[] values = new String[] { getResources().getString(R.string.menu_partida),
getResources().getString(R.string.menu_acciones),
getResources().getString(R.string.menu_resultado) };
ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), R.layout.list_item_menu, values);
setListAdapter(adapter);
}
Views are only draw after all of the "creation" callbacks have executed, there is no callback for this event. However you can post() a Runnable to the UI Handler and achieve the same thing:
getListView().post(new Runnable() {
public void run() {
TextView tv = (TextView) this.getListView().getChildAt(0);
tv.setBackgroundColor(getResources().getColor(R.color.White));
tv.setTextColor(getResources().getColor(R.color.OtherColor));
}
}
But really, this change won't do what you expect since the row layouts are recycled in a ListView. (You will see eradict behavior while scrolling.) You should create a custom Adapter to change the layout for the row at position 0 only. You might get away with the Runnable since you only have three rows, but the best solution is to extend Adapter.

Retaining list in list fragment on orientation change

I have an app using fragments, all of which are contained in a single activity. The activity starts with a fragment containing a menu of buttons, all of which cause various listfragments to replace the original button/menu fragment.
My problem is that upon an orientation change, if the activity is displaying one of the listviews, it goes away and the button menu returns. I understand why this is happening... the activity is destroyed and re-created, but not how to work around it and maintain the list view/current fragment through the orientation change.
I've found setRetainInstance and the example of use here, but I can't figure out how to apply it to my situation with the button menu or the possibility that the fragment I want to retain could be one of several different ones.
Below is code simplified to show the main activity and one of the listfragments.
Any pointers in what to add where to make it so that the list fragment will be retained would be greatly appreciated.
Activity
public class Main extends FragmentActivity {
private MainMenuFragment menu;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
menu = new MainMenuFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.pane, menu).commit();
}
}
ListFragment
public class ItemListFragment extends ListFragment {
private TextView header;
private TextView empty;
private Button add;
public static Cursor itemCursor;
private GroceryDB mDbHelper;
public static long mRowId;
public static CheckCursorAdapter lists;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.common_list, container, false);
header = (TextView) v.findViewById(R.id.header);
empty = (TextView) v.findViewById(android.R.id.empty);
header.setText(R.string.header_item);
empty.setText(R.string.empty_items);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mRowId=0;
mDbHelper = new GroceryDB(getActivity());
mDbHelper.open();
itemCursor = mDbHelper.fetchAllItems();
getActivity().startManagingCursor(itemCursor);
String[] from = new String[] { GroceryDB.ITEM_NAME };
int[] to = new int[] { R.id.ListItem };
lists = new CheckCursorAdapter(getActivity(),
R.layout.listlayout_itemlist, itemCursor, from, to);
setListAdapter(lists);
}
}
how to work around it and maintain the list view/current fragment through the orientation change
You are blindly replacing the fragment every time onCreate() is called. Instead, only add/replace the fragment if savedInstanceState() is null. If it is not null, you are coming back from a configuration change, and your existing fragments will be recreated (or, if they were retained, they are already there).
setRetainInstance(true) means that the fragment itself will be retained across configuration changes, instead of being destroyed/recreated like the activity is. However, it will still be called with onCreateView(). In your code, that means that your data members of ItemListFragment would stick around, but you would still need to call setListAdapter() even if you do not requery the database.
I know that this has been resolved a long time ago, but for the sake of people searching for a solution who have as much issues as I've (repeatedly) had with retaining lists during an orientation change I would like to add that you could also use a custom class which holds the list of data for your listadapter.
This way it keeps the data when recreating the activity (and listfragment) and you can just test to see if it has any data in your oncreate. If the list == null or the list.size < 0 you proceed as usual and get the data whatever way you normally get it. Otherwise you just set your listadapter with the data it already has.
To me this is a lot easier, and seeing as Eclipse automatically creates a similar DummyContent class for your data when creating an android master/detail flow project it basically only requires a change of the oncreate of your listfragment.

Categories

Resources