Accessing a Loader created in one fragment from another fragment - android

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.

Related

Duplicate items with SimpleCursorAdapter

I populate a DialogFragment with the items from the Cursor which I pass in the SimpleCursorAdapter.
The Problem: I get duplicated items even if in SQLite db the items aren't duplicated
Some info:
compileSdkVersion 27
buildToolsVersion "27.0.3"
I tested the problem in Android API 18 and 23
I used the android support libraries v7: 25.0.1 and 27.1.1
This is my code:
public class ServiceCodifiedResultDialog extends DialogFragment implements
DialogInterface.OnClickListener, ViewBinder, LoaderManager.LoaderCallbacks<Cursor> {
private static final String EXTRA_SERVICE_INFO = "EXTRA_SERVICE_INFO";
private static final String STATE_CODIFIED_RESULT = "STATE_CODIFIED_RESULT";
private static final String STATE_SERVICE_INFO = "STATE_SERVICE_INFO";
private static final int LOADER_SERVICE_RESULTS_ID = 0;
private int mCodifiedResult;
private ServiceInfo mServiceInfo;
private SimpleCursorAdapter mListAdapter;
private OnServiceListener mOnServiceListener;
public static ServiceCodifiedResultDialog newInstance(ServiceInfo serviceInfo) {
Bundle arguments = new Bundle(1);
arguments.putSerializable(EXTRA_SERVICE_INFO, serviceInfo);
ServiceCodifiedResultDialog fragment = new ServiceCodifiedResultDialog();
fragment.setArguments(arguments);
return fragment;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mOnServiceListener = (OnServiceListener) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mServiceInfo = (ServiceInfo) savedInstanceState.getSerializable(STATE_SERVICE_INFO);
mCodifiedResult = savedInstanceState.getInt(STATE_CODIFIED_RESULT, -1);
} else {
mServiceInfo = (ServiceInfo) getArguments().getSerializable(EXTRA_SERVICE_INFO);
mCodifiedResult = -1;
}
mListAdapter = new SimpleCursorAdapter(getActivity(), R.layout.row_dialog_service_result,
null,
new String[]{ServiceResults.COLUMN_NAME_DESCR},
new int[]{
R.id.id_codified_result_descr
}, 0);
mListAdapter.setViewBinder(this);
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
/* creat a dialog with SingleChoice List */
AlertDialog dialog = new AlertDialog.Builder(
new ContextThemeWrapper(getActivity(), R.style.DialogApptheme))
.setIcon(R.drawable.services)
.setTitle(R.string.dialog_title)
.setPositiveButton(R.string.btn_ok, this)
.setNegativeButton(R.string.btn_cancel, this)
.setSingleChoiceItems(mListAdapter, -1, this).create();
return dialog;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(LOADER_SERVICE_RESULTS_ID, null, this);
}
//continue below
This method is called several times with duplicated values and I don't know why:
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (view.getId() == R.id.id_codified_result_descr) {
TextView codifiedResultDescrTextView = (TextView) view;
String codifiedResultDescr = cursor.getString(columnIndex);
if (!cursor.isNull(columnIndex + 1)) {
codifiedResultDescr = String.format(Locale.getDefault(), "%1$s \u2013 %2$s",
cursor.getString(columnIndex + 1), codifiedResultDescr);
}
codifiedResultDescrTextView.setText(codifiedResultDescr);
return true;
}
return false;
}
Here the methods onCreate, onFinished and onReset Loader:
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
StringBuilder selection = new StringBuilder();
selection.append(ServiceResults.COLUMN_NAME);
selection.append("=").append(value);
StringBuilder sortOrder = new StringBuilder();
sortOrder.append(ServiceResults.COLUMN_NAME_DESCR).append(" ASC");
return new CursorLoader(getActivity(), ServiceResults.CONTENT_URI, new String[]{
String.format("%1$s AS %2$s", ServiceResults.COLUMN_NAME, ServiceResults._ID),
ServiceResults.COLUMN_NAME_DESCR,
ServiceResults.COLUMN_NAME_CODE
}, selection.toString(), null, sortOrder.toString());
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
int checkedPosition = -1;
int valueToCheck = mCodifiedResult == -1 && mServiceInfo.mCodifiedResult != null
? mServiceInfo.mCodifiedResult : mCodifiedResult;
while (valueToCheck >= 0 && cursor.moveToNext() && checkedPosition == -1) {
if (cursor.getInt(0) == valueToCheck) {
checkedPosition = cursor.getPosition();
}
}
mListAdapter.swapCursor(cursor);
if (checkedPosition >= 0) {
((AlertDialog) getDialog()).getListView().setItemChecked(checkedPosition, true);
}
}
#Override
public void onLoaderReset(Loader<Cursor> cursor) {
mListAdapter.swapCursor(null);
}
}
Any idea how to solve the problem?

Listview does not refresh when underlying Loader data changes

First, I'll preface my question with the fact that I'm not using a CursorLoader.
I'm pulling in data from a SQLlite database to populate a listview in a ListFragment. The initial load works well, but once the data is manipulated (i.e. an addition is made to the list), the listview NEVER refreshes to show the new data. I am implementing the Loader callbacks like so:
public class BillListingFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<Bill>> {
private billListAdapter mAdapter;
private static final int LOADER_ID = 1;
private SQLiteDatabase mDatabase;
private BillsDataSource mDataSource;
private BillsStoreDatabaseHelper mDbHelper;
/**
* The fragment argument representing the fragment type (archive or outstanding)
*/
private static final String ARG_FRAGMENT_TYPE = "fragment_type";
/**
* Returns a new instance of this fragment based on type
*/
public static BillListingFragment newInstance(String type) {
// TODO: Make the fragment type an enum
BillListingFragment fragment = new BillListingFragment();
Bundle args = new Bundle();
args.putString(ARG_FRAGMENT_TYPE, type);
fragment.setArguments(args);
return fragment;
}
public BillListingFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.bill_view_layout, container, false);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mDbHelper = new BillsStoreDatabaseHelper(getActivity());
mDatabase = mDbHelper.getWritableDatabase();
mDataSource = new BillsDataSource(mDatabase);
mAdapter = new billListAdapter(getActivity(), R.layout.bill_row_layout);
setListAdapter(mAdapter);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
#Override
public Loader<List<Bill>> onCreateLoader(int id, Bundle args) {
BillDataLoader loader = new BillDataLoader(getActivity(), mDataSource);
return loader;
}
#Override
public void onLoadFinished(Loader<List<Bill>> loader, List<Bill> data) {
for(Bill bill: data){
mAdapter.add(bill);
}
setListAdapter(mAdapter);
}
#Override
public void onLoaderReset(Loader<List<Bill>> loader) {
mAdapter.clear();
}
#Override
public void onDestroy() {
super.onDestroy();
mDbHelper.close();
mDatabase.close();
mDataSource = null;
mDbHelper = null;
mDatabase = null;
}
public void reload(){
getLoaderManager().restartLoader(LOADER_ID, null, this);
}
private class billListAdapter extends ArrayAdapter<Bill> {
Context context;
public billListAdapter(Context context, int resourceID){
super(context, resourceID);
this.context = context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getActivity().getLayoutInflater().inflate(R.layout.bill_row_layout, parent, false);
}
TextView payToField = (TextView) convertView.findViewById(R.id.nameField);
TextView dueDateField = (TextView) convertView.findViewById(R.id.overdueField);
payToField.setText(getItem(position).getPayTo());
// calculate days until due
Bill bill = getItem(position);
// TODO: Add how many days until bill in overdue field + add color
JodaTimeAndroid.init(getActivity());
DateTime dueDateDt = new DateTime(bill.getDateDue());
DateTime currentDt = new DateTime();
int daysDifference = Days.daysBetween(currentDt.toLocalDate(), dueDateDt.toLocalDate()).getDays();
// depending on what that differential looks like set text / color
if (daysDifference > 1) {
dueDateField.setText(Integer.toString(daysDifference) + " Days");
} else {
if (daysDifference == 0) {
dueDateField.setText("DUE TODAY");
} else {
if (daysDifference < 0) {
}
}
}
return convertView;
}
}
}
I have debugged my code so I know that the onLoadFinished callback is being made after the data has been manipulated. I also know that adapter contains the updated data at this point. I have tried resetting the adapter via setListAdapter(mAdatper) and every notifyDataChanged-like method I can find, but to no avail. What is going on here and how can I get the listview to update?

ExpandableListView using SimpleCursorTreeAdapter scrolls to top on update

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);
}
}
}

when back button is pressed, cursor loader should restart

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.

How to fill listviews with sqlite data, which are swiped horizontally

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");

Categories

Resources