FragmentPagerAdapter - Create dynamic content for each fragment - android

I have implement FragmentPagerAdapter in my app but it show only a same list of items for each fragment whenever i swipe. I am using SherlockFragmentActivity and i want to show different non static pages for each fragment whenever i swipe to next or previous fragment in fragment pager.
How can i do so ?
Have i listed a list of contacts without any title of the current fragment so that i could know that this is my contacts fragment in my fragment using this code
public class ContactsFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
// If non-null, this is the current filter the user has provided.
String mCurFilter;
public static Fragment newInstance(Context context){
ContactsFragment contactFragment = new ContactsFragment();
return contactFragment;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Give some text to display if there is no data. In a real
// application this would come from a resource.
// setEmptyText("No phone numbers");
// Create an empty adapter we will use to display the loaded data.
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_1, null,
new String[] {ContactsContract.Contacts.DISPLAY_NAME},
new int[] { android.R.id.text1}, 0);
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(true);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
#Override public void onListItemClick(ListView l, View v, int position, long id) {
// Insert desired behavior here.
Log.i("FragmentComplexList", "Item clicked: " + id);
}
// These are the Contacts rows that we will retrieve.
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader, so we don't care about the ID.
// First, pick the base URI to use depending on whether we are
// currently filtering.
Uri baseUri;
if (mCurFilter != null) {
baseUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI,
Uri.encode(mCurFilter));
} else {
baseUri = ContactsContract.Contacts.CONTENT_URI;
}
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
String select = "((" + ContactsContract.Contacts.DISPLAY_NAME + " NOTNULL) AND ("
+ ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ ContactsContract.Contacts.DISPLAY_NAME + " != '' ))";
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
mAdapter.swapCursor(data);
// The list should now be shown.
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
}
But I want to show tile above the contact list. For this i put two more methods in my fragment class which i have listed below
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_pager_list, container, false);
View tv = v.findViewById(R.id.text);
((TextView)tv).setText("Contacts");
return v;
}
But when i run my app " Your app stopped unexpetedly" this popup mesage is come.
Without these methods my app is working fine but without any title of fragment. Whats wrong with it?

hi you can achieve this using view pager here the exmple
you can use this in your one.xml layout
<ListView android:id="#+id/List" android:background="#00000000"
android:scrollbars="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollingCache="false"
android:fastScrollEnabled="true"
android:cacheColorHint="#color/white"
/>

Related

Android using SQLite cursor to display next item or previous item

A common Android application feature is to swipe on each detail item to get to the next item or previous item.
The database cursor contains a list of items which are displayed in the onCreate of a ListActivity:
if (cursor.moveToFirst()) {
listThings.setAdapter(new ResourceCursorAdapter(this, R.layout.my_simple_expandable_list_item_2, cursor) {
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView tvFirst = (TextView)view.findViewById(android.R.id.text1);
TextView tvSecond = (TextView)view.findViewById(android.R.id.text2);
tvFirst.setText(cursor.getString(1) + " - " + getPctString(cursor.getString(2)));
tvSecond.setText(cursor.getString(3));
}
});
} else {
....
That works fine. The built-in layout resource R.layout.my_simple_expandable_list_item_2 tells the adapter to display each item in the cursor in a single text view. On click, I'm able to show the details of the item in the follow-on activity:
AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> listView, View v, int position, long id) {
Intent intent = new Intent(ThingListActivity.this, ThingActivity.class);
intent.putExtra(FollowOnActivity.EXTRA_ID, (int) id);
startActivity(intent);
}
};
Once in FollowOnActivity I can lookup the details and populate the view. I can also listen for and react to swipes.
Problem: I don't have access to what the next and previous items in the list are. So far, I've not come-up with what I consider a clean solution. Since this is a common requirement, there's probably a nice pattern for this. I'd like to know what that is.
I was able to get this screen slide example working, but the list in that example is fixed at five items, and those items are text in xml files instead of database items. I created ThingSlideActivity based on their ScreenSlidePagerActivity, ThingSlidePageAdapter based on their ScreenSlidePageAdapter and ThingSlideFragment based on their ScreenSlidePageFragment. But I don't know how to wire that up to the list view that I'm coming from. It might have a big list, and I'm trying not to pull details on all of them.
I'm sitting in a list view that's been populated with a cursor (the first block of code at the top of this question). The user clicks on a random one in the list and onListItemClick runs. What should it do to enable swiping left and right to see previous and next items?
You ran a query and got a Cursor for your ListActivity. You attached the Cursor to a CursorAdapter which is showing your list.
If the user selects the third item (Item 2), then in your OnItemClickListener, the position parameter would be 2.
So what if you passed the position (2) to your follow-on activity, ran the same query there and started with cursor row 2? With the cursor, you would know previous, next... you'd have data for everything in the list!
The way to show large detail views and swipe through them horizontally left and right is to use a widget called a ViewPager. ViewPager is driven by a PagerAdapter, which has some similarities but is definitely not the same as a ListAdapter.
What you want to do is create a PagerAdapter that has your Cursor so when you create a page, you can give it the data from the Cursor. When the adapter is asked for page 3, you create a detail view, read the third record from the cursor and put that data in the detail view.
It's really that simple. The ResourceCursorAdapter is doing this under the covers. When the adapter is asked for the view for the third item, a view is created/recycled, the cursor is positioned on the third record, and finally your bindView method is called to put the data in the view.
Here's a rough sample of a PagerAdapter:
public class CursorPagerAdapter extends PagerAdapter {
/** Note that this class does not handle closing the cursor. */
private Cursor mCursor;
public CursorPagerAdapter(Cursor mCursor) {
this.mCursor = mCursor;
}
#Override
public int getCount() {
return mCursor == null ? 0 : mCursor.getCount();
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
mCursor.moveToPosition(position);
String data1 = mCursor.getString(1);
String data2 = mCursor.getString(2);
String data3 = mCursor.getString(3);
View view = LayoutInflater.from(container.getContext()).inflate(R.layout.detail_view, container, false);
// TODO fill in the view with the cursor data
container.addView(view);
return view;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
ViewPager is a tricky little bugger, but as an Android developer you will need it sooner or later so it's good to start learning how to work with them now. I recommend you dive in and check out any ViewPager tutorials you can get your hands on.
This is what ended-up working. It uses the pattern found in screen-slide example from developer.android.com/training, with one difference: in ThingSlideActivity.getItem(), instead of running ThingSlideFragment.onCreate(pos), I used ThingSlideFragment.newInstance(pos). Also, I added static Cursor getCursor() which made available the original Cursor that populated the ListActivity in the first place. This allowed me to translate from the position within the list to the database key. If there are any faults with this pattern, please advise.
The initial activity This activity has a list from the database and a cursor left open until the list is destroyed :
public class ThingListActivity extends ListActivity {
private SQLiteDatabase db;
private static Cursor cursor;
static Cursor getCursor() {
return cursor;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ListView listThings = getListView();
int position = getIntent().getIntExtra("POSITION", 0);
try {
SQLiteOpenHelper tableDatabaseHelper = new TableDatabaseHelper(this);
db = tableDatabaseHelper.getReadableDatabase();
cursor = db.query("TABLE", pullFields, selectionFields, selectionArgs, null, null, null); // you define your own query
if (cursor.moveToFirst()) {
listThings.setAdapter(new ResourceCursorAdapter(this, R.layout.my_simple_expandable_list_item_2, cursor) { //built-in layout
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView tvFirst = (TextView)view.findViewById(android.R.id.text1);
TextView tvSecond = (TextView)view.findViewById(android.R.id.text2);
tvFirst.setText(cursor.getString(1) + " - " + getPctString(cursor.getString(2)));
tvSecond.setText(cursor.getString(3));
}
});
} else {
Toast toast = Toast.makeText(this, "The list was empty.", Toast.LENGTH_SHORT);
toast.show();
}
} catch (SQLiteException e) {
Toast toast = Toast.makeText(this, "Database Unavailable", Toast.LENGTH_SHORT);
toast.show();
} finally {
//Not closing cursor. Will do in onDestroy()
}
}
#Override
public void onDestroy(){
super.onDestroy();
if (cursor != null) cursor.close();
if (db != null) db.close();
}
#Override
protected void onListItemClick(ListView listView, View view, int position, long id) {
Intent intent = new Intent(ThingListActivity.this, ThingSlideActivity.class);
intent.putExtra(ThingSlideActivity.EXTRA_POSITION, (int) position);
startActivity(intent);
}
}
The follow-on FragmentActivity. This activity has an inner class ThingSlidePageAdapter. Notice setCurrentItem, which places you in the right spot within the list. :
public class ThingSlideActivity extends FragmentActivity{
public static final String EXTRA_POSITION = "extra_position";
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_slide);
ViewPager mPager = (ViewPager)findViewById(R.id.pager);
PagerAdapter mPagerAdapter = new ThingSlidePageAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
mPager.setCurrentItem((Integer)getIntent().getExtras().get(EXTRA_POSITION));
}
private static class ThingSlidePageAdapter extends FragmentStatePagerAdapter {
int count;
public ThingSlidePageAdapter(FragmentManager fm){
super(fm);
this.count = ThingListActivity.getCursor().getCount();
}
#Override
public int getCount() {
return this.count;
}
#Override
public Fragment getItem(int position) {
return ThingSlideFragment.newInstance(position); // onCreate() doesn't work well.
}
}
}
**The Fragment we are paging through. This is where we use the Cursor from the original ListView in order to get the database key (_id). Then a fresh query is executed, pulling details for only for one item. But under the covers, the previous and next items are also pulled.
public class ThingSlideFragment extends Fragment {
private static final String ARG_POSITION = "position";
public static ThingSlideFragment create(int position) {
ThingSlideFragment fragment = new ThingSlideFragment();
Bundle args = new Bundle();
args.putInt(ARG_POSITION, position);
fragment.setArguments(args);
return fragment;
}
public static ThingSlideFragment newInstance(int position) {
ThingSlideFragment fragment = new ThingSlideFragment();
Bundle args = new Bundle();
args.putInt(ARG_POSITION, position);
fragment.setArguments(args);
return fragment;
}
public ThingSlideFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.activity_thing, container, false);
TextView tv = (TextView)rootView.findViewById(R.id.thingname);
Cursor mCursor = ThingListActivity.getCursor();
if (mCursor != null) {
mCursor.moveToPosition(getArguments().getInt(ARG_POSITION));
int id = Integer.parseInt(mCursor.getString(0));
populateView(id, rootView);
}
return rootView;
}
private void populateView(int id, View rootView) {
Cursor cursor = null;
SQLiteDatabase db = null;
try {
SQLiteOpenHelper tableDatabaseHelper = new TableDatabaseHelper(this.getContext()) ;
db = tableDatabaseHelper.getReadableDatabase();
cursor = db.query("TABLE", new String[] {"NAME", "DESCRIPTION", "DETAIL1", "DETAIL2", "DETAIL3", "DETAIL4"}, "_id = ?", new String[] {Integer.toString(id)}, null, null, null);
//Move to first record in the cursor (should be just one since our query used database key "CREATE TABLE TABLE (_id INTEGER PRIMARY KEY AUTOINCREMENT, ...."
if (cursor.moveToFirst()) {
// Get thing details from the cursor
String nameText = cursor.getString(0);
String descriptionText = cursor.getString(1);
// ........ continue with other fields
// Populate TextView items
((TextView)rootView.findViewById(R.id.thingname)).setText(nameText);
((TextView)rootView.findViewById(R.id.description)).setText(descriptionText);
// ........ continue with other fields
}
} catch (SQLiteException e) {
Toast toast = Toast.makeText(this.getContext(), "Database unavailable. "+ e.getMessage(), Toast.LENGTH_LONG) ;
} finally {
try {cursor.close();} catch (Throwable t) {}
try {db.close();} catch (Throwable t) {}
}
}
}
And, left out of many of the examples here, the contents of the supporting xml files!
<!-- R.layout.activity_screen_slide.xml containing R.id.pager -->
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- R.layout.activity_thing.xml containing R.id.thingname and R.id.description -->
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:id="#+id/thingRelativeLayout"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context="com.someones.package.ThingActivity"
tools:showIn="#layout/activity_thing">
<TextView
android:id="#+id/thingname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:paddingTop="40dp"
android:textSize="40dp"
android:gravity="center"
tools:text="Name Of Thing"
/>
<TextView
android:id="#+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:textSize="20dp"
android:layout_below="#id/thingname"
android:paddingTop="10dp"
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris et magna ut erat elementum cursus in quis ipsum. Nam faucibus ultrices eros, vel tempor leo semper sit amet."
/>
</RelativeLayout>
</ScrollView>
I hope this works for you and hope a lot of people are able to find it and benefit from it, because I spent a couple of days fiddling around with this until I got it working to my satisfaction. Possibly an easy one for the more highly experienced here, but helpful for those at a certain level of experience.

Why do contacts repeat in listview?

I was following an example off of the android site. I am new to android development. The problem I am having is that my contacts repeat over and over, about 6 times. Can anyone figure out why? I feel it may have to do with my imports as they were not included with the example but I am not certain. Also note that I did not create an xml file for the listview under res.
Thanks,
ListViewLoader.java
package com.example.contactlist;
import android.app.ListActivity;
import android.app.LoaderManager;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
//from http://developer.android.com/guide/topics/ui/layout/listview.html
public class ListViewLoader extends ListActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
// This is the Adapter being used to display the list's data
SimpleCursorAdapter mAdapter;
// These are the Contacts rows that we will retrieve
static final String[] PROJECTION = new String[] {
ContactsContract.Data._ID, ContactsContract.Data.DISPLAY_NAME };
// This is the select criteria
static final String SELECTION = "((" + ContactsContract.Data.DISPLAY_NAME
+ " NOTNULL) AND (" + ContactsContract.Data.DISPLAY_NAME
+ " != '' ))";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// For the cursor adapter, specify which columns go into which views
String[] fromColumns = { ContactsContract.Data.DISPLAY_NAME };
int[] toViews = { android.R.id.text1 }; // The TextView in
// simple_list_item_1
// Create an empty adapter we will use to display the loaded data.
// We pass null for the cursor, then update it in onLoadFinished()
mAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1, null, fromColumns,
toViews, 0);
setListAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
// Called when a new Loader needs to be created
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
return new CursorLoader(this, ContactsContract.Data.CONTENT_URI,
PROJECTION, SELECTION, null, null);
}
// Called when a previously created loader has finished loading
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
mAdapter.swapCursor(data);
}
// Called when a previously created loader is reset, making the data
// unavailable
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Do something when a list item is clicked
}
}
I've figured out the solution. I needed to query the Contacts table instead of the Data table. Apparently the Data table has duplicates. I've pasted a portion of my updated code.
public class ListViewLoader extends ListActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
// This is the Adapter being used to display the list's data
SimpleCursorAdapter mAdapter;
// These are the Contacts rows that we will retrieve
static final String[] PROJECTION = new String[] {
ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME };
// This is the select criteria
static final String SELECTION = "((" + ContactsContract.Contacts.DISPLAY_NAME
+ " NOTNULL) AND (" + ContactsContract.Contacts.DISPLAY_NAME
+ " != '' ))";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// For the cursor adapter, specify which columns go into which views
String[] fromColumns = { ContactsContract.Contacts.DISPLAY_NAME };
int[] toViews = { android.R.id.text1 }; // The TextView in
// simple_list_item_1
// Create an empty adapter we will use to display the loaded data.
// We pass null for the cursor, then update it in onLoadFinished()
mAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1, null, fromColumns,
toViews, 0);
setListAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
System.out.println("oncreate (Bundle)");
}
// Called when a new Loader needs to be created
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
System.out.println("oncreateloader");
System.out.println(PROJECTION);
System.out.println(SELECTION);
return new CursorLoader(this, ContactsContract.Contacts.CONTENT_URI,
PROJECTION, SELECTION, null, ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
Try changing
mAdapter.swapCursor(data)
to
mAdapter.changeCursor(cursor)
and
mAdapter.swapCursor(null)
to
mAdapter.changeCursor(null)

Navigation drawer SimpleCursorAdapter refresh

I'm working on an app which has a navigation drawer which shows a list of options taken from an SQLite table, for which I'm using a SimpleCursorAdapter as follows:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
mDrawerListView = (ListView) inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
selectItem(position);
}
});
mCursorAdapter = getList();
mDrawerListView.setAdapter(mCursorAdapter);
mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
return mDrawerListView;
}
getList() returns a SimpleCursorAdapter, as follows:
private SimpleCursorAdapter getList()
{
Uri uri = Uri.parse("content://" + MyContentProvider.AUTHORITY + "/searches");
Cursor cursor = getActivity().getContentResolver().query(uri,
new String[]
{
SearchTable.COLUMN_ID,
SearchTable.COLUMN_SEARCH_ID,
SearchTable.COLUMN_FULL,
SearchTable.COLUMN_TYPE,
SearchTable.COLUMN_TEXT
},
null, null, null);
if (cursor == null)
{
Log.i(TAG, "FRC! Cursor is null in NavigationDrawerFragment!");
Toast.makeText(getActivity(), getString(R.string.database_error), Toast.LENGTH_SHORT).show();
}
// Defines a list of columns to retrieve from the Cursor and load into an output row
String[] mWordListColumns =
{
SearchTable.COLUMN_TEXT,
SearchTable.COLUMN_TYPE
};
// Defines a list of View IDs that will receive the Cursor columns for each row
int[] mWordListItems = { R.id.search_full, R.id.search_type};
// layout for each of the articles in the sidebar
int layout = R.layout.search_title;
// Creates a new SimpleCursorAdapter to bind to the navigation drawer
mCursorAdapter = new SimpleCursorAdapter(
getActivity(),
layout,
cursor,
mWordListColumns,
mWordListItems,
0);
return mCursorAdapter;
}
Unfortunately, when the user refreshes the list of searches there's no change in what is shown in the navigation drawer unless the app is closed, swiped away from the task switcher, and re-launched. My content provider is notifying the app of changes in the tables and I'm watching for them as below:
class MyObserver extends ContentObserver
{
public MyObserver(Handler handler)
{
super(handler);
}
#Override
public void onChange(boolean selfChange)
{
this.onChange(selfChange, null);
}
#Override
public void onChange(boolean selfChange, Uri uri)
{
mCursorAdapter.notifyDataSetChanged();
mDrawerListView.invalidate();
Log.i(TAG,"Cursor dataset changed!");
}
}
I see the log messages for a changed dataset, so that code is actually being called. The fragment's onCreate method contains this:
Uri searchUri = Uri.parse("content://" + MyContentProvider.AUTHORITY + "/searches");
observer = new MyObserver(new Handler());
getActivity().getContentResolver().registerContentObserver(searchUri, true, observer);
What am I missing here? Or, have I misunderstood how notifyDataSetChanged() is supposed to work? As a workaround I was considering destroying and recreating the fragment, but since onChange() gets called several times for multiple inserts/deletions then this might be rather a wasteful hack.
Thanks for any suggestions.
Eventually I managed to find a way to do this, which I don't think is very good but it seems to function adequately for the moment. Every other attempt to invalidate views or notify of changed datasets had no effect.
#Override
public void onPrepareOptionsMenu(Menu menu) // called when drawer opens
{
if (mDrawerLayout != null && isDrawerOpen())
{
mCursorAdapter = getList(); // create a new cursor with the latest data (see above)
mCursorAdapter.notifyDataSetChanged(); // do I even need this?
ListView listView = (ListView) getActivity().findViewById(R.id.navigation_drawer); // bind the new cursor to the listview
listView.setAdapter(mCursorAdapter);
listView.invalidateViews();
...
}
}
Please let me know if you can think of a better way!

getLoadManager().initLoader(0, null, this) does not acceptable

API level is 8
I am sure that I use the support package
i get the getLoadManager().initLoader(0, null, this) does not acceptable
my code is as below:
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
public class ListViewLoader extends ListActivity implements LoaderManager.LoaderCallbacks<Cursor>
{
// This is the Adapter being used to display the list's data
SimpleCursorAdapter mAdapter;
// These are the Contacts rows that we will retrieve
static final String[] PROJECTION = new String[] { ContactsContract.Data._ID, ContactsContract.Data.DISPLAY_NAME };
// This is the select criteria
static final String SELECTION = "((" + ContactsContract.Data.DISPLAY_NAME + " NOTNULL) AND (" + ContactsContract.Data.DISPLAY_NAME + " != '' ))";
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Create a progress bar to display while the list loads
ProgressBar progressBar = new ProgressBar(this);
progressBar.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
progressBar.setIndeterminate(true);
getListView().setEmptyView(progressBar);
// Must add the progress bar to the root of the layout
ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
root.addView(progressBar);
// For the cursor adapter, specify which columns go into which views
String[] fromColumns = { ContactsContract.Data.DISPLAY_NAME };
int[] toViews = { android.R.id.text1 }; // The TextView in simple_list_item_1
// Create an empty adapter we will use to display the loaded data.
// We pass null for the cursor, then update it in onLoadFinished()
mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, null, fromColumns, toViews);
setListAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoadManager().initLoader(0, null, this);
}
// Called when a new Loader needs to be created
public Loader<Cursor> onCreateLoader(int id, Bundle args)
{
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
return new CursorLoader(this, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, null, null);
}
// Called when a previously created loader has finished loading
public void onLoadFinished(Loader<Cursor> loader, Cursor data)
{
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
mAdapter.swapCursor(data);
}
// Called when a previously created loader is reset, making the data unavailable
public void onLoaderReset(Loader<Cursor> loader)
{
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id)
{
// Do something when a list item is clicked
}
}

Use of setListAdapter

In my application 4 fragments are attached to one activity class. In my activity class i have set the root content view using this
setContentView(R.layout.fragment_pager);
my four fragments are in seperate java files.
In one of my fragment i am displaying a list of contact for this i used
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_1, null,
new String[] {ContactsContract.Contacts.DISPLAY_NAME},
new int[] { android.R.id.text1}, 0);
setListAdapter(mAdapter);
setListShown(true);
I want to know that what is the use of setListAdapter in my case and where it put list of content given by SimpleCursorAdapter class? and how can i set the title of my fragment.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:drawable/gallery_thumb">
<TextView android:id="#+id/text"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="#string/hello_world"/>
<!-- The frame layout is here since we will be showing either
the empty view or the list view. -->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" >
<!-- Here is the list. Since we are using a ListActivity, we
have to call it "#android:id/list" so ListActivity will
find it -->
<ListView android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="false"/>
<!-- Here is the view to show if the list is emtpy -->
<TextView android:id="#android:id/empty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="No items."/>
</FrameLayout>
</LinearLayout>
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_1, null,
new String[] {ContactsContract.Contacts.DISPLAY_NAME},
new int[] { android.R.id.text1}, 0);
//setListAdapter(mAdapter);
// setListShown(true);
// getLoaderManager().initLoader(0, null, this);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_pager_list, container, false);
View tv = v.findViewById(R.id.text);
((TextView)tv).setText("Contacts");
return v;
}
My Cursor display data when i use this method and removes two methods onCreate and onCreateView
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_1, null,
new String[] {ContactsContract.Contacts.DISPLAY_NAME},
new int[] { android.R.id.text1}, 0);
setListAdapter(mAdapter);
setListShown(true);
getLoaderManager().initLoader(0, null, this);
}
but when i use those three methods together then my application stops unexpectedly. What can be the error when i use these three method together?
package com.keepintouch.android;
import android.os.Bundle;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import com.actionbarsherlock.app.SherlockListFragment;
public class ContactsFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
// If non-null, this is the current filter the user has provided.
String mCurFilter;
View lv;
// These are the Contacts rows that we will retrieve.
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
};
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
public static Fragment newInstance(Context context){
ContactsFragment contactFragment = new ContactsFragment();
return contactFragment;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_1, null,
new String[] {ContactsContract.Contacts.DISPLAY_NAME},
new int[] { android.R.id.text1}, 0);
setListAdapter(mAdapter);
setListShown(true);
getLoaderManager().initLoader(0, null, this);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Insert desired behavior here.
Log.i("FragmentComplexList", "Item clicked: " + id);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader, so we don't care about the ID.
// First, pick the base URI to use depending on whether we are
// currently filtering.
Uri baseUri;
if (mCurFilter != null) {
baseUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI,
Uri.encode(mCurFilter));
} else {
baseUri = ContactsContract.Contacts.CONTENT_URI;
}
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
String select = "((" + ContactsContract.Contacts.DISPLAY_NAME + " NOTNULL) AND ("
+ ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ ContactsContract.Contacts.DISPLAY_NAME + " != '' ))";
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
mAdapter.swapCursor(data);
// The list should now be shown.
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
}
If you are using the Listfragement setListAdapter set the Adapter in your default list comes with Listfragement..
if using action bar (android:targetSdkVersion="15")
ActionBar ab = this.getActionBar();
ab.setTitle(" ");
if not then
getActivity().setTitle(" "); // after onAttach called

Categories

Resources