2

I have read following links for updating data when database get changed.

So It's successfully done with ContentObserver and my Fragment get notified with that and I have updated RecyclerView by following way.

/**
 * A simple {@link Fragment} subclass.
 */
public class OrderListFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {

    /**
     * Cursor Loader ID
     */
    private int LOADER_ID = 2;

    /**
     * Observer...
     */
    OrderObserver orderObserver = null;

    @Override
    public void onResume() {
        super.onResume();
        /**
         * Observer Declaration...
         */
        orderObserver = new OrderObserver(new Handler());
        LOGD("Registered......");
        getActivity().getContentResolver().registerContentObserver(KOOPSContentProvider.CONTENT_URI_ORDER, true, orderObserver);
    }

    @Override
    public void onPause() {
        super.onPause();
        if (orderObserver != null) {
            LOGD("Unregistered...");
            getActivity().getContentResolver().unregisterContentObserver(orderObserver);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_order_list, container, false);

        orderListBinding = DataBindingUtil.bind(view);

        /**
         * Getting Context
         */
        mContext = getActivity().getApplicationContext();

        /**
         * Setup with RecyclerView
         */
        layoutManager = new HPLinearLayoutManager(mContext);

        /**
         * Adapter...
         */
        orderListAdapter = new OrderRecyclerAdapter(mContext, orderCursor);

        /**
         * RecyclerView Binding
         */
        orderListBinding.orderListRecyclerView.setLayoutManager(layoutManager);
        orderListBinding.orderListRecyclerView.setHasFixedSize(true);
        orderListBinding.orderListRecyclerView.setAdapter(orderListAdapter);

        /**
         * First Time init Loader
         */
        orderQueryData = new Bundle();
        orderQueryData.putString("searchString", "");

        /**
         * Adding Bundle in Loader and then Call
         */
        getActivity().getSupportLoaderManager().initLoader(LOADER_ID, orderQueryData, this);

        /*********************************/
        // Inflate the layout for this fragment
        return view;
    }



    /**
     * Get Data From Local
     */
    private void getDataFromLocal() {
        /**
         * Adding Bundle in Loader and then Call
         */
        getActivity().getSupportLoaderManager().restartLoader(LOADER_ID, orderQueryData, this);
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        final Uri CONTENT_URI = KOOPSContentProvider.CONTENT_URI_ORDER.buildUpon()
                .appendQueryParameter(KOOPSContentProvider.QUERY_PARAMETER_OFFSET, String.valueOf(offset))
                .build();

        return new CursorLoader(mContext, CONTENT_URI, null, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

        int length = data.getCount();

        LOGD("Length of Orders in Local : " + length);

            /***
             * Binding Data to Adapter
             * OFFSET is 0 whenever search for orders of sync
             */
            if (offset == 0) {
                ((OrderRecyclerAdapter) orderListBinding.orderListRecyclerView.getAdapter()).swapCursor(data);
            } else {
                Cursor cursor = ((OrderRecyclerAdapter) orderListBinding.orderListRecyclerView.getAdapter()).getCursor();

                //fill all existing in adapter
                ArrayList<String> first = new ArrayList<>(Arrays.asList(Order.ORDER_COLUMNS));
                first.add("amount");

                MatrixCursor mx = new MatrixCursor(first.toArray(new String[first.size()]));
                fillMx(cursor, mx);

                //fill with additional result
                fillMx(data, mx);
                ((OrderRecyclerAdapter) orderListBinding.orderListRecyclerView.getAdapter()).swapCursor(mx);
            }

            /**
             * Check Length of Data from Local
             */

    }

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

    }

    /**
     * Merging New Cursor with Old Cursor...
     *
     * @param data data
     * @param mx   matrix cursor
     */
    private void fillMx(Cursor data, MatrixCursor mx) {
        if (data == null)
            return;

        data.moveToPosition(-1);

        while (data.moveToNext()) {
            mx.addRow(new Object[]{

                    data.getString(data.getColumnIndex(MOBILE_ID)),
                    data.getString(data.getColumnIndex(SERVER_ID)),
                    data.getString(data.getColumnIndex(ORDER_ORDER_DATE)),
                    data.getString(data.getColumnIndex(ORDER_ACCOUNT_ID)),
                    data.getString(data.getColumnIndex(ORDER_CREATED_BY)),
                    data.getString(data.getColumnIndex(ORDER_ORDER_STATUS)),
                    data.getString(data.getColumnIndex(ORDER_SEEN)),
                    data.getString(data.getColumnIndex(ORDER_ITP)),
                    data.getString(data.getColumnIndex(ORDER_UTP)),
                    data.getString(data.getColumnIndex(ORDER_MITP)),
                    data.getString(data.getColumnIndex("amount")),
            });
        }
    }

    /**
     * My Observer....
     */
    class OrderObserver extends ContentObserver {

        /**
         * Creates a content observer.
         *
         * @param handler The handler to run {@link #onChange} on, or null if none.
         */
        OrderObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            this.onChange(selfChange, null);
            LOGD("Changed.....");
            // Override this method to listen to any changes
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            // depending on the handler you might be on the UI
            // thread, so be cautious!
            LOGD("Changed....." + uri);
            offset = 0;
            hasLocal = true;
            getDataFromLocal();

            // HERE I WANT TO DO SOMETHING LIKE CHANGE VALUES ONLY WHICH ROW IS UPDATED......
            // HOW CAN I UPDATE ROW ONLY......

        }
    }
}

Currently What I am doing updating all records from database? How can I update row which is inserted/updated in database. I dont want to refresh whole RecyclerView?

Is there any mechanism to notify only updated row in ContentObserver?

Community
  • 1
  • 1
Pratik Butani
  • 60,504
  • 58
  • 273
  • 437

1 Answers1

1

In your onChange method you get a Uri parameter that is meant to identify what has changed.

If your content provider is correctly done, the Uri should identify uniquely what has changed. For instance if you have a table items and receive the uri content://com.application.sample/items/42, then you know that it's item #42 which has changed.

If you can modify you Content Provider, you could go even further and have different Uris to know what the change is :

  • content://com.application.sample/items/42/deleted
  • content://com.application.sample/items/42/inserted
  • content://com.application.sample/items/42/updated

Using those you can trigger the relevant notify??? methods on your adapter.

XGouchet
  • 10,002
  • 10
  • 48
  • 83