I have a listFragment and when an item of the list is clicked it starts a new activity. When back button is pressed, the list is shown again. Im using cursor Loaders so, I want to know if is there an easy way to refresh the cursor loader when back button is pressed. This is because the new activity changes the contents of the list.
Edit:
public class ListWordFragment extends SherlockListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
private static String TAG = ListWordFragment.class.getSimpleName();
private CursorLoader cursorLoader;
// Loader
private static final int URL_LOADER = 0;
private SimpleCursorAdapter adapter;
public static LoaderManager mLoaderManager;
// ActionBar
private AutoCompleteTextView autoCompView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_list_words, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ListView list = getListView();
String[] from = new String[] { Word.NAME, Word.TYPE, Word.TRANSLATE };
int[] to = new int[] { R.id.textView_word, R.id.textView_type,
R.id.textView_translate };
adapter = new ListWordAdapter(getSherlockActivity(),
R.layout.row_list_words, null, from, to, 0);
setListAdapter(adapter);
mLoaderManager = getLoaderManager();
mLoaderManager.initLoader(URL_LOADER, null, this);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
fillRow(l, id, position, false);
}
private void fillRow(ListView l, long ide, int position, boolean firstCall) {
Cursor cursor = getActivity().getContentResolver().query(
Uri.withAppendedPath(WordListProvider.WORDS_CONTENT_URI,
String.valueOf(ide)), null, null, null, null);
if(cursor.moveToFirst()){
String id = cursor.getString(cursor.getColumnIndex(Word.ID));
String name = cursor.getString(cursor.getColumnIndex(Word.NAME));
String type = cursor.getString(cursor.getColumnIndex(Word.TYPE));
String translate = cursor.getString(cursor
.getColumnIndex(Word.TRANSLATE));
String example = cursor.getString(cursor.getColumnIndex(Word.EXAMPLE));
String note = cursor.getString(cursor.getColumnIndex(Word.NOTE));
// Master/Detail
if ((getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE)
&& (getResources().getString(R.string.selected_configuration)
.equals(Constants.CONFIGURATION_LARGE))) {
WordDetailFragment frag = (WordDetailFragment) getFragmentManager()
.findFragmentById(R.id.word_detail_fragment);
if (frag != null) {
frag.setId(id);
frag.setName(name);
frag.setType(type);
frag.setTranslate(translate);
frag.setExample(example);
frag.setNote(note);
}
} else if (firstCall) {
// Do nothing
} else {
Intent i = new Intent(getActivity().getApplicationContext(),
WordDetailActivity.class);
i.putExtra(Word.ID, id);
i.putExtra(Word.NAME, name);
i.putExtra(Word.TYPE, type);
i.putExtra(Word.TRANSLATE, translate);
i.putExtra(Word.EXAMPLE, example);
i.putExtra(Word.NOTE, note);
startActivity(i);
}
cursor.close();
}
}
public void onWordSaved() {
getLoaderManager().restartLoader(URL_LOADER, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int loaderID, Bundle bundle) {
String[] projection = { Word.ID, Word.NAME, Word.TYPE, Word.TRANSLATE,
Word.EXAMPLE, Word.NOTE };
/* Takes action based on the ID of the Loader that's being created */
switch (loaderID) {
case URL_LOADER:
// Returns a new CursorLoader
cursorLoader = new CursorLoader(getSherlockActivity(), // Parent
// activity
// context
WordListProvider.WORDS_CONTENT_URI, // Table to query
projection, // Projection to return
null, // No selection clause
null, // No selection arguments
null // Default sort order
);
return cursorLoader;
default:
// An invalid id was passed in
return null;
}
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
}
Try adding to your Fragment class:
#Override
protected void onResume()
{
super.onResume();
getLoaderManager().restartLoader(URL_LOADER, null, this);
}
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
To clear up your efficiency concern: When you call the initial init, it will start, but restartLoader on the same ID will automatically cancel that previous request and start a new one. So it won't get executed fully twice on activity start up.
More info in Google Loader Dev Doco.
Related
I have created an ExpandableListAdapter by extending SimpleCursorTreeAdapter. The cursors are managed by loaders. When the list is displayed to user , I start a background service to fetch latest data from server. If the server returns new data I add it to DB and notify the children cursors. The cursors gets requeried and the list updates. At this point if the user has scrolled down in the list, the list scrolls up to top. This is very annoying. I have gone through the entire API for *TreeAdapters and do not see any method to prevent it. This must be a very common problem. How can I fix it ?
Try this code:
public class GroupsAdapter extends SimpleCursorTreeAdapter {
private final String TAG = getClass().getSimpleName().toString();
private final FragmentActivity mActivity;
private final ContactsFragment mFragment;
private static final String[] CONTACTS_PROJECTION = new String[] {
ContactsContract.Users._ID, ContactsContract.Users.USER_ID,
ContactsContract.Users.NAME, ContactsContract.Users.STATUS_TYPE,
ContactsContract.Users.STATUS_MESSAGE,
ContactsContract.Users.HAS_ALERT };
// Note that the constructor does not take a Cursor. This is done to avoid
// querying the database on the main thread.
public GroupsAdapter(final Context context, final ContactsFragment glf,
final int groupLayout, final int childLayout,
final String[] groupFrom, final int[] groupTo,
final String[] childrenFrom, final int[] childrenTo) {
super(context, null, groupLayout, groupFrom, groupTo, childLayout,
childrenFrom, childrenTo);
mActivity = (FragmentActivity) context;
mFragment = glf;
}
#Override
protected Cursor getChildrenCursor(final Cursor groupCursor) {
final String id = groupCursor.getString(groupCursor
.getColumnIndex(ContactsContract.Groups.GROUP_ID));
final CursorLoader cursorLoader = new CursorLoader(mActivity,
ContactsContract.Users.CONTENT_URI, CONTACTS_PROJECTION, "("
+ ContactsContract.UserGroupColumns.GROUP_ID + "=?)",
new String[] { id }, null);
Cursor childCursor = null;
try {
childCursor = cursorLoader.loadInBackground();
childCursor.moveToFirst();
} catch (final Exception e) {
Log.e(TAG, e.getMessage());
}
return childCursor;
}
}
and the fragment:
public class ContactsFragment extends Fragment implements
LoaderCallbacks<Cursor> {
private static final String[] GROUPS_PROJECTION = new String[] {
ContactsContract.Groups._ID, ContactsContract.Groups.NAME,
ContactsContract.Groups.GROUP_ID,
ContactsContract.Groups.USERS_COUNT };
private static final String TAG = "ContactsFragment";
ExpandableListView listView;
GroupsAdapter mAdapter;
public ContactsFragment() {
// Required empty public constructor
}
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public View onCreateView(final LayoutInflater inflater,
final ViewGroup container, final Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_contacts, container, false);
}
#Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
inflater.inflate(R.menu.contacts_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView = (ExpandableListView) getView().findViewById(
android.R.id.list);
// listView.setEmptyView();
// Set up our adapter
mAdapter = new GroupsAdapter(getActivity(), R.layout.group,
R.layout.user, new String[] { ContactsContract.Groups.NAME,
ContactsContract.Groups.USERS_COUNT }, // Name
// for group layouts
new int[] { R.id.group, R.id.count }, new String[] {
ContactsContract.Users.NAME,
ContactsContract.Users.STATUS_MESSAGE }, // Name
// for child layouts
new int[] { R.id.user_name, R.id.status_message });
listView.setAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
final Loader<Cursor> loader = getLoaderManager().getLoader(-1);
if (loader != null && !loader.isReset()) {
getLoaderManager().restartLoader(-1, null, this);
} else {
getLoaderManager().initLoader(-1, null, this);
}
getActivity().getContentResolver().registerContentObserver(
ContactsContract.Users.CONTENT_URI, false,
new ContentObserver(null) {
#Override
public void onChange(final boolean selfChange) {
Log.w(TAG, "Change");
}
});
}
#Override
public Loader<Cursor> onCreateLoader(final int id, final Bundle args) {
// This is called when a new Loader needs to be created.
// group cursor
final CursorLoader cl = new CursorLoader(getActivity(),
ContactsContract.Groups.CONTENT_URI, GROUPS_PROJECTION, null,
null, null);
return cl;
}
#Override
public void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) {
// Swap the new cursor in.
final int id = loader.getId();
if (id == -1) {
mAdapter.setGroupCursor(cursor);
}
}
#Override
public void onLoaderReset(final Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// is about to be closed.
final int id = loader.getId();
if (id != -1) {
// child cursor
try {
mAdapter.setChildrenCursor(id, null);
} catch (final NullPointerException e) {
Log.w("TAG", "Adapter expired, try again on the next query: "
+ e.getMessage());
}
} else {
mAdapter.setGroupCursor(null);
}
}
}
My SimpleCursorAdapter does not display any data from the ArrayList that I pass into it! Why is this and how do I fix it?
Here's my ListFragment, you can see the SimpleCursorAdapter being used in the onViewCreated() method.
public class CourseListFragment extends SherlockListFragment {
SQLiteDatabase db;
DbHelper dbHelper;
private static String courseName;
ArrayList<String> courseItems;
SimpleCursorAdapter adapter;
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
*/
private static final String STATE_ACTIVATED_POSITION = "activated_position";
/**
* The fragment's current callback object, which is notified of list item
* clicks.
*/
private Callbacks mCallbacks = sDummyCallbacks;
/**
* The current activated item position. Only used on tablets.
*/
private int mActivatedPosition = ListView.INVALID_POSITION;
/**
* A callback interface that all activities containing this fragment must
* implement. This mechanism allows activities to be notified of item
* selections.
*/
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(String id);
}
/**
* A dummy implementation of the {#link Callbacks} interface that does
* nothing. Used only when this fragment is not attached to an activity.
*/
private static Callbacks sDummyCallbacks = new Callbacks() {
#Override
public void onItemSelected(String id) {
}
};
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public CourseListFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Restore the previously serialized activated item position.
if (savedInstanceState != null
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState
.getInt(STATE_ACTIVATED_POSITION));
}
dbHelper = new DbHelper(getActivity());
db = dbHelper.getWritableDatabase();
courseItems = new ArrayList<String>();
String[] projection = new String[] {DbHelper.COURSE_NAME, DbHelper.C_ID};
String[] from = new String[] { DbHelper.COURSE_NAME };
Cursor cursor = db.query(DbHelper.TABLE_NAME, projection, null, null, null, null, null);
// Fields on the UI to which we map
int[] to = new int[] { getListView().getId() };
int layout = (Build.VERSION.SDK_INT >= 11) ? android.R.layout.simple_list_item_activated_1
: android.R.layout.simple_list_item_1;
adapter = new SimpleCursorAdapter(getActivity(), layout, cursor, from, to, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(adapter);
// The problem starts here
SwipeDismissListViewTouchListener touchListener = new SwipeDismissListViewTouchListener(
getListView(),
new SwipeDismissListViewTouchListener.OnDismissCallback() {
public void onDismiss(ListView listView,
int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
removeCourse(position);
adapter.notifyDataSetChanged();
}
}
});
getListView().setOnTouchListener(touchListener);
getListView().setOnScrollListener(touchListener.makeScrollListener());
adapter.notifyDataSetChanged();
}
#Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
String[] projection = { DbHelper.COURSE_NAME };
Cursor c = db.query(DbHelper.TABLE_NAME, projection, null, null, null,
null, null);
c.moveToFirst();
while (c.moveToNext()) {
courseName = c.getString(c.getColumnIndex(DbHelper.COURSE_NAME));
courseItems.add(courseName);
}
c.close();
adapter.notifyDataSetChanged();
}
public void addCourse() {
String[] projection = { DbHelper.COURSE_NAME };
Cursor c = db.query(DbHelper.TABLE_NAME, projection, null, null, null,
null, null);
c.moveToLast();
courseName = c.getString(c.getColumnIndex(DbHelper.COURSE_NAME));
courseItems.add(courseName);
c.close();
adapter.notifyDataSetChanged();
}
public void removeCourse(int position) {
String[] projection = { DbHelper.C_ID, DbHelper.COURSE_NAME };
Cursor c = db.query(DbHelper.TABLE_NAME, projection, null, null, null,
null, null);
c.moveToPosition(position);
db.delete(DbHelper.TABLE_NAME, DbHelper.C_ID + "=" + position,
null);
c.close();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Activities containing this fragment must implement its callbacks.
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException(
"Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
#Override
public void onDetach() {
super.onDetach();
// Reset the active callbacks interface to the dummy implementation.
mCallbacks = sDummyCallbacks;
}
#Override
public void onListItemClick(ListView listView, View view, int position,
long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(null);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mActivatedPosition != ListView.INVALID_POSITION) {
// Serialize and persist the activated item position.
outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
}
}
/**
* Turns on activate-on-click mode. When this mode is on, list items will be
* given the 'activated' state when touched.
*/
public void setActivateOnItemClick(boolean activateOnItemClick) {
// When setting CHOICE_MODE_SINGLE, ListView will automatically
// give items the 'activated' state when touched.
getListView().setChoiceMode(
activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
public void setActivatedPosition(int position) {
if (position == ListView.INVALID_POSITION) {
getListView().setItemChecked(mActivatedPosition, false);
} else {
getListView().setItemChecked(position, true);
}
mActivatedPosition = position;
}
}
Thanks! Much appreciated!
*Edit: Updated code using SimpleCursorAdapter*
public class CourseListFragment extends SherlockListFragment {
SQLiteDatabase db;
DbHelper dbHelper;
private static String courseName;
ArrayList<String> courseItems;
SimpleCursorAdapter adapter;
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
*/
private static final String STATE_ACTIVATED_POSITION = "activated_position";
/**
* The fragment's current callback object, which is notified of list item
* clicks.
*/
private Callbacks mCallbacks = sDummyCallbacks;
/**
* The current activated item position. Only used on tablets.
*/
private int mActivatedPosition = ListView.INVALID_POSITION;
/**
* A callback interface that all activities containing this fragment must
* implement. This mechanism allows activities to be notified of item
* selections.
*/
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(String id);
}
/**
* A dummy implementation of the {#link Callbacks} interface that does
* nothing. Used only when this fragment is not attached to an activity.
*/
private static Callbacks sDummyCallbacks = new Callbacks() {
#Override
public void onItemSelected(String id) {
}
};
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public CourseListFragment() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Restore the previously serialized activated item position.
if (savedInstanceState != null
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState
.getInt(STATE_ACTIVATED_POSITION));
}
dbHelper = new DbHelper(getActivity());
db = dbHelper.getWritableDatabase();
courseItems = new ArrayList<String>();
final String[] projection = new String[] {DbHelper.COURSE_NAME, DbHelper.C_ID};
Cursor cursor = db.query(DbHelper.TABLE_NAME, projection, null, null, null, null, null);
// Fields on the UI to which we map
final String[] from = new String[] { DbHelper.COURSE_NAME };
final int[] to = new int[] { R.id.internalEmpty };
final int layout = (Build.VERSION.SDK_INT >= 11) ? android.R.layout.simple_list_item_activated_1
: android.R.layout.simple_list_item_1;
adapter = new SimpleCursorAdapter(getActivity(), layout, cursor, from, to, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(adapter);
// The problem starts here
SwipeDismissListViewTouchListener touchListener = new SwipeDismissListViewTouchListener(
getListView(),
new SwipeDismissListViewTouchListener.OnDismissCallback() {
public void onDismiss(ListView listView,
int[] reverseSortedPositions) {
for (int position : reverseSortedPositions) {
removeCourse(position);
Cursor c = db.query(DbHelper.TABLE_NAME, projection, null, null, null, null, null);
adapter = new SimpleCursorAdapter(getActivity(), layout, c, from, to, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
setListAdapter(adapter);
}
}
});
getListView().setOnTouchListener(touchListener);
getListView().setOnScrollListener(touchListener.makeScrollListener());
adapter.notifyDataSetChanged();
}
#Override
public void onViewStateRestored(Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
String[] projection = { DbHelper.COURSE_NAME };
Cursor c = db.query(DbHelper.TABLE_NAME, projection, null, null, null,
null, null);
c.moveToFirst();
while (c.moveToNext()) {
courseName = c.getString(c.getColumnIndex(DbHelper.COURSE_NAME));
courseItems.add(courseName);
}
c.close();
adapter.notifyDataSetChanged();
}
public void addCourse() {
String[] projection = { DbHelper.COURSE_NAME };
Cursor c = db.query(DbHelper.TABLE_NAME, projection, null, null, null,
null, null);
c.moveToLast();
courseName = c.getString(c.getColumnIndex(DbHelper.COURSE_NAME));
courseItems.add(courseName);
c.close();
adapter.notifyDataSetChanged();
}
public void removeCourse(int position) {
String[] projection = { DbHelper.C_ID, DbHelper.COURSE_NAME };
Cursor c = db.query(DbHelper.TABLE_NAME, projection, null, null, null,
null, null);
c.moveToPosition(position);
db.delete(DbHelper.TABLE_NAME, DbHelper.C_ID + "=" + position,
null);
c.close();
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Activities containing this fragment must implement its callbacks.
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException(
"Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
#Override
public void onDetach() {
super.onDetach();
// Reset the active callbacks interface to the dummy implementation.
mCallbacks = sDummyCallbacks;
}
#Override
public void onListItemClick(ListView listView, View view, int position,
long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
mCallbacks.onItemSelected(null);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mActivatedPosition != ListView.INVALID_POSITION) {
// Serialize and persist the activated item position.
outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
}
}
/**
* Turns on activate-on-click mode. When this mode is on, list items will be
* given the 'activated' state when touched.
*/
public void setActivateOnItemClick(boolean activateOnItemClick) {
// When setting CHOICE_MODE_SINGLE, ListView will automatically
// give items the 'activated' state when touched.
getListView().setChoiceMode(
activateOnItemClick ? ListView.CHOICE_MODE_SINGLE
: ListView.CHOICE_MODE_NONE);
}
public void setActivatedPosition(int position) {
if (position == ListView.INVALID_POSITION) {
getListView().setItemChecked(mActivatedPosition, false);
} else {
getListView().setItemChecked(position, true);
}
mActivatedPosition = position;
}
}
int[] to = new int[] { getListView().getId() };
that line is wrong. and i cant imagine what's happening behind the scenes. the int[] to is supposed to be for example
int[] to = new int[] {R.id.text1};
the id of the textView in the int layout parameter that you passed to the SimpleCursorAdapter, that you want the columns of String[] from to be written to. i suggest you find out the textView id contents of:
int layout = (Build.VERSION.SDK_INT >= 11) ? android.R.layout.simple_list_item_activated_1
: android.R.layout.simple_list_item_1;
Then make a conditional statement just like that.
EDIT use the following line
int[] to = new int[] {android.R.id.text1};
I have an app with a fairly standard fragment layout. An expandable listview fragment on the left and a panel on the right that is used for different things depending on what the user chooses to do with the list on the left (displaying data, adding new data, etc).
I'm using the LoaderManager (first time using loaders) with CommonWare's loaderex library as I have no need or desire to create a Content Provider for my database just so I can use a standard CursorLoader. This setup works great for displaying my list.
The issue I am having is when I use the second fragment to add data to the database. I cannot figure out how to trigger a re-load of the list in the first fragment. For the life of me I cannot figure out how to grab the loader from the first fragment in the second so that it will be aware that the data needs to be pulled again, nor can I seem to figure how to manually trigger a re-load.
As this is my first attempt at using Loaders, if I'm doing something improperly I'd be happy to be (gently) re-directed down a better path.
Fragment 1
public class StudentListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
private TAOpenHelper mDbHelper = null;
private MyExpandableListAdapter mAdapter = null;
private ExpandableListView lv = null;
private Button addStudentButton;
public static long mRowId = 0;
public SQLiteCursorLoader studentLoader=null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.leftlistfragment_entry, container,
false);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
addStudentButton = (Button) getActivity().findViewById(R.id.AddButton);
addStudentButton.setText(getResources().getString(
R.string.button_add_student));
addStudentButton.setOnClickListener(addStudentButtonHandler);
lv = (ExpandableListView) getListView();
mDbHelper = TAOpenHelper.getInstance(getActivity());
fillData();
getLoaderManager().getLoader(-1);
if (studentLoader != null && !studentLoader.isReset()) {
getLoaderManager().restartLoader(-1, null, this);
} else {
getLoaderManager().initLoader(-1, null, this);
}
}
private void fillData() {
mAdapter = new MyExpandableListAdapter(getActivity(), this,
R.layout.listlayout_exp_double_group,
R.layout.listlayout_exp_double_child,
new String[] { TeacherAidDB.STUDENT_FIRST,
TeacherAidDB.STUDENT_LAST }, new int[] {
R.id.ListItem1, R.id.ListItem2 }, new String[] {
TeacherAidDB.CLASS_NAME, TeacherAidDB.CLASS_LEVEL },
new int[] { R.id.ListItem1, R.id.ListItem2 });
lv.setAdapter(mAdapter);
}
public class MyExpandableListAdapter extends SimpleCursorTreeAdapter {
protected final SparseIntArray mGroupMap;
private StudentListFragment mFragment;
public MyExpandableListAdapter(Context context,
StudentListFragment clf, int groupLayout, int childLayout,
String[] groupFrom, int[] groupTo, String[] childrenFrom,
int[] childrenTo) {
super(context, null, groupLayout, groupFrom, groupTo, childLayout,
childrenFrom, childrenTo);
mFragment = clf;
mGroupMap = new SparseIntArray();
}
#Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
int groupPos = groupCursor.getPosition();
int groupId = groupCursor.getInt(groupCursor
.getColumnIndex(TeacherAidDB.CLASS_ROWID));
mGroupMap.put(groupId, groupPos);
Loader<Cursor> loader = getActivity().getLoaderManager().getLoader(
groupId);
if (loader != null && !loader.isReset()) {
getActivity().getLoaderManager().restartLoader(groupId, null,
mFragment);
} else {
getActivity().getLoaderManager().initLoader(groupId, null,
mFragment);
}
return null;
}
public SparseIntArray getGroupMap() {
return mGroupMap;
}
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (id != -1) { // Child Cursor
studentLoader = new SQLiteCursorLoader(getActivity(), mDbHelper,
TeacherAidDB.STUDENT_LIST_CLASS_QUERY + id, null);
} else { // Group Cursor
studentLoader = new SQLiteCursorLoader(getActivity(), mDbHelper,
TeacherAidDB.STUDENT_LIST_QUERY, null);
}
return studentLoader;
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
int id = loader.getId();
if (id != -1) { // Child cursor
if (!data.isClosed()) {
SparseIntArray groupMap = mAdapter.getGroupMap();
int groupPos = groupMap.get(id);
mAdapter.setChildrenCursor(groupPos, data);
}
} else { // Groups cursor
mAdapter.setGroupCursor(data);
}
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
mAdapter.changeCursor(null);
}
View.OnClickListener addStudentButtonHandler = new View.OnClickListener() {
public void onClick(View v) {
AddPerson personadd = AddPerson.newInstance(AddPerson.STUDENT, AddPerson.CREATE, mRowId);
getFragmentManager().beginTransaction()
.replace(R.id.rightpane, personadd).commit();
}
};
}
Fragment 2
public class AddPerson extends Fragment {
public static int STUDENT = 0;
public static int TEACHER = 1;
public static int CREATE = 0;
public static int EDIT = 1;
private int mRowId;
private TAOpenHelper mDbHelper;
private Cursor personedit;
private Button commit;
private Button cancel;
int who;
int what;
long rowId;
static AddPerson newInstance(int type, int action, long rowid) {
AddPerson f = new AddPerson();
Bundle args = new Bundle();
args.putInt("type", type);
args.putInt("action", action);
args.putLong("rowid", rowid);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
who = getArguments().getInt("type");
what = getArguments().getInt("action");
rowId = getArguments().getInt("rowid");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dialog_person_add, container, false);
mDbHelper = TAOpenHelper.getInstance(getActivity());
if (what == EDIT) {
if (who == STUDENT) {
// Student Edit stuff here
} else {
// Teacher Edit stuff here
}
} else {
if (who == STUDENT) {
// Student Create stuff here
} else {
// Teacher Create stuff here
}
}
// Code to gather data from user goes here
commit = (Button) v.findViewById(R.id.commitbutton);
commit.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
first = firstTxt.getText().toString();
last = lastTxt.getText().toString();
street = streetTxt.getText().toString();
city = cityTxt.getText().toString();
zip = zipTxt.getText().toString();
phone = phoneTxt.getText().toString();
email = emailTxt.getText().toString();
if (what == CREATE) {
processAdd(who);
} else {
processUpdate(who);
}
}
});
cancel = (Button) v.findViewById(R.id.cancelbutton);
cancel.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Fragment check = getFragmentManager().findFragmentById(
R.id.rightpane);
getFragmentManager().beginTransaction().remove(check).commit();
}
});
return v;
}
private void processAdd(int who) {
ContentValues initialValues = new ContentValues();
if (who == STUDENT) {
initialValues.put(TeacherAidDB.STUDENT_FIRST, first);
initialValues.put(TeacherAidDB.STUDENT_LAST, last);
initialValues.put(TeacherAidDB.STUDENT_STREET, street);
initialValues.put(TeacherAidDB.STUDENT_CITY, city);
initialValues.put(TeacherAidDB.STUDENT_STATE, state);
initialValues.put(TeacherAidDB.STUDENT_ZIP, zip);
initialValues.put(TeacherAidDB.STUDENT_PHONE, phone);
initialValues.put(TeacherAidDB.STUDENT_EMAIL, email);
initialValues.put(TeacherAidDB.STUDENT_BDAY, birthday);
// How to get studentLoader from fragment 1?
//studentLoader.insert(TeacherAidDB.STUDENT_TABLE, null, initialValues);
}
}
}
With a regular CursorLoader, this would happen automagically via the ContentObserver framework, which eventually boils down to a bunch of static data members.
With SQLiteCursorLoader, ContentObserver is not available, with the closest simulacrum being to route your CRUD operations through the Loader so it knows to reload the Cursor. And that is really only designed for use within a single activity.
So, as Luksprog suggested, your best option is to delegate CRUD work to the containing activity.
If these fragments might be hosted by disparate activities (e.g., for small/normal vs. large/xlarge screen sizes), define a common interface for handling this work, and have the fragments delegate to the interface.
My goal is to swipe lists horizontally , which are filled by public class ClientsManagerOpenHandler extends SQLiteOpenHelper.
I try to reach this goal by working with viewpager and ListFragments. If you have an other solution please tell me.
Now the problem:
If I try to call from the following PageListFragment.java, data from ClientsManagerOpenHandler the program crashes at:
dbCursorTerminAnsicht = openHandler.queryTabelle("terminansicht");
Maybe I cannot call an extended SQLiteOpenHelper within ListFragment? But how I get the data from sqlite into my lists, and when I swipe horizontally to change data...
Please help. I have tried anything, but I really need help now.
public class PageListFragment extends ListFragment implements OnClickListener,
LoaderCallbacks<Cursor> {
private Calendar cal = Calendar.getInstance();
private ClientsManagerOpenHandler openHandler;
public static final String PREFS_NAME ="MyPrefsFile";
SharedPreferences prefs;`
private Cursor dbCursorTerminAnsicht;
private Integer intVerdienst = 0;
private String queryVerdienst;
private SimpleCursorAdapter mCursorAdapter;
private ListView listViewTermine;
private final int listNr;
private final String[] fruit = { "Bananen", "Apfle", "Erdbeere",
"Kirschen", "Mangos" };
private Uri[] mMediaSource = {null, MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI};
public PageListFragment(int nr) {
this.listNr = nr;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//!!!!! after the next line the program crashes. Even I have set breakpoints at ClientsManagerOpenHandler
//I cannot see anything in the debugger (Debugger: Source not found...)
dbCursorTerminAnsicht = openHandler.queryTabelle("terminansicht");
if (listNr == 0) {
ArrayAdapter<String> openHandler = new ArrayAdapter<String>(
getActivity(), android.R.layout.simple_list_item_1, fruit);
setListAdapter(openHandler);
} else if (listNr == 1) {
mCursorAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_1, null,
new String[] { MediaStore.Audio.Artists.ARTIST },
new int[] { android.R.id.text1 }, 0);
setListAdapter(mCursorAdapter);
getLoaderManager().initLoader(0, null, this);
} else if (listNr == 2) {
openHandler = new ClientsManagerOpenHandler(getActivity());
String query = "projekte, klienten, termine WHERE termine.KLIENTID = klienten._id AND termine.PROJEKTID = projekte._id ORDER BY BEGINN ASC;";
MyDataAdapter myClientsadapter = new MyDataAdapter (
getActivity(),
R.layout.terminzeile,
// android.R.layout.two_line_list_item,
dbCursorTerminAnsicht,
new String[] { openHandler.BEGINN , openHandler.ENDE, openHandler.NACHNAME, openHandler.VORNAME, openHandler.PROJEKT, openHandler.BEZAHLT},
// fields,
// new int[] {R.id.editTextNachname, R.id.editTextVorname }
new int[] {R.id.textViewBeginn, R.id.textViewEnde, R.id.textViewNachname, R.id.textViewVorname, R.id.textViewProjekt,R.id.checkBoxBezahlt }
);
myClientsadapter.setViewBinder(new MyDataAdapter.ViewBinder() {
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if(columnIndex == 13) {
String strBeginn = cursor.getString(columnIndex);
CheckBox cb = (CheckBox) view;
int intbezahlt = cursor.getInt(13);
int index = cursor.getColumnIndex("SATZ");
Integer intSatz = cursor.getInt(index);
if (index>0) {
if (intbezahlt>0){
intVerdienst = intVerdienst + intSatz;
}
}
cb.setChecked(intbezahlt > 0);
return true;
}
String str = cursor.getString(columnIndex);
return false;
}
});
//TerminlisteRefresh("");
setListAdapter(myClientsadapter);
getLoaderManager().initLoader(0, null, this);
}
}
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
Loader<Cursor> loader = new CursorLoader(getActivity(), mMediaSource[listNr],
null, null, null, null);
return loader;
}
public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
mCursorAdapter.swapCursor(cursor);
}
public void onLoaderReset(Loader<Cursor> arg0) {
mCursorAdapter.swapCursor(null);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
}
It appears that you are trying to access openHandler before you have defined it:
dbCursorTerminAnsicht = openHandler.queryTabelle("terminansicht");
...
openHandler = new ClientsManagerOpenHandler(getActivity());
This might work better:
openHandler = new ClientsManagerOpenHandler(getActivity());
dbCursorTerminAnsicht = openHandler.queryTabelle("terminansicht");
I obviously new and have been trying to two days to figure out how to save the state of my main activity to no avail. I would appreciate any help. When I launch the ShowDetail activity and return to the main activity I have no data in the list. I have two xml files a main.xml and a item.xml file. main is just a listview and a textview. Item.xml is 3 textviews for the data in the list. Item Here is the code from my main activity:
public class main extends ListActivity {
private EventsData events;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
events = new EventsData(this);
try {
Cursor cursor = getEvents();
showEvents(cursor);
} finally {
events.close();
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState){
super.onRestoreInstanceState(savedInstanceState);
}
#Override
public void onPause(){
super.onPause();
}
#Override
public void onRestart(){
super.onRestart();
}
private static String[] FROM = { CODE, EXCERPT, _ID, };
private static String ORDER_BY = CODE + " ASC";
private Cursor getEvents() {
SQLiteDatabase db = events.getReadableDatabase();
Cursor cursor = db.query(TABLE_NAME, FROM, null, null, null, null, ORDER_BY);
startManagingCursor(cursor);
return cursor;
}
private static int[] TO = { R.id.code, R.id.excerpt, };
private void showEvents(Cursor cursor) {
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.item, cursor, FROM, TO);
setListAdapter(adapter);
}
private static String[] MIKEY = { _ID, CODE, DEFINITION };
protected void onListItemClick(ListView l, View v, int position, long id) {
Cursor cursor = ((CursorAdapter)getListAdapter()).getCursor();
cursor.getLong(2);
SQLiteDatabase db = events.getReadableDatabase();
Cursor c = db.query(TABLE_NAME, MIKEY, "_id = "+cursor.getLong(2)+"", null, null, null, null);
c.moveToFirst();
Intent in1 = new Intent();
Bundle bun = new Bundle();
bun.putLong("id", c.getLong(0));
bun.putString("code", c.getString(1));
bun.putString("definition", c.getString(2));
in1.setClass(this, ShowDetail.class);
in1.putExtras(bun);
startActivity(in1);
}
}
I'd say you need to place your general actions into onResume() instead of in onCreate().
Maybe a look at the application lifecycle helps understanding what I mean:
http://developer.android.com/reference/android/app/Activity.html