0

I am working on a project where user adds data at runtime.I am using cursorloader to load the data content provider to add data to database and customadapter to set the data to recyclerview.The problem is whenever user inserts new data the data is adding to the database but it is not updating in the recyclerview.

Method addDetails(View view) executes when user enters data

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(2,null,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);
        getContentResolver().insert(DataProvider.ContentUri_Details,contentValues);
        adapter.notifyDataSetChanged();
        Toast.makeText(AddLog.this, DataProvider.Per_In, 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 uri = DataProvider.ContentUri_Person+"/"+logid;
            Uri uri1 = Uri.parse(uri);
            getContentResolver().update(uri1,values,null,null);
            startActivity(returnback);
            finish();
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(final int id, Bundle args)
    {
        String _uri = DataProvider.ContentUri_Details+"/"+logid;
        Uri uri = Uri.parse(_uri);
        return new CursorLoader(this,uri,new String[]{DataProvider.Dname,DataProvider.Damount,DataProvider.Ddate},null,null,null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data)
    {
        adapter = new DetailsAdapter(this,data);
        adddetailtolist.setAdapter(adapter);
        adddetailtolist.setLayoutManager(new LinearLayoutManager(this));
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {

    }
}

Custom Cursor Adapter:

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

Adapter class

public class DetailsAdapter extends CursorRecyclerViewAdapter<DetailsAdapter.View_Holder>
{

    public DetailsAdapter(Context context, Cursor cursor) {
        super(context, cursor);
    }
    public static class View_Holder extends RecyclerView.ViewHolder
    {
        TextView mName,mAmount,mDate;
        public View_Holder(View itemView)
        {
            super(itemView);
            mName = (TextView)itemView.findViewById(R.id.DetailName);
            mAmount = (TextView)itemView.findViewById(R.id.DetailAmount);
            mDate = (TextView)itemView.findViewById(R.id.DetailDate);
        }
    }
    @Override
    public DetailsAdapter.View_Holder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.addloglistlayout,parent,false);
        View_Holder viewHolder = new View_Holder(view);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(DetailsAdapter.View_Holder viewHolder, Cursor cursor)
    {
        Details details = Details.from(cursor);
        viewHolder.mName.setText(details.getName());
        viewHolder.mAmount.setText(String.valueOf(details.getAmount()));
        viewHolder.mDate.setText(details.getDate());
    }
}

Content Provider :

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;
    public static long logid = 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,"_ID");
        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");
    }
}

Thank you

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

1 Answers1

0

The problem is in next. During update of the data in ContentProvider, you send notification:

getContext().getContentResolver().notifyChange(uri,null);

But you didn't listen for the changes. See more information here: How do CursorLoader automatically updates the view even if the app is inactive?

Community
  • 1
  • 1
Alex
  • 617
  • 4
  • 15