IndexOutOfBoundException while reading from Cursor - android

I'm trying to use a CursorLoader but keep getting an IndexOutOfBounds error when reading from the Cursor. Relevant error lines from Logcat:
at com.codephillip.app.busticket.SelectRouteFragment.onLoadFinished(SelectRouteFragment.java:96)
at com.codephillip.app.busticket.SelectRouteFragment.onLoadFinished(SelectRouteFragment.java:28)
This is the fragment class:
public class SelectRouteFragment extends Fragment implements MaterialSpinner.OnItemSelectedListener, LoaderManager.LoaderCallbacks {
private static final String TAG = SelectRouteFragment.class.getSimpleName();
private MaterialSpinner destSpinner;
private MaterialSpinner sourceSpinner;
private Button selectButton;
private String destination;
private String source;
public SelectRouteFragment() {
}
public static SelectRouteFragment newInstance() {
return new SelectRouteFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_select_route, container, false);
destSpinner = rootView.findViewById(R.id.dest_spinner);
sourceSpinner = rootView.findViewById(R.id.source_spinner);
destSpinner.setOnItemSelectedListener(this);
sourceSpinner.setOnItemSelectedListener(this);
selectButton = rootView.findViewById(R.id.select_button);
selectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (source.equals(destination)) {
Toast.makeText(getContext(), "Choose a different Destination", Toast.LENGTH_SHORT).show();
} else {
Intent intent = new Intent(getContext(), BookActivity.class);
intent.putExtra(Utils.SOURCE, source);
intent.putExtra(Utils.DESTINATION, destination);
getActivity().startActivity(intent);
}
}
});
return rootView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(2, null, this);
}
#Override
public Loader onCreateLoader(int id, Bundle args) {
return new CursorLoader(getContext(), LocationsColumns.CONTENT_URI, null, null, null, null);
}
#Override
public void onLoadFinished(Loader loader, Cursor data) {
Log.d(TAG, "onLoadFinished: started");
LocationsCursor cursor = new LocationsCursor(data);
List locations = new ArrayList<>();
if (cursor.moveToFirst()) {
do {
locations.add(cursor.getName());
} while (cursor.moveToNext());
}
// Set default route values
source = locations.get(0);
destination = locations.get(0);
ArrayAdapter dataAdapter = new ArrayAdapter(getContext(), android.R.layout.simple_expandable_list_item_1, locations);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
sourceSpinner.setAdapter(dataAdapter);
destSpinner.setAdapter(dataAdapter);
}
#Override
public void onLoaderReset(Loader loader) {
}
#Override
public void onItemSelected(MaterialSpinner view, int position, long id, Object itemObject) {
Snackbar.make(view, "Clicked " + itemObject.toString(), Snackbar.LENGTH_LONG).show();
String item = itemObject.toString();
Log.d(TAG, "onItemSelected: " + item);
if (view.getId() == destSpinner.getId()) {
Log.d(TAG, "onItemSelected: clicked dest");
destination = item;
} else {
Log.d(TAG, "onItemSelected: clicked source");
source = item;
}
}
}
Any help understanding the issue would be greatly appreciated.

I guess the issue is happening here:
source = locations.get(0);
destination = locations.get(0);
If cursor is empty, locations will also be empty and then, locations.get(0) will throw an exception.
You should check if location is not empty.
if(locations.size() > 0) {
...
}

Related

Updating code to save the state of the clicked items

I'm a new developer to android development. I'll like the code below (for querying and displaying images media collection) whose images checkboxes are checked when clicked, to be updated to include onsaveinstancestate to save the state of the clicked/checked items.
public class PhotosFragment extends Fragment {
ArrayList<ImageModel > imageList;
RecyclerView imageRecyclerView;
ImageAdapter imageAdapter;
View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_photos, container, false);
runtimePermission();
return view;
}
private void runtimePermission() {
Dexter.withContext(getContext()).withPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(new PermissionListener() {
#Override
public void onPermissionGranted(PermissionGrantedResponse permissionGrantedResponse) {
init();
getAllImages();
setImageList();
}
#Override
public void onPermissionDenied(PermissionDeniedResponse permissionDeniedResponse) {
Toast.makeText(getContext(), "Permission is Required!", Toast.LENGTH_SHORT).show();
}
#Override
public void onPermissionRationaleShouldBeShown(PermissionRequest permissionRequest, PermissionToken permissionToken) {
permissionToken.continuePermissionRequest();
}
}).check();
}
public void init() {
imageRecyclerView = (RecyclerView) view.findViewById(R.id.photos_recycler);
imageList = new ArrayList<>();
}
public void setImageList() {
imageRecyclerView.setLayoutManager((new GridLayoutManager(getContext(), 4)));
imageAdapter = new ImageAdapter(getContext(), imageList);
imageRecyclerView.setAdapter(imageAdapter);
/* Here `isSelected` is a boolean variable. It is true when item is checked and false when not checked. When false, the if condition evaluates to true and the `selectImage()` method is called, otherwise the `unSelectImage()` is called */
imageAdapter.setOnItemClickListener(new ImageAdapter.OnItemClickListener() {
#Override
public void onItemViewClick(int position, View v){
try {
if (!imageList.get(position).isSelected) {
selectImage(position);
} else {
unSelectImage(position);
}
} catch (ArrayIndexOutOfBoundsException ed) {
ed.printStackTrace();
}
}
});
};
public void selectImage(int position) {
imageList.get(position).setSelected(true);
imageAdapter.notifyDataSetChanged();
}
public void unSelectImage(int position) {
imageList.get(position).setSelected(false);
imageAdapter.notifyDataSetChanged();
}
}
Querying the mediastore for images collection
public void getAllImages() {
Uri imageCollection;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
imageCollection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
} else {
imageCollection = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
}
String[] projection = new String[] {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.Media.SIZE
};
String sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC";
Cursor cursor = getActivity().getContentResolver().query(imageCollection , projection, null, null, sortOrder);
int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
int nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME);
int dateColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_ADDED);
int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE);
while (cursor.moveToNext()) {
long id = cursor.getLong(idColumn);
String name = cursor.getString(nameColumn);
int duration = cursor.getInt(dateColumn);
int size = cursor.getInt(sizeColumn);
Uri uriImage = Uri.withAppendedPath(imageCollection, ""+ id);
ImageModel imageModel = new ImageModel();
imageModel.setImage(uriImage);
imageList.add(imageModel);
}
cursor.close();
}

How to show spinner selection in gridview?

i am having spinner with country name and below i am showing flags according to country spinner.here i want to show flag according to spinner selection and not all..how can i show that in gridView?
HERE IS MY CODE:
public class FanciersFragment extends Fragment {
private View rootView;
private Spinner spFindCountry;
private RecyclerView rvFanciers;
private ArrayList<CountryDetail> countryDetailArray;
private LinearLayout llContainer;
private String countryCode;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_fanciers, container, false);
iitializeView();
return rootView;
}
private void iitializeView() {
spFindCountry = (Spinner) rootView.findViewById(R.id.sp_country_find);
rvFanciers = (RecyclerView) rootView.findViewById(R.id.rv_fanc_items);
llContainer = (LinearLayout) rootView.findViewById(R.id.ll_fanciers_container);
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity() , 3);
rvFanciers.setHasFixedSize(true);
rvFanciers.setLayoutManager(gridLayoutManager);
getCounties();
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle("FanciersResponse");
}
private void getCounties() {
if(Utility.isNetworkConnected(getActivity())) {
final Call<Countries> resp = Utility.getApiService().getContries();
resp.enqueue(new Callback<Countries>() {
#Override
public void onResponse(Call<Countries> call, Response<Countries> response) {
if (response.code() == 200) {
Countries countries = (Countries) response.body();
if (countries != null)
if (countries.getStatus() != null)
if (countries.getStatus().equals("OK")) {
countryDetailArray = (ArrayList<CountryDetail>) countries.getCountryDetails();
if(countryDetailArray != null)
populateCountrySpinner(countryDetailArray);
pupulateFanciers();
} else {
Utility.ShowSnackBar(countries.getStatusMessage() , llContainer);
}
} else {
Utility.ShowSnackBar("Network Error" , llContainer);
}
}
#Override
public void onFailure(Call<Countries> call, Throwable t) {
Utility.ShowSnackBar("No Response" , llContainer);
}
});
}
else {
Utility.ShowSnackBar(getResources().getString(R.string.no_internet), llContainer);
}
}
private void pupulateFanciers() {
Fanciers rcAdapter = new Fanciers(getActivity(), countryDetailArray , new Fanciers.OnItemClickListener() {
#Override
public void onItemClick(CountryDetail item) {
if(item != null){
Bundle b = new Bundle();
b.putSerializable(Constants.COUNTRY_DETAILS , item);
Intent intent = new Intent(getActivity() , CountryBaseFanciers.class);
intent.putExtra(Constants.BUNDLE , b);
startActivity(intent);
}
}
});
rvFanciers.setAdapter(rcAdapter);
}
private void populateCountrySpinner(final ArrayList<CountryDetail> countryDetailList) {
ArrayList<String> countryList = new ArrayList<>();
if(countryDetailList != null){
for(CountryDetail countryDetail: countryDetailList ){
countryList.add(countryDetail.getCountryName());
}
}
/*adapterCountry = new ArrayAdapter<String>(getActivity(), R.layout.spinner_layout, R.id.tv_country_name, countryList);
spCountry.setAdapter(adapterCountry);*/
HintSpinner<String> hintSpinner = new HintSpinner<>(
spFindCountry,
// Default layout - You don't need to pass in any layout id, just your hint text and
// your list data
new HintAdapter<>(getActivity(), getResources().getString(R.string.find_country), countryList),
new HintSpinner.Callback<String>() {
#Override
public void onItemSelected(int position, String itemAtPosition) {
// Here you handle the on item selected event (this skips the hint selected event)
countryCode = countryDetailList.get(position).getCountryCode();
}
});
hintSpinner.init();
}
}
I am getting all flags in gridview but i want on selection of spinner..kindly help
Instead of using GridView, try extending an ArrayAdapter class to use images, setting it in a ListView and implementing a filter based on country name. This should be fine if you want only one flag to be displayed at a time.

Add data in SQLite Database using Fragment in Android

I am trying to Add data in SQLite Database using Fragment, but it's not Adding in Database and there is no error while running app.
My code in AddRoom Fragment :
public class AddRoom extends Fragment implements View.OnClickListener {
DatabaseHotel myHotel;
Button bt_addRoom;
EditText ed_roomtype, ed_roomPrice, ed_noOfRoom;
View view;
Context context;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
myHotel = new DatabaseHotel(getActivity());
view = inflater.inflate(R.layout.addroom, container, false);
bt_addRoom = (Button)view.findViewById(R.id.bt_addroom);
ed_roomtype = (EditText)view.findViewById(R.id.ed_roomtype);
ed_roomPrice = (EditText)view.findViewById(R.id.ed_roomprice);
ed_noOfRoom = (EditText)view.findViewById(R.id.ed_noofrooms);
return view;
}
#Override
public void onClick(View v) {
bt_addRoom.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addRoom();
}
});
}
private void addRoom(){
String roomType = ed_roomtype.getText().toString();
int roomPrice = Integer.parseInt(ed_roomPrice.getText().toString());
int noOfRoom = Integer.parseInt(ed_noOfRoom.getText().toString());
boolean inserted = myHotel.addRoom(roomType, roomPrice, noOfRoom);
if (inserted){
Message.message(context, "Room Added Succeccfully");
}else {
Message.message(context, "Room Not Added!!");
}
}
}
In My Database class : addRoom() method code:
public boolean addRoom(String roomType, int roomPrice, int numberOfRoom){
SQLiteDatabase db = mydb.getReadableDatabase();
ContentValues cv = new ContentValues();
cv.put(Database.ROOM_TYPE, roomType);
cv.put(Database.ROOM_PRICE, roomPrice);
cv.put(Database.NUMBER_OF_ROOMS, numberOfRoom);
try {
long result = db.insert(Database.ROOM_TABLE,null, cv);
if (result == -1){
return false;
}else {
return true;
}
}catch (SQLException e){
Message.message(context, e+"");
}
return true;
}
I think you missed
bt_addRoom.setOnClickListener(this);
in onCreateView(..). You should register OnClickListener first.
What MD said... but you might also want mydb.getWriteableDatabase(); and not getReadableDatabase() as well

Is it possible to send an object from a fragment to another fragment?

The object that I want to send from a fragment to another fragment is "post".
The DemandFragment consist of a listview which consist of items which are post objects.
I need to send the selected item from the listview, in this case postArrayList.get(position), to SelectedPostFragment.
I've tried with bundle but this is not working...
Does someone know how to fix this?
DemandFragment:
public class DemandFragment extends Fragment {
ListView lv;
ArrayAdapter adapter;
ArrayList<Post> postArrayList;
private EditText editSearch;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_demand, container, false);
if(rootView != null){
lv = (ListView) rootView.findViewById(R.id.listDemand);
editSearch = (EditText) rootView.findViewById(R.id.search_post);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// clicked on item show post
Post selectedPost = postArrayList.get(position);
Bundle bundle = new Bundle();
bundle.putParcelable("data", (Parcelable) selectedPost);
FragmentManager fm = getActivity().getFragmentManager();
Fragment fragment = new rang.afterflight.fragments.SelectedPostFragment();
fragment.setArguments(bundle);
fm.beginTransaction().replace(R.id.content_main, fragment).commit();
}
});
}
searchPost();
return rootView;
}
public void searchPost(){
editSearch.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
adapter.getFilter().filter(s);
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
ParseQuery<ParseObject> query = ParseQuery.getQuery("Post");
postArrayList = new ArrayList<Post>();
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> postList, ParseException e) {
if (e == null) {
for (ParseObject object : postList) {
Post newPost = new Post();
newPost.setAirportParse((String) object.get("airport"));
newPost.setDateParse((String) object.get("date"));
newPost.setTimeParse((String) object.get("time"));
newPost.setPersonsParse((String) object.get("persons"));
newPost.setAddressParse((String) object.get("address"));
newPost.setFlightnrParse((String) object.get("address"));
newPost.setUsername((String) object.get("username"));
newPost.setImageFile((ParseFile) object.get("profilepic"));
postArrayList.add(newPost);
}
adapter = new ListViewAdapter(getActivity(), R.layout.item_cardview, postArrayList);
lv.setAdapter(adapter);
}
}
});
}
}
SelectedPostFragment:
public class SelectedPostFragment extends Fragment {
TextView airportPost, datePost, timePost, personsPost, addressPost,
flightnrPost, postedbyPost, contactPost;
ImageView iv;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_selectedpost, container, false);
airportPost = (TextView) rootView.findViewById(R.id.airport_post);
datePost = (TextView) rootView.findViewById(R.id.date_post);
timePost = (TextView) rootView.findViewById(R.id.time_post);
personsPost = (TextView) rootView.findViewById(R.id.persons_post);
addressPost = (TextView) rootView.findViewById(R.id.address_post);
flightnrPost = (TextView) rootView.findViewById(R.id.flightnr_post);
postedbyPost = (TextView) rootView.findViewById(R.id.postedby_post);
contactPost = (TextView) rootView.findViewById(R.id.contact_post);
Post selectedPost = getArguments().getParcelable("object");
String s = (String) selectedPost.get("airport");
Log.d("AIRPORT NAME", s);
return rootView;
}
}
Post:
#ParseClassName("Post")
public class Post extends ParseObject implements Serializable {
public Post(){
super();
}
public String getId(){
return getString("objectId");
}
public void setId(String id){
put("objectId", id);
}
//////////
public String getUsername(){
return getString("username");
}
public void setUsername(String username){
put("username", username);
}
public String getAirportParse(){
return getString("airport");
}
public void setAirportParse(String airport){
put("airport", airport);
}
//////////
public String getDateParse(){
return getString("date");
}
public void setDateParse(String date){
put("date", date);
}
//////////
public String getTimeParse(){
return getString("time");
}
public void setTimeParse(String time){
put("time", time);
}
//////////
public String getPersonsParse(){
return getString("persons");
}
public void setPersonsParse(String persons){
put("persons", persons);
}
//////////
public String getAddressParse(){
return getString("address");
}
public void setAddressParse(String address){
put("address", address);
}
public String getFlightnrParse(){
return getString("flightnr");
}
public void setFlightnrParse(String flightnr){
put("flightnr", flightnr);
}
public Bitmap getImageFile(){
Bitmap bmp = null;
ParseFile image = getParseFile("profilepic");
if(image != null){
try {
byte[] data = image.getData();
bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
} catch (ParseException e) {
e.printStackTrace();
}
}
return bmp;
}
public void setImageFile(ParseFile file) {
if (file != null) {
put("profilepic", file);
}
}
}
I believe your Post class needs to implement Parcelable as well to pass it in a bundle between fragments with putParcelable().
Check out: Parcelable.
This is also a great example.
Basic implementation:
public class Post extends ParseObject implements Serializable, Parcelable {
...
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(getId());
out.writeSring(getUsername());
...
}
public static final Parcelable.Creator<Post> CREATOR
= new Parcelable.Creator<Post>() {
public Post createFromParcel(Parcel in) {
return new Post(in);
}
public Post[] newArray(int size) {
return new Post[size];
}
};
private Post(Parcel in) {
// Items must be read in the order they were written.
setId(in.readString());
setUsername(in.readString());
...
}
}
Try that on for size, hope it helps.
Use the activity as a transporting mechanism.
Create an interface for the activity to implement, which the activity passes to the fragment upon instantiation. Whenever you want to transfer data, call the callback for the interface. Co-ordinate with the activity which fragment it needs to interact with and then post your data in another callback that will be linked to the fragment.
If all of this is too complex, then just use Otto and enjoy sending events everywhere without having to worry about detaching/attaching interfaces/listeners upon configuration change.

Accessing a Loader created in one fragment from another fragment

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.

Categories

Resources