I have a DialogFragment that I'm working on to display two spinners, side by side, one displays a list of drivers, the other a list of vehicles.
The data to populate these spinners is retrieved from a sqlite database. I am trying to use a LoaderManager to keep the spinners updated or in sync with the database tables, (drivers and vehicles).
When I add/delete/edit a record in either the drivers table or vehicles table in the database, the spinners don't get updated, the driver or vehicle remains unchanged in the spinner.
I'm not sure what I'm missing because I thought LoaderManager is supposed to keep the lists updated or in sync with the database tables automatically right?
I created a button called addDriverVehicle() which is supposed to allow the user to add another driver/vehicle in the future but for now I'm using it as a test to delete a driver to kind of simulate the database tables changing just so i can see if the spinner gets updated automatically but it's not happening. The record is being deleted but the spinner continues to show it.
public class DriverVehiclePickersDialogFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<Cursor>, OnItemSelectedListener {
public static final String ARG_LISTENER_TYPE = "listenerType";
public static final String ARG_DIALOG_TYPE = "dialogType";
public static final String ARG_TITLE_RESOURCE = "titleResource";
public static final String ARG_SET_DRIVER = "setDriver";
public static final String ARG_SET_VEHICLE = "setVehicle";
private static final int DRIVERS_LOADER = 0;
private static final int VEHICLES_LOADER = 1;
private DriverVehicleDialogListener mListener;
// These are the Adapter being used to display the driver's and vehicle's data.
SimpleCursorAdapter mDriversAdapter, mVehiclesAdapter;
// Define Dialog view
private View mView;
// Store Driver and Vehicle Selected
private long[] mDrivers, mVehicles;
// Spinners Containing Driver and Vehicle List
private Spinner driversSpinner;
private Spinner vehiclesSpinner;
private static enum ListenerType {
ACTIVITY, FRAGMENT
}
public static enum DialogType {
DRIVER_SPINNER, VEHICLE_SPINNER, DRIVER_VEHICLE_SPINNER
}
public interface DriverVehicleDialogListener {
public void onDialogPositiveClick(long[] mDrivers, long[] mVehicles);
}
public DriverVehiclePickersDialogFragment() {
// Empty Constructor
Log.d("default", "default constructor ran");
}
public static DriverVehiclePickersDialogFragment newInstance(DriverVehicleDialogListener listener, Bundle dialogSettings) {
final DriverVehiclePickersDialogFragment instance;
if (listener instanceof Activity) {
instance = createInstance(ListenerType.ACTIVITY, dialogSettings);
} else if (listener instanceof Fragment) {
instance = createInstance(ListenerType.FRAGMENT, dialogSettings);
instance.setTargetFragment((Fragment) listener, 0);
} else {
throw new IllegalArgumentException(listener.getClass() + " must be either an Activity or a Fragment");
}
return instance;
}
private static DriverVehiclePickersDialogFragment createInstance(ListenerType listenerType, Bundle dialogSettings) {
DriverVehiclePickersDialogFragment fragment = new DriverVehiclePickersDialogFragment();
if (!dialogSettings.containsKey(ARG_LISTENER_TYPE)) {
dialogSettings.putSerializable(ARG_LISTENER_TYPE, listenerType);
}
if (!dialogSettings.containsKey(ARG_DIALOG_TYPE)) {
dialogSettings.putSerializable(ARG_DIALOG_TYPE, DialogType.DRIVER_VEHICLE_SPINNER);
}
if (!dialogSettings.containsKey(ARG_TITLE_RESOURCE)) {
dialogSettings.putInt(ARG_TITLE_RESOURCE, 0);
}
fragment.setArguments(dialogSettings);
return fragment;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Find out how to get the DialogListener instance to send the callback events to
Bundle args = getArguments();
ListenerType listenerType = (ListenerType) args.getSerializable(ARG_LISTENER_TYPE);
switch (listenerType) {
case ACTIVITY: {
// Send callback events to the hosting activity
mListener = (DriverVehicleDialogListener) activity;
break;
}
case FRAGMENT: {
// Send callback events to the "target" fragment
mListener = (DriverVehicleDialogListener) getTargetFragment();
break;
}
}
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
Button btnAddDriverVehicle = (Button) mView.findViewById(R.id.addDriverVehicleButton);
btnAddDriverVehicle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DatabaseHelper1 mOpenHelper = new DatabaseHelper1(getActivity());
try {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
db.delete("drivers", " driver_number = 70", null);
} catch (SQLException e) {
}
}
});
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
Bundle args = getArguments();
int titleResource = args.getInt(ARG_TITLE_RESOURCE);
DialogType dialogType = (DialogType) args.getSerializable(ARG_DIALOG_TYPE);
if (args.containsKey(ARG_SET_DRIVER)) {
mDrivers = args.getLongArray(ARG_SET_DRIVER);
}
if (args.containsKey(ARG_SET_VEHICLE)) {
mVehicles = args.getLongArray(ARG_SET_VEHICLE);
}
mView = LayoutInflater.from(getActivity()).inflate(R.layout.driver_vehicle_dialog, null);
if ((dialogType == DialogType.DRIVER_SPINNER) || (dialogType == DialogType.DRIVER_VEHICLE_SPINNER)) {
driversSpinner = (Spinner) mView.findViewById(R.id.driversSpinner);
vehiclesSpinner = (Spinner) mView.findViewById(R.id.vehiclesSpinner);
driversSpinner.setVisibility(View.VISIBLE);
mDriversAdapter = new SimpleCursorAdapter(getActivity(), R.layout.driver_listview_row, null, new String[] { ConsoleContract.Drivers.DRIVER_NUMBER,
ConsoleContract.Drivers.DRIVER_NAME }, new int[] { R.id.driver_number, R.id.driver_name }, 0);
driversSpinner.setAdapter(mDriversAdapter);
driversSpinner.setOnItemSelectedListener(this);
}
if ((dialogType == DialogType.VEHICLE_SPINNER) || (dialogType == DialogType.DRIVER_VEHICLE_SPINNER)) {
vehiclesSpinner.setVisibility(View.VISIBLE);
mVehiclesAdapter = new SimpleCursorAdapter(getActivity(), R.layout.vehicle_listview_row, null, new String[] { ConsoleContract.Vehicles.VEHICLE_NUMBER,
ConsoleContract.Vehicles.VEHICLE_VIN }, new int[] { R.id.vehicle_number, R.id.vehicle_vin }, 0);
vehiclesSpinner.setAdapter(mVehiclesAdapter);
vehiclesSpinner.setOnItemSelectedListener(this);
}
// Prepare the loader. Either re-connect with an existing one, or start a new one.
getLoaderManager().initLoader(DRIVERS_LOADER, null, this);
getLoaderManager().initLoader(VEHICLES_LOADER, null, this);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(mView);
if (titleResource == 0) {
builder.setMessage("Select Driver and Vehicle");
} else {
builder.setMessage(getString(titleResource));
}
builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mListener.onDialogPositiveClick(mDrivers, mVehicles);
}
});
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
private static class DatabaseHelper1 extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "test.db";
private static final int DATABASE_VERSION = 1;
DatabaseHelper1(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
// These are the Contacts rows that we will retrieve.
static final String[] DRIVERS_SUMMARY_PROJECTION = new String[] { ConsoleContract.Drivers._ID, ConsoleContract.Drivers.DRIVER_ID, ConsoleContract.Drivers.DRIVER_NUMBER,
ConsoleContract.Drivers.DRIVER_NAME };
static final String[] VEHICLES_SUMMARY_PROJECTION = new String[] { ConsoleContract.Vehicles._ID, ConsoleContract.Vehicles.VEHICLE_ID, ConsoleContract.Vehicles.VEHICLE_NUMBER,
ConsoleContract.Vehicles.VEHICLE_VIN };
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader, so we don't care about the ID.
// First, pick the base URI to use depending on whether we are
// currently filtering.
Uri baseUri = null;
String select = null, sortOrder = null;
String[] projection = null;
switch (id) {
case DRIVERS_LOADER:
baseUri = ConsoleContract.Drivers.CONTENT_URI;
select = "((" + Drivers.DRIVER_NAME + " NOT NULL) AND (" + Drivers.DRIVER_NAME + " != '' ))";
sortOrder = Drivers.DRIVER_NUMBER;
projection = DRIVERS_SUMMARY_PROJECTION;
break;
case VEHICLES_LOADER:
baseUri = ConsoleContract.Vehicles.CONTENT_URI;
select = "((" + Vehicles.VEHICLE_NUMBER + " NOT NULL) AND (" + Vehicles.VEHICLE_NUMBER + " != '' ))";
sortOrder = Vehicles.VEHICLE_NUMBER;
projection = VEHICLES_SUMMARY_PROJECTION;
break;
}
return new CursorLoader(getActivity(), baseUri, projection, select, null, sortOrder);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
int id = loader.getId();
MatrixCursor newCursor = null;
switch (id) {
case DRIVERS_LOADER:
newCursor = new MatrixCursor(DRIVERS_SUMMARY_PROJECTION);
break;
case VEHICLES_LOADER:
newCursor = new MatrixCursor(VEHICLES_SUMMARY_PROJECTION);
break;
}
newCursor.addRow(new String[] { "0", "0", "", "" });
Cursor[] cursors = { newCursor, data };
Cursor mergedCursor = new MergeCursor(cursors);
switch (id) {
case DRIVERS_LOADER:
mDriversAdapter.swapCursor(mergedCursor);
break;
case VEHICLES_LOADER:
mVehiclesAdapter.swapCursor(mergedCursor);
break;
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
int id = loader.getId();
switch (id) {
case DRIVERS_LOADER:
mDriversAdapter.swapCursor(null);
break;
case VEHICLES_LOADER:
mVehiclesAdapter.swapCursor(null);
break;
}
}
#Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if (parent.getId() == R.id.driversSpinner) {
mDriver = id;
} else {
mVehicle = id;
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
Make sure in your ContentProvider to call the notifyChange() method inside the insert, delete and update methods.
Here a snippet taken from Grokking Android Blog
public Uri insert(Uri uri, ContentValues values) {
if (URI_MATCHER.match(uri) != LENTITEM_LIST) {
throw new IllegalArgumentException("Unsupported URI for insertion: " + uri);
}
long id = db.insert(DBSchema.TBL_ITEMS, null, values);
if (id > 0) {
// notify all listeners of changes and return itemUri:
Uri itemUri = ContentUris.withAppendedId(uri, id);
getContext().getContentResolver().notifyChange(itemUri, null);
return itemUri;
}
// s.th. went wrong:
throw new SQLException("Problem while inserting into " + DBSchema.TBL_ITEMS + ", uri: " + uri); // use another exception here!!!
}
Conversely your Loader won't "heard" DB changes.
#rciovati's answer is good to me. But for me,I used Cursor Loader in my list view so it also need at query method in My ContentProvider.
In your ContentProvider class, query method also need to call notify after query like the code below-
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sort) {
SQLiteQueryBuilder queryBuilder=new SQLiteQueryBuilder();
Cursor cursor=queryBuilder.query(dbHelper.getReadableDatabase(),
projection,
selection,
selectionArgs,
null,
null,
sort);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
Related
it's the first time I'm using the content provider.
so I have this:
public class ContactsContentProvider extends ContentProvider {
private ContactsDatabaseHelper dbHelper;
private static final UriMatcher uriMatcher =
new UriMatcher(UriMatcher.NO_MATCH);
private static final int ONE_CONTACT = 1;
private static final int CONTACTS = 2;
private static final int CONTACT = 3;
static {
uriMatcher.addURI(ContactsDatabaseDescription.AUTHORITY,
Contact.TABLE_NAME + "/#", ONE_CONTACT);
uriMatcher.addURI(ContactsDatabaseDescription.AUTHORITY,
Contact.TABLE_NAME, CONTACTS);
uriMatcher.addURI(ContactsDatabaseDescription.AUTHORITY,
Contact.TABLE_NAME + "/*" , CONTACT);
}
#Override
public boolean onCreate() {
dbHelper = new ContactsDatabaseHelper(getContext());
return true;
}
#Override
public String getType(Uri uri) {
return null;
}
#Override
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(Contact.TABLE_NAME);
switch (uriMatcher.match(uri)) {
case ONE_CONTACT:
queryBuilder.appendWhere(
Contact._ID + "=" + uri.getLastPathSegment());
break;
case CONTACTS:
break;
default:
throw new UnsupportedOperationException(
getContext().getString(R.string.invalid_query_uri) + uri);
}
Cursor cursor = queryBuilder.query(dbHelper.getReadableDatabase(),
projection, selection, selectionArgs, null, null, sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
// insert a new contact in the database
#Override
public Uri insert(Uri uri, ContentValues values) {
Uri newContactUri = null;
switch (uriMatcher.match(uri)) {
case CONTACTS:
// insert the new contact--success yields new contact's row id
long rowId = dbHelper.getWritableDatabase().insert(
Contact.TABLE_NAME, null, values);
if (rowId > 0) {
newContactUri = Contact.buildContactUri(rowId);
getContext().getContentResolver().notifyChange(uri, null);
}
else
throw new SQLException(
getContext().getString(R.string.insert_failed) + uri);
break;
default:
throw new UnsupportedOperationException(
getContext().getString(R.string.invalid_insert_uri) + uri);
}
return newContactUri;
}
#Override
public int update(Uri uri, ContentValues values,
String selection, String[] selectionArgs) {
int numberOfRowsUpdated; // 1 if update successful; 0 otherwise
switch (uriMatcher.match(uri)) {
case ONE_CONTACT:
String id = uri.getLastPathSegment();
numberOfRowsUpdated = dbHelper.getWritableDatabase().update(
Contact.TABLE_NAME, values, Contact._ID + "=" + id,
selectionArgs);
break;
default:
throw new UnsupportedOperationException(
getContext().getString(R.string.invalid_update_uri) + uri);
}
if (numberOfRowsUpdated != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return numberOfRowsUpdated;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int numberOfRowsDeleted;
switch (uriMatcher.match(uri)) {
case ONE_CONTACT:
String id = uri.getLastPathSegment();
numberOfRowsDeleted = dbHelper.getWritableDatabase().delete(
Contact.TABLE_NAME, Contact._ID + "=" + id, selectionArgs);
break;
default:
throw new UnsupportedOperationException(
getContext().getString(R.string.invalid_delete_uri) + uri);
}
if (numberOfRowsDeleted != 0) {
getContext().getContentResolver().notifyChange(uri, null);
}
return numberOfRowsDeleted;
}
}
My database is
public class ContactsDatabaseDescription {
public static final String AUTHORITY =
"com.example.afran.bdcontacts.data";
private static final Uri BASE_CONTENT_URI =
Uri.parse("content://" + AUTHORITY);
public static final class Contact implements BaseColumns {
public static final String TABLE_NAME = "contacts"; // table's name
public static final Uri CONTENT_URI =
BASE_CONTENT_URI.buildUpon().appendPath(TABLE_NAME).build();
public static final String COLUMN_FIRST_NAME = "firstName";
public static final String COLUMN_LAST_NAME = "lastName";
public static final String COLUMN_EMAIL = "email";
public static final String COLUMN_TYPE = "type";
public static Uri buildContactUri(long id) {
return ContentUris.withAppendedId(CONTENT_URI, id);
}
}
}
and on this fragment I read one last name (search) and I want to find the contact and I do not know how
public class DetailFragment extends Fragment
implements LoaderManager.LoaderCallbacks<Cursor> {
public interface DetailFragmentListener {
void onContactDeleted();
void onEditContact(Uri contactUri);
}
private static final int CONTACT_LOADER = 0;
private DetailFragmentListener listener;
private Uri contactUri;
private TextView prenomTextView;
private TextView nomTextView;
private TextView emailTextView;
private TextView typeTextView;
#Override
public void onAttach(Context context) {
super.onAttach(context);
listener = (DetailFragmentListener) context;
}
#Override
public void onDetach() {
super.onDetach();
listener = null;
}
#Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
setHasOptionsMenu(true);
Bundle arguments = getArguments();
if (arguments != null)
contactUri = arguments.getParcelable(MainActivity.CONTACT_URI);
View view =
inflater.inflate(R.layout.fragment_detail, container, false);
prenomTextView = (TextView) view.findViewById(R.id.firstNameTextView);
nomTextView = (TextView) view.findViewById(R.id.lastNameTextView);
emailTextView = (TextView) view.findViewById(R.id.emailTextView);
typeTextView = (TextView) view.findViewById(R.id.typeTextView);
getLoaderManager().initLoader(CONTACT_LOADER, null, this);
return view;
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_main, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_edit:
listener.onEditContact(contactUri);
return true;
case R.id.action_delete:
deleteContact();
return true;
case R.id.action_search:
searchContact();
return true;
}
return super.onOptionsItemSelected(item);
}
private void searchContact() {
final EditText input = new EditText(getContext());
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.menuitem_recherche);
builder.setMessage(R.string.label_lastName);
builder.setView(input);
builder.setPositiveButton(R.string.button_ok, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int whichButton) {
String value = input.getText().toString();
return;
}
});
builder.setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
return;
}
});
builder.create().show();
}
private void deleteContact() {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.confirm_title);
builder.setMessage(R.string.confirm_message);
builder.setPositiveButton(R.string.button_delete, new DialogInterface.OnClickListener() {
#Override
public void onClick(
DialogInterface dialog, int button) {
getActivity().getContentResolver().delete(
contactUri, null, null);
listener.onContactDeleted();
}
}
);
builder.setNegativeButton(R.string.button_cancel, null);
builder.create().show();
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader;
switch (id) {
case CONTACT_LOADER:
cursorLoader = new CursorLoader(getActivity(),
contactUri,
null,
null,
null,
null);
break;
default:
cursorLoader = null;
break;
}
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if (data != null && data.moveToFirst()) {
int firstIndex = data.getColumnIndex(ContactsDatabaseDescription.Contact.COLUMN_FIRST_NAME);
int lastIndex = data.getColumnIndex(ContactsDatabaseDescription.Contact.COLUMN_LAST_NAME);
int emailIndex = data.getColumnIndex(ContactsDatabaseDescription.Contact.COLUMN_EMAIL);
int typeIndex = data.getColumnIndex(ContactsDatabaseDescription.Contact.COLUMN_TYPE);
prenomTextView.setText(data.getString(firstIndex));
nomTextView.setText(data.getString(lastIndex));
emailTextView.setText(data.getString(emailIndex));
typeTextView.setText(data.getString(typeIndex));
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) { }
}
It is simple to search for a match of any column in your table. You simply need the contentUri, and where and whereArgs parameters for the query. Ensure your Uri points to the whole table. Assuming you want to match columns called "first_name" and "surname" with Strings called firstName and surname.
String where = "first_name =? and surname =?";
String[] whereArgs = {firstName, surname};
You can use parentheses and "and" and "or" to construct more complex queries. With numerical fields you can use > and < etc. You must ensure whereArgs has as many elements as where has "?"
I have two activities MainActivity and Addlogactivity i am updating a data in Addlogactivity which should be displayed in mainactivity recyclerview the data is not updating in database
MianActivityClass :
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{
RecyclerView recyclerView;
Intent addDisplay;
Mainrow_Adapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView)findViewById(R.id.listView);
addDisplay = new Intent(this,AddLog.class);
Toolbar toolbar = (Toolbar)findViewById(R.id.maintoolbar);
setSupportActionBar(toolbar);
toolbar.setTitle("Account's");
getSupportLoaderManager().initLoader(1,null,this);
adapter = new Mainrow_Adapter(this,null);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
public void createID(View view)
{
ContentValues values = new ContentValues();
values.put(DataProvider.Pname,"1");
values.put(DataProvider.Pphone,"1");
values.put(DataProvider.Paddress,"1");
values.put(DataProvider.PCategory,"1");
values.put(DataProvider.Pamount,"1");
getContentResolver().insert(DataProvider.ContentUri_Person,values);
long id = DataProvider.insertId;
addDisplay.putExtra("ID",id);
Toast.makeText(MainActivity.this,String.valueOf(id), Toast.LENGTH_SHORT).show();
startActivity(addDisplay);
finish();
}
#Override
protected void onResume() {
super.onResume();
adapter.notifyDataSetChanged();
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] Prjection = {DataProvider.PID,DataProvider.Pname,DataProvider.Pphone,DataProvider.Paddress,DataProvider.PCategory,DataProvider.Pamount};
return new CursorLoader(this,DataProvider.ContentUri_Person,Prjection,null,null,null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data)
{
adapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader)
{
adapter.swapCursor(null);
}
}
AddLog activity class :
public class AddLog extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{
TextView TotalAmount,Date;
EditText name,mobile,city,detailname,detailamount;
RecyclerView adddetailtolist;
DetailsAdapter adapter;
Intent returnback;
double totamount;
long logid;
String Debt = "Debt";
String Paid = "Paid";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_log);
Toolbar toolbar = (Toolbar)findViewById(R.id.addlogtoolbar);
setSupportActionBar(toolbar);
toolbar.setTitle("Add Log");
returnback = new Intent(this,MainActivity.class);
Intent intent = getIntent();
logid = intent.getExtras().getLong("ID");
TotalAmount = (TextView)findViewById(R.id.totalAmount);
Date = (TextView)findViewById(R.id.addlogDate);
name = (EditText)findViewById(R.id.AddName);
mobile = (EditText)findViewById(R.id.AddPhone);
city = (EditText)findViewById(R.id.Addcity);
detailname = (EditText)findViewById(R.id.Detailname);
detailamount = (EditText)findViewById(R.id.Detailamount);
adddetailtolist = (RecyclerView)findViewById(R.id.addloglist);
Date.setText(getDate());
getSupportLoaderManager().initLoader(1,null,this);
adapter = new DetailsAdapter(this,null);
adddetailtolist.setAdapter(adapter);
adddetailtolist.setLayoutManager(new LinearLayoutManager(this));
}
private String getDate()
{
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE,dd-MMM-yyyy");
String date = simpleDateFormat.format(calendar.getTime());
return date;
}
public void addDetails(View view)
{
String Name = detailname.getText().toString();
String Amount = detailamount.getText().toString();
String date = Date.getText().toString();
ContentValues contentValues = new ContentValues();
contentValues.put(DataProvider.Dname,Name);
contentValues.put(DataProvider.DCategory,Debt);
contentValues.put(DataProvider.Damount,Amount);
contentValues.put(DataProvider.Ddate,date);
contentValues.put(DataProvider.Per_In,logid);
Uri uri = getContentResolver().insert(DataProvider.ContentUri_Details,contentValues);
Toast.makeText(AddLog.this, uri.toString()+"Value Inserted", Toast.LENGTH_SHORT).show();
NumberFormat currency = changeamount();
TotalAmount.setText(currency.format(getAmount()));
}
private double getAmount()
{
ContentProviderClient client = getContentResolver().acquireContentProviderClient(DataProvider.ContentUri_Details);
SQLiteDatabase db = ((DataProvider)client.getLocalContentProvider()).sqLiteDatabase;
String query = "SELECT SUM(DAmount) FROM Details WHERE Per_In = "+logid;
Cursor cursor = db.rawQuery(query, null);
cursor.moveToFirst();
double amount = cursor.getDouble(0);
cursor.close();
client.release();
return amount;
}
public NumberFormat changeamount()
{
Locale locale = new Locale("en","IN");
NumberFormat currencyformat = NumberFormat.getCurrencyInstance(locale);
return currencyformat;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuinflate = getMenuInflater();
menuinflate.inflate(R.menu.addlogmenu,menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.done:
saveData();
}
return super.onOptionsItemSelected(item);
}
private void saveData()
{
String name1 = name.getText().toString();
String phone = mobile.getText().toString();
String address = city.getText().toString();
if (TextUtils.isEmpty(name1)||TextUtils.isEmpty(phone)||TextUtils.isEmpty(address))
{
if (TextUtils.isEmpty(name1))
{
name.setError("Feild can not be Empty");
}
else if (TextUtils.isEmpty(phone))
{
mobile.setError("Feild can not be Empty");
}
else if (TextUtils.isEmpty(address))
{
city.setError("Feild can not be Empty");
}
}
else
{
ContentValues values = new ContentValues();
values.put(DataProvider.Pname,name1);
values.put(DataProvider.Pphone,phone);
values.put(DataProvider.Paddress,address);
values.put(DataProvider.PCategory,"Debt");
values.put(DataProvider.Pamount,totamount);
String where = DataProvider.PID+"=?";
String[] whereargs = {String.valueOf(logid)};
int a = getContentResolver().update(DataProvider.ContentUri_Person,values,where,whereargs);
Toast.makeText(AddLog.this, String.valueOf(1)+"Value updated", Toast.LENGTH_SHORT).show();
startActivity(returnback);
finish();
}
}
#Override
public Loader<Cursor> onCreateLoader(final int id, Bundle args)
{
String[] Projection = new String[]{DataProvider.DID,DataProvider.Dname,DataProvider.DCategory,DataProvider.Damount,DataProvider.Ddate};
String selection = DataProvider.Per_In+"=?";
String[] selectionargs = new String[]{String.valueOf(logid)};
return new CursorLoader(this,DataProvider.ContentUri_Details,Projection,selection,selectionargs,null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data)
{
adapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader)
{
adapter.swapCursor(null);
}
}
Content Provider class:
public class DataProvider extends ContentProvider
{
static final String ProviderName = "com.example.mrudu.accounts.provider";
static final String URLPerson = "content://"+ProviderName+"/Person_Detail";
static final String URLDetails = "content://"+ProviderName+"/Details";
static final Uri ContentUri_Person = Uri.parse(URLPerson);
static final Uri ContentUri_Details = Uri.parse(URLDetails);
//Tables
private static String PTableName = "Person_Detail";
private static String DTableName = "Details";
public static long insertId = 0;
//Person_Detail Coloumns
public static String PID = "_id";
public static String Pname = "PName";
public static String Pphone = "PMobile";
public static String Paddress = "PCity";
public static String PCategory = "PCategory";
public static String Pamount = "PAmount";
//Details coloumn
public static String DID = "_id";
public static String Dname = "DName";
public static String Damount = "DAmount";
public static String Ddate = "DDate";
public static String DCategory = "DCategory";
public static String Per_In = "Per_In";
private static final int Person = 1;
private static final int Person_ID = 2;
private static final int Details = 3;
private static final int Details_Id = 4;
static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static
{
uriMatcher.addURI(ProviderName,PTableName,Person);
uriMatcher.addURI(ProviderName,PTableName+"/#",Person_ID);
uriMatcher.addURI(ProviderName,DTableName,Details);
uriMatcher.addURI(ProviderName,DTableName+"/#",Details_Id);
}
public static SQLiteDatabase sqLiteDatabase;
private static String Databasename = "Accounts";
private static int DatabaseVersion = 1;
private class DatabaseHelper extends SQLiteOpenHelper
{
public DatabaseHelper(Context context)
{
super(context, Databasename, null, DatabaseVersion);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase)
{
String Create_Person = " Create Table "+PTableName+"("+PID+" INTEGER PRIMARYKEY ,"+Pname+" TEXT ,"+Pphone+" TEXT ,"+Paddress+" TEXT ,"+PCategory+" TEXT ,"+Pamount+" REAL"+")";
String Create_Details = " Create Table "+DTableName+"("+DID+" INTEGER PRIMARYKEY ,"+Dname+" TEXT ,"+DCategory+" TEXT ,"+Damount+" REAl ,"+Ddate+" TEXT ,"+Per_In+" INTEGER )";
sqLiteDatabase.execSQL(Create_Person);
sqLiteDatabase.execSQL(Create_Details);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1)
{
sqLiteDatabase.execSQL("Drop TABLE if exists"+PTableName);
sqLiteDatabase.execSQL("Drop TABLE if exists"+DTableName);
onCreate(sqLiteDatabase);
}
}
#Override
public boolean onCreate()
{
Context context = getContext();
DatabaseHelper databaseHelper = new DatabaseHelper(context);
sqLiteDatabase = databaseHelper.getWritableDatabase();
return (sqLiteDatabase==null)?false:true;
}
#Override
public Uri insert(Uri uri, ContentValues values)
{
switch (uriMatcher.match(uri))
{
case Person:
long rowId = sqLiteDatabase.insert(PTableName,null,values);
insertId = rowId;
if (rowId>0)
{
Uri _uri = ContentUris.withAppendedId(ContentUri_Person,rowId);
getContext().getContentResolver().notifyChange(_uri,null);
return _uri;
}
break;
case Details:
long rowId1 = sqLiteDatabase.insert(DTableName,null,values);
if (rowId1>0)
{
Uri _uri = ContentUris.withAppendedId(ContentUri_Details,rowId1);
getContext().getContentResolver().notifyChange(_uri,null);
return _uri;
}
break;
}
return null;
}
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
SQLiteQueryBuilder sqLiteQueryBuilder = new SQLiteQueryBuilder();
switch (uriMatcher.match(uri))
{
case Person_ID:
sqLiteQueryBuilder.setTables(PTableName);
sqLiteQueryBuilder.appendWhere(PID+ "="+ uri.getPathSegments().get(1));
break;
case Person:
sqLiteQueryBuilder.setTables(PTableName);
break;
case Details_Id:
sqLiteQueryBuilder.setTables(DTableName);
sqLiteQueryBuilder.appendWhere(Per_In +"="+ uri.getPathSegments().get(1));
break;
case Details:
sqLiteQueryBuilder.setTables(DTableName);
break;
default:
throw new UnsupportedOperationException("Not yet implemented");
}
Cursor cursor = sqLiteQueryBuilder.query(sqLiteDatabase,projection,selection,selectionArgs,null,null,sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(),uri);
return cursor;
}
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs)
{
int count = 0;
switch (uriMatcher.match(uri))
{
case Person:
count = sqLiteDatabase.update(PTableName,values,selection,selectionArgs);
break;
case Person_ID:
count = sqLiteDatabase.update(PTableName,values,PID+" = "+uri.getPathSegments().get(1)+(!TextUtils.isEmpty(selection)?" AND (" + selection + ')':""),selectionArgs);
break;
case Details:
count = sqLiteDatabase.update(DTableName,values,selection,selectionArgs);
break;
case Details_Id:
count = sqLiteDatabase.update(DTableName,values,Per_In+" = "+uri.getPathSegments().get(1)+(!TextUtils.isEmpty(selection)?" AND (" + selection + ')':""),selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri );
}
getContext().getContentResolver().notifyChange(uri,null);
return count;
}
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Implement this to handle requests to delete one or more rows.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public String getType(Uri uri) {
// TODO: Implement this to handle requests for the MIME type of the data
// at the given URI.
throw new UnsupportedOperationException("Not yet implemented");
}
Cursor Recyclerview Adapter class:
public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
private Context mContext;
private Cursor mCursor;
private boolean mDataValid;
private int mRowIdColumn;
private DataSetObserver mDataSetObserver;
public CursorRecyclerViewAdapter(Context context, Cursor cursor) {
mContext = context;
mCursor = cursor;
mDataValid = cursor != null;
mRowIdColumn = mDataValid ? mCursor.getColumnIndex("_id") : -1;
mDataSetObserver = new NotifyingDataSetObserver();
if (mCursor != null) {
mCursor.registerDataSetObserver(mDataSetObserver);
}
}
public Cursor getCursor() {
return mCursor;
}
#Override
public int getItemCount() {
if (mDataValid && mCursor != null) {
return mCursor.getCount();
}
return 0;
}
#Override
public long getItemId(int position) {
if (mDataValid && mCursor != null && mCursor.moveToPosition(position)) {
return mCursor.getLong(mRowIdColumn);
}
return 0;
}
#Override
public void setHasStableIds(boolean hasStableIds) {
super.setHasStableIds(true);
}
public abstract void onBindViewHolder(VH viewHolder, Cursor cursor);
#Override
public void onBindViewHolder(VH viewHolder, int position) {
if (!mDataValid) {
throw new IllegalStateException("this should only be called when the cursor is valid");
}
if (!mCursor.moveToPosition(position)) {
throw new IllegalStateException("couldn't move cursor to position " + position);
}
onBindViewHolder(viewHolder, mCursor);
}
/**
* Change the underlying cursor to a new cursor. If there is an existing cursor it will be
* closed.
*/
public void changeCursor(Cursor cursor) {
Cursor old = swapCursor(cursor);
if (old != null) {
old.close();
}
}
/**
* Swap in a new Cursor, returning the old Cursor. Unlike
* {#link #changeCursor(Cursor)}, the returned old Cursor is <em>not</em>
* closed.
*/
public Cursor swapCursor(Cursor newCursor) {
if (newCursor == mCursor) {
return null;
}
final Cursor oldCursor = mCursor;
if (oldCursor != null && mDataSetObserver != null) {
oldCursor.unregisterDataSetObserver(mDataSetObserver);
}
mCursor = newCursor;
if (mCursor != null) {
if (mDataSetObserver != null) {
mCursor.registerDataSetObserver(mDataSetObserver);
}
mRowIdColumn = newCursor.getColumnIndexOrThrow("_id");
mDataValid = true;
notifyDataSetChanged();
} else {
mRowIdColumn = -1;
mDataValid = false;
notifyDataSetChanged();
//There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
}
return oldCursor;
}
private class NotifyingDataSetObserver extends DataSetObserver {
#Override
public void onChanged() {
super.onChanged();
mDataValid = true;
notifyDataSetChanged();
}
#Override
public void onInvalidated() {
super.onInvalidated();
mDataValid = false;
notifyDataSetChanged();
//There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
}
}
}
Main Adapter class:
public class Mainrow_Adapter extends CursorRecyclerViewAdapter<Mainrow_Adapter.ViewHolder>
{
public Mainrow_Adapter(Context context, Cursor cursor) {
super(context, cursor);
}
public static class ViewHolder extends RecyclerView.ViewHolder
{
TextView mName,mAmount;
public ViewHolder(View itemView) {
super(itemView);
mName = (TextView)itemView.findViewById(R.id.mainrowname);
mAmount = (TextView)itemView.findViewById(R.id.mainrowAmount);
}
}
#Override
public Mainrow_Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.mainrow_layout,parent,false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(Mainrow_Adapter.ViewHolder viewHolder, Cursor cursor)
{
PersonDetails personDetails = PersonDetails.from(cursor);
viewHolder.mName.setText(personDetails.getName());
viewHolder.mAmount.setText(String.valueOf(personDetails.getAmount()));
}
}
Ok,
then move below three lines from onCreate method to onResume(),
getSupportLoaderManager().initLoader(1,null,this);
adapter = new Mainrow_Adapter(this,null);
recyclerView.setAdapter(adapter);
Hope this will work
I’m struggling to write a method that deletes a row from the SQLiteDatabase. I have a list of songs in a gridview where when a user clicks one of the items from the list the app will take them to my SongDetailFragment activity which contains more information about the song and a star button where if a song in in the database the star button is “switched on”, conversely if the item is NOT in the database the star button is “switched-off”
When a user click the star button I'm able to add a song successfully in the database and my star button is “switched-on”. Now I want to press the same button again and call deleteFromDB() to delete the song that was added to the database. So I have the following code in my onClick:
public void onClick(View v)
{
if (mIsFavourite) {
deleteFromDB();
}
else {
insertData();
mIsFavourite = true;
}
The problem is deleteFromDB() method is not working correctly as I can see that the song is not deleting from the database. I’m not sure what is the correct syntax to fix it.
Here is my method:
private void deleteFromDB() {
ContentValues songValues = new ContentValues();
getActivity().getContentResolver().delete(SongContract.SongEntry.CONTENT_URI,
SongContract.SongEntry.COLUMN_TITLE + " = ?",
new String[]{songValues.getAsString(song.getTitle())});
//switch off button
imgViewFavButton.setImageResource(android.R.drawable.btn_star_big_off);
}
Here is my delete method snippet from my ContentProvider class:
#Override
public int delete(Uri uri, String selection, String[] selectionArgs){
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
final int match = sUriMatcher.match(uri);
int numDeleted;
switch(match){
case SONG:
numDeleted = db.delete(
SongContract.SongEntry.TABLE_NAME, selection, selectionArgs);
// reset _ID
db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
SongContract.SongEntry.TABLE_NAME + "'");
break;
case SONG_WITH_ID:
numDeleted = db.delete(SongContract.SongEntry.TABLE_NAME,
SongContract.SongEntry._ID + " = ?",
new String[]{String.valueOf(ContentUris.parseId(uri))});
// reset _ID
db.execSQL("DELETE FROM SQLITE_SEQUENCE WHERE NAME = '" +
SongContract.SongEntry.TABLE_NAME + "'");
break;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
return numDeleted;
}
Here is my SongDetailFragment:
public class SongDetailFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{
private Song song;
private static final int CURSOR_LOADER_ID = 0;
ImageButton imgViewFavButton;
Boolean mIsFavourite = false;
// private final Context mContext;
public SongDetailFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.song_fragment_detail, container, false);
Intent intent = getActivity().getIntent();
if (intent != null && intent.hasExtra("song")) {
song = intent.getParcelableExtra("song");
//display title
((TextView) rootView.findViewById(R.id.detail_title_textview))
.setText(song.getTitle());
((TextView)rootView.findViewById(R.id.detail_description_textview))
.setText(song.getDescription());
((TextView)rootView.findViewById(R.id.song_releasedate_textview))
.setText(song.getReleaseDate());
double dRating = song.getVoteAverage();
String sRating = String.valueOf(dRating);
((TextView)rootView.findViewById(R.id.song_rating_textview))
.setText(sRating + "/10 ");
//show song poster
ImageView imageView = (ImageView) rootView.findViewById(R.id.song_detail_poster_imageview);
Picasso.with(getActivity()).load(song.getPoster()).into(imageView);
}
imgViewFavButton = (ImageButton) rootView.findViewById(R.id.imgFavBtn);
checkFavourites();
imgViewFavButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
if (mIsFavourite) {
deleteFromDB();
}
else {
insertData();
mIsFavourite = true;
}
}
});
return rootView;
}
// insert data into database
public void insertData(){
ContentValues songValues = new ContentValues();
songValues.put(SongContract.SongEntry.COLUMN_ID, song.getsong_id());
songValues.put(SongContract.SongEntry.COLUMN_IMAGE, song.getPoster());
songValues.put(SongContract.SongEntry.COLUMN_TITLE, song.getTitle());
songValues.put(SongContract.SongEntry.COLUMN_OVERVIEW, song.getDescription());
songValues.put(SongContract.SongEntry.COLUMN_RELEASEDATE, song.getReleaseDate());
songValues.put(SongContract.SongEntry.COLUMN_RATING, song.getVoteAverage().toString());
//Insert our ContentValues
getActivity().getContentResolver().insert(SongContract.SongEntry.CONTENT_URI,
songValues);
imgViewFavButton.setImageResource(android.R.drawable.btn_star_big_on);
}
private void deleteFromDB() {
ContentValues songValues = new ContentValues();
getActivity().getContentResolver().delete(SongContract.SongEntry.CONTENT_URI,
SongContract.SongEntry.COLUMN_TITLE + " = ?",
new String[]{songValues.getAsString(song.getTitle())});
imgViewFavButton.setImageResource(android.R.drawable.btn_star_big_off);
}
private void checkFavourites() {
Cursor c =
getActivity().getContentResolver().query(SongContract.SongEntry.CONTENT_URI,
null,
SongContract.SongEntry.COLUMN_ID + " = ?",
new String[]{song.getsong_id()},
null);
if (c != null) {
c.moveToFirst();
int index = c.getColumnIndex(SongContract.SongEntry.COLUMN_ID);
if (c.getCount() > 0 && c.getString(index).equals(song.getsong_id())) {
mIsFavourite = true;
imgViewFavButton.setImageResource(android.R.drawable.btn_star_big_on);
}
else{
imgViewFavButton.setImageResource(android.R.drawable.btn_star_big_off);
}
c.close();
}
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args){
return new CursorLoader(getActivity(),
SongContract.songEntry.CONTENT_URI,
null,
null,
null,
null);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
}
// Set the cursor in our CursorAdapter once the Cursor is loaded
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
}
// reset CursorAdapter on Loader Reset
#Override
public void onLoaderReset(Loader<Cursor> loader){
}
}
Notice this line right here:
ContentValues songValues = new ContentValues();
getActivity().getContentResolver().delete(SongContract.songEntry.CONTENT_URI,
SongContract.songEntry.COLUMN_TITLE + " = ?",
new String[]{songValues.getAsString(song.getTitle())});
You set songValues to an empty ContentValues object, and later call getAsString() which will return null since it doesn't contain any key for song.getTitle().
Just change your array to have the song title, you don't need ContentValues here:
new String[]{song.getTitle()});
I have a Loader class, which loads some data asynchronously in an fragment in a RecyclerView. This works fine, when the user comes to that fragment the first time. If he moves away by clicking an ActionBar Button to insert some new data, and returns, I want that the new data becomes visible in my RecyclerView, but it doesn't.
I initialise the Loader in onStart() and although onStart() is called when the user comes back, the loader is not not updating (No changes to the RecyclerView visible)
Here are the relevant methods from the fragment with the loader:
private static final int TERMIN_LOADER_ID = 1;
private static final int AUFGABEN_LOADER_ID = 2;
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
switch(i){
case TERMIN_LOADER_ID:
return new TerminLoader(getActivity());
case AUFGABEN_LOADER_ID:
throw new UnsupportedOperationException("AUFGABEN_LOADER_ID not implemented yet.");
default:
throw new UnsupportedOperationException("Unknown loader id.");
}
}
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
// mAdapter is a CursorAdapter
//mAdapter.swapCursor(cursor);
switch(cursorLoader.getId()){
case TERMIN_LOADER_ID:
RadListView termineListView = (RadListView)getActivity().findViewById(R.id.termineRadListView);
// now here we can fill our termineListView because we got the cursor ready
ArrayList<Termin> termine = new ArrayList<>();
cursor.moveToFirst();
while(!cursor.isAfterLast()){
// loop over the results from the query and build our termine ArrayList
// this is our MatrixCursor from our TerminLoader
long terminId = cursor.getLong(cursor.getColumnIndex(CalendarContract.Events._ID));
String title = cursor.getString(cursor.getColumnIndex(CalendarContract.Events.TITLE));
long begin = cursor.getLong(cursor.getColumnIndex(CalendarContract.Events.DTSTART));
Termin termin = new Termin(terminId, title, begin);
termine.add(termin);
cursor.moveToNext();
}
TerminListViewAdapter terminListViewAdapter = new TerminListViewAdapter(termine, getActivity());
termineListView.setAdapter(terminListViewAdapter);
break;
case AUFGABEN_LOADER_ID:
throw new UnsupportedOperationException("AUFGABEN_LOADER_ID not implemented yet.");
default:
throw new UnsupportedOperationException("Unknown LOADER_ID.");
}
}
#Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
switch(cursorLoader.getId()){
case TERMIN_LOADER_ID:
// now here we can fill our termineListView because we got the cursor ready
//RadListView termineListView = (RadListView)getActivity().findViewById(R.id.termineRadListView);
ArrayList<Termin> termine = new ArrayList<>();
TerminListViewAdapter terminListViewAdapter = new TerminListViewAdapter(termine, getActivity());
this.termineListView.setAdapter(terminListViewAdapter);
break;
case AUFGABEN_LOADER_ID:
throw new UnsupportedOperationException("AUFGABEN_LOADER_ID not implemented yet.");
default:
throw new UnsupportedOperationException("Unknown LOADER_ID.");
}
}
#Override
public void onStart() {
super.onStart();
loadData();
}
public void loadData(){
// reload termine
getActivity().getSupportLoaderManager().initLoader(TERMIN_LOADER_ID, null, this);
}
This is how the user moves away:
toolbarBottom = (Toolbar) getActivity().findViewById(R.id.toolbar_bottom);
toolbarBottom.inflateMenu(R.menu.menu_toolbar_home);
toolbarBottom.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem menuItem) {
// the selected patient's id
SharedPreferences prefs = HomeFragment.this.getActivity().getSharedPreferences(Constants.SHARED_PREFS_FILE, 0);
long _id = prefs.getLong(Constants.SELECTED_PATIENT_ID, 1);
switch (menuItem.getItemId()) {
case R.id.item_termin_erstellen:
//Toast.makeText(getActivity(), "Termin clicked: " + String.valueOf(_id), Toast.LENGTH_LONG).show();
TerminFragment terminFragment = TerminFragment.newInstance(_id);
Bundle args = new Bundle();
args.putString(Constants.ACTION, Constants.CREATE);
terminFragment.setArguments(args);
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, terminFragment).addToBackStack(Constants.TERMIN_FRAGMENT).commit();
break;
case R.id.item_aufgabe_erstellen:
Toast.makeText(getActivity(), "Aufgabe clicked: " + String.valueOf(_id), Toast.LENGTH_LONG).show();
break;
case R.id.item_dokumentation:
Toast.makeText(getActivity(), "Dokumentation clicked: " + String.valueOf(_id), Toast.LENGTH_LONG).show();
break;
default:
}
return true;
}
});
}
And this is the code in TerminFragment which gets the user back to the first fragment:
MainActivity mainActivity = (MainActivity) getActivity();
FragmentManager fragmentManager = getFragmentManager();
HomeFragment homeFragment = (HomeFragment)fragmentManager.findFragmentByTag(Constants.HOME_FRAGMENT);
if(homeFragment != null){
homeFragment.loadData();
}
fragmentManager.popBackStack();
And finally, this is my Loader class:
public class TerminLoader extends CursorLoader {
private static final String TAG = "TerminLoader";
private Context context;
// This loader loads events by querying the database for additional data
public TerminLoader(Context context) {
super(context);
this.context = context;
}
#Override
public Cursor loadInBackground() {
// we query against the calendar database for all termine of a peticular patient// only fetch the termine of a particular patient
SharedPreferences prefs = context.getSharedPreferences(Constants.SHARED_PREFS_FILE, 0);
long selectedPatientId = prefs.getLong(Constants.SELECTED_PATIENT_ID, 1);
String selection = TerminContract.Columns.PATIENT_ID + " = ? ";
String[] selectionArgs = {String.valueOf(selectedPatientId)};
Cursor cursor = context.getApplicationContext().getContentResolver().query(TerminContract.CONTENT_URI, null, selection, selectionArgs, "");
cursor.moveToFirst();
String[] columnNames = {CalendarContract.Events._ID,
CalendarContract.Events.TITLE,
CalendarContract.Events.DTSTART};
MatrixCursor matrixCursor = new MatrixCursor(columnNames);
while(!cursor.isAfterLast()){
long terminId = cursor.getLong(cursor.getColumnIndex(TerminContract.Columns.TERMIN_ID));
// retrieve the event for this terminId by querying the calendar
Cursor cur = null;
Uri uri = CalendarContract.Events.CONTENT_URI;
ContentResolver cr = context.getContentResolver();
String[] projection2 = {CalendarContract.Events.TITLE,
CalendarContract.Events.DTSTART};
String selection2 = "(" + CalendarContract.Events._ID + " = ?)";
String[] selectionArgs2 = new String[] {String.valueOf(terminId)};
// Submit the query and get a Cursor object back.
cur = cr.query(uri, projection2, selection2, selectionArgs2, null);
cur.moveToFirst();
// Get the field values
String title = cur.getString(cur.getColumnIndex(CalendarContract.Events.TITLE));
//String title = "title";
long dtStart = cur.getLong(cur.getColumnIndex(CalendarContract.Events.DTSTART));
// and add it to our MatrixCursor
MatrixCursor.RowBuilder rowBuilder = matrixCursor.newRow();
rowBuilder.add(terminId)
.add(title)
.add(dtStart);
//move to nexr row
cursor.moveToNext();
}
return matrixCursor;
}
}
Any ideas?
Note, that I can confirm that before the above lines are executed, the data is inserted correctly.
Also note, that the above lines fail to findFragmentByTag.
Thanks
I fixed the problem by a very simple, little change:
public void loadData(){
// reload termine
getActivity().getSupportLoaderManager().destroyLoader(TERMIN_LOADER_ID);
getActivity().getSupportLoaderManager().initLoader(TERMIN_LOADER_ID, null, this);
}
I destroy an existing loader before initialising the loader.
I have a DatabaseConnector class where I want to check if the database is empty and then show an alert and a click on it will close the activity.
This is my DatabaseConnector class
public class DatabaseConnector {
// Declare Variables
private static final String DB_NAME = "MyNotes";
private static final String TABLE_NAME = "tablenotes";
private static final String TITLE = "title";
private static final String ID = "_id";
private static final String NOTE = "note";
private static final int DATABASE_VERSION = 2;
private SQLiteDatabase database;
private DatabaseHelper dbOpenHelper;
public static final String MAINCAT = "maincat";
public static final String SUBCAT = "subcat";
public DatabaseConnector(Context context) {
dbOpenHelper = new DatabaseHelper(context, DB_NAME, null,
DATABASE_VERSION);
}
// Open Database function
public void open() throws SQLException {
// Allow database to be in writable mode
database = dbOpenHelper.getWritableDatabase();
}
// Close Database function
public void close() {
if (database != null)
database.close();
}
// Create Database function
public void InsertNote(String title, String note , String maincat, String subcat) {
ContentValues newCon = new ContentValues();
newCon.put(TITLE, title);
newCon.put(NOTE, note);
newCon.put(MAINCAT, maincat);
newCon.put(SUBCAT, subcat);
open();
database.insert(TABLE_NAME, null, newCon);
close();
}
// Update Database function
public void UpdateNote(long id, String title, String note) {
ContentValues editCon = new ContentValues();
editCon.put(TITLE, title);
editCon.put(NOTE, note);
open();
database.update(TABLE_NAME, editCon, ID + "=" + id, null);
close();
}
// Delete Database function
public void DeleteNote(long id) {
open();
database.delete(TABLE_NAME, ID + "=" + id, null);
close();
}
// List all data function
//String selection = dbOpenHelper.MAINCAT + " = 'quiz'"
// +" AND " + dbOpenHelper.SUBCAT + " = 'test'";
// public Cursor ListAllNotes() {
// return database.query(TABLE_NAME, new String[] { ID, TITLE }, null,
// null, null, null, TITLE);
// }
public Cursor ListAllNotes(String selection) {
return database.query(TABLE_NAME, new String[] { ID, TITLE }, selection,
null, null, null, TITLE);
}
// Capture single data by ID
public Cursor GetOneNote(long id) {
return database.query(TABLE_NAME, null, ID + "=" + id, null, null,
null, null);
}
And here is the ListActivity wherein I want to close the Activity with an alert
public class dbMainactivty extends ListActivity {
// Declare Variables
public static final String ROW_ID = "row_id";
private static final String TITLE = "title";
private ListView noteListView;
private CursorAdapter noteAdapter;
#SuppressWarnings("deprecation")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Tracker t = ((AnalyticsSampleApp)this.getApplication()).getTracker(TrackerName.APP_TRACKER);
t.setScreenName("dbMainactivty");
t.send(new HitBuilders.AppViewBuilder().build());
// Locate ListView
noteListView = getListView();
// setContentView(R.layout.list_note);
//noteListView = (ListView) findViewById(R.id.listview);
// Prepare ListView Item Click Listener
noteListView.setOnItemClickListener(viewNoteListener);
// Map all the titles into the ViewTitleNotes TextView
String[] from = new String[] { TITLE };
int[] to = new int[] { R.id.ViewTitleNotes };
// Create a SimpleCursorAdapter
noteAdapter = new SimpleCursorAdapter(dbMainactivty.this,
R.layout.list_note, null, from, to);
// Set the Adapter into SimpleCursorAdapter
setListAdapter(noteAdapter);
}
// Capture ListView item click
OnItemClickListener viewNoteListener = new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// Open ViewNote activity
Intent viewnote = new Intent(dbMainactivty.this, ViewNote.class);
// Pass the ROW_ID to ViewNote activity
viewnote.putExtra(ROW_ID, arg3);
startActivity(viewnote);
}
};
#Override
protected void onResume() {
super.onResume();
// Execute GetNotes Asynctask on return to MainActivity
new GetNotes().execute((Object[]) null);
GoogleAnalytics.getInstance(dbMainactivty.this).reportActivityStart(this);
}
#Override
protected void onStop() {
Cursor cursor = noteAdapter.getCursor();
// Deactivates the Cursor
if (cursor != null)
cursor.deactivate();
noteAdapter.changeCursor(null);
super.onStop();
GoogleAnalytics.getInstance(dbMainactivty.this).reportActivityStop(this);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent i = null;
switch (item.getItemId()) {
case R.id.action_rate:
String webpage = "http://developer.android.com/index.html";
Intent intent2 = new Intent(Intent.ACTION_VIEW, Uri.parse(webpage));
startActivity(intent2);
overridePendingTransition(R.anim.slide_in, R.anim.slide_out);
case R.id.action_share:
i = new Intent();
i.setAction(Intent.ACTION_SEND);
//i.putExtra(Intent.EXTRA_TEXT, feed.getItem(pos).getTitle().toString()+ " to know the answer download http://developer.android.com/index.html");
i.setType("text/plain");
startActivity(i);
return true;
}
return super.onOptionsItemSelected(item);
};
// GetNotes AsyncTask
private class GetNotes extends AsyncTask<Object, Object, Cursor> {
DatabaseConnector dbConnector = new DatabaseConnector(dbMainactivty.this);
#Override
protected Cursor doInBackground(Object... params) {
// Open the database
dbConnector.open();
return dbConnector.ListAllNotes("maincat LIKE 'quiz' AND subcat LIKE 'test'");
}
#Override
protected void onPostExecute(Cursor result) {
noteAdapter.changeCursor(result);
// Close Database
dbConnector.close();
}
}
#Override
protected void onStart() {
super.onStart();
ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (conMgr.getActiveNetworkInfo() == null) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(
"Please check your Internet Connection.")
.setTitle("tilte")
.setCancelable(false)
.setPositiveButton("Exit",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int id) {
//loader.cancel(true);
finish();
}
});
AlertDialog alert = builder.create();
alert.show();
} else {
Cursor cursor = noteAdapter.getCursor();
if(cursor != null && cursor.getCount() > 0){
cursor.moveToFirst();
//do your action
//Fetch your data
GoogleAnalytics.getInstance(dbMainactivty.this).reportActivityStart(this);
Toast.makeText(getBaseContext(), "Yipeee!", Toast.LENGTH_SHORT).show();
}
else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(
"oops nothing pinned yet! ....")
.setTitle("title")
.setCancelable(false)
.setPositiveButton("Exit",
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int id) {
//loader.cancel(true);
finish();
}
});
AlertDialog alert = builder.create();
alert.show();
Toast.makeText(getBaseContext(), "No records yet!", Toast.LENGTH_SHORT).show();
}
}
}
}
I am trying to check
cursor != null && cursor.getCount()>0 and if it turns false then show the alert that
nothing has been pinned yet
Should show up however even though if the cursor returns data the alert still shows up.
First step, take a look at the lifecycle of your activity: http://www.android-app-market.com/wp-content/uploads/2012/03/Android-Activity-Lifecycle.png
As you can see onResume() is called after onStart() which means that checking the cursor on the onStart() can not work.
Secondly you are starting an AsyncTask (GetNotes) on the onResume() method which means you are running a parallel thread at this point and can't check for the result after calling new GetNotes().execute((Object[]) null);
Your problem is you need to check the emptiness of your cursor (cursor != null && cursor.getCount()>0) AFTER the data is loader which mean after the AsyncTask has completed. In other words, move the check for emptiness on your cursor inside the onPostExecute(Cursor result) method.