Search code examples
androidandroid-contentproviderandroid-cursorloader

Contentent Provider urimatching CASE statement getting called twice


I am updating my app to use a Content Provider and a CursorLoader in place of using startManagingCursor.

I have 2 tables in my sqlite database, table errors and table messages. When i start the activities that show the contents of these tables in a listview, everything seems to work fine.

One thing i have noticed is that when i call the viewMessages Activity the Case statement that is matching the URI in the content provider is getting called twice.

This does not happen when a call viewPhoneNumbers activity.

It seems like i am calling the following twice

cursorLoader = new CursorLoader(this, RR3ContentProvider.CONTENT_URI_MESSAGES, projection, null, null, null);

I'll show the logging statements first so you can see what i mean. It logs 'CASE Messages' twice, but when i do the same for the phone table it just logs 'Case PHONES' only once, which i think it should only do it once.

Can anyone tell me why the CASE MESSAGES is executing twice?

07-22 10:17:11.845: E/ViewMessagesActivityAsync(10808): inside ViewMessagesActivityAsync oncreate
07-22 10:17:11.845: E/RR3ContentProvider(10808): inside RR3ContentProvider query method
07-22 10:17:11.845: E/RR3ContentProvider(10808): CASE MESSAGES
07-22 10:17:11.845: E/RR3ContentProvider(10808): About to do the query method in content provider
07-22 10:17:11.855: E/ViewMessagesActivityAsync(10808): inside3 onCreateLoader in ViewMessagesActivityAsync
07-22 10:17:11.855: E/RR3ContentProvider(10808): inside RR3ContentProvider query method
07-22 10:17:11.855: E/RR3ContentProvider(10808): CASE MESSAGES
07-22 10:17:11.855: E/RR3ContentProvider(10808): About to do the query method in content provider
07-22 10:17:11.915: V/PhoneStatusBar(1219): setLightsOn(true)
07-22 10:17:11.945: E/ViewMessagesActivityAsync(10808): inside myadapter getview for messages
07-22 10:17:11.945: E/ViewMessagesActivityAsync(10808): (Cursor)getItem(position) = android.content.ContentResolver$CursorWrapperInner@67a0e5b8position = 0
07-22 10:17:11.945: E/ViewMessagesActivityAsync(10808): inside myadapter getview for messages
07-22 10:17:11.945: E/ViewMessagesActivityAsync(10808): (Cursor)getItem(position) = android.content.ContentResolver$CursorWrapperInner@67a0e5b8position = 1
07-22 10:17:11.955: E/ViewMessagesActivityAsync(10808): inside myadapter getview for messages
07-22 10:17:11.955: E/ViewMessagesActivityAsync(10808): (Cursor)getItem(position) = android.content.ContentResolver$CursorWrapperInner@67a0e5b8position = 2

.

07-22 10:17:21.345: E/ViewPhoneNumberAsync(10808): inside ViewPhoneNumberAsync onCreate
07-22 10:17:21.345: E/RR3ContentProvider(10808): inside RR3ContentProvider query method
07-22 10:17:21.345: E/RR3ContentProvider(10808): CASE PHONES
07-22 10:17:21.345: E/RR3ContentProvider(10808): About to do the query method in content provider
07-22 10:17:21.405: V/PhoneStatusBar(1219): setLightsOn(true)
07-22 10:17:21.425: E/ViewPhoneNumberAsync(10808): inside myadapter getview
07-22 10:17:21.435: E/ViewPhoneNumberAsync(10808): inside myadapter getview

. ViewPhoneNumberAsync

public class ViewPhoneNumberAsync extends Activity implements LoaderCallbacks<Cursor>  {

    ListView listView;
    MyAdapter mAdapter;         
    LoaderManager loadermanager;        
    CursorLoader cursorLoader;
    private static final String TAG = ViewPhoneNumberAsync.class.getSimpleName();
    final String               BACKPRESS_ACTION = "com.carefreegroup.rr3.BACKPRESS_ACTION";
    private final String TABLEPHONE = "phone";

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Log.e(TAG, "inside ViewPhoneNumberAsync onCreate");

        loadermanager=getLoaderManager();

           // setup UI
            setContentView(R.layout.viewphonenumbers);

            //transactionCount = (TextView)findViewById(R.id.textviewtransactionsfordaycount);
            listView = (ListView) findViewById(R.id.listviewphonenumbers);

            String[] from = { LoginValidate.C_PHONE_NAME, LoginValidate.C_PHONE_NUMBER};
            int[] to = { R.id.phonename, R.id.phonenumber };

//      String[] uiBindFrom = {  TABLEPHONE};       
//      int[] uiBindTo = {android.R.id.text1};

            /*Empty adapter that is used to display the loaded data*/
        mAdapter = new MyAdapter(this, R.layout.rowphonenumbers, null, from, to,0);  
        listView.setAdapter(mAdapter);
        listView.setOnItemClickListener(mAdapter);


       loadermanager.initLoader(1, null, this);
   }


   public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {

    String[] projection = { LoginValidate.C_ID_PHONE, LoginValidate.C_PHONE_NAME, LoginValidate.C_PHONE_NUMBER };


    cursorLoader = new CursorLoader(this, RR3ContentProvider.CONTENT_URI_PHONE_NUMBERS, projection, null, null, null);
    return cursorLoader;

   }



   public void onLoadFinished(Loader<Cursor> loader,Cursor cursor) {
    if(mAdapter!=null && cursor!=null)
        mAdapter.swapCursor(cursor); //swap the new cursor in.
    else
        Log.v(TAG,"OnLoadFinished: mAdapter is null");
   }



   public void onLoaderReset(Loader<Cursor> arg0) {
    if(mAdapter!=null)
        mAdapter.swapCursor(null);
    else
        Log.v(TAG,"OnLoadFinished: mAdapter is null");
   }



   @Override
    public void onBackPressed() {
        super.onBackPressed();
        Intent i = new Intent(this, NfcscannerActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
        //i.setAction(QRCODE_ACTION);
        i.setAction(BACKPRESS_ACTION);
        startActivity(i); 
    }


    private class MyAdapter extends SimpleCursorAdapter implements OnItemClickListener {

        public MyAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
            super(context, layout, c, from, to, flags);


        }

.

ViewMessagesAsync

public class ViewMessagesActivityAsync extends Activity implements LoaderCallbacks<Cursor>{

    private static final String TAG = ViewMessagesActivityAsync.class.getSimpleName(); 
    final String               BACKPRESS_ACTION = "com.carefreegroup.rr3.BACKPRESS_ACTION";

    NfcScannerApplication nfcscannerapplication;
    Cursor cursorMessages;
    ListView listView;
    SimpleCursorAdapter adapter;
    MyAdapter myAdapter;
    TextView noMessages;
    ArrayList<String> guidArray;

    LoaderManager loadermanager;        
    CursorLoader cursorLoader;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Log.e(TAG, "inside ViewMessagesActivityAsync oncreate");

        setContentView(R.layout.viewmessages);

        nfcscannerapplication = (NfcScannerApplication) getApplication();

        loadermanager=getLoaderManager();

        guidArray = new ArrayList<String>();






            listView = (ListView) findViewById(R.id.listviewmessages);

            noMessages = (TextView)findViewById(R.id.textviewnomessageslabel);




            cursorMessages = getContentResolver().query(RR3ContentProvider.CONTENT_URI_MESSAGES, null, null, null, null);

            if(cursorMessages.getCount() == 0){


                noMessages.setVisibility(View.VISIBLE);
                listView.setVisibility(View.GONE);

            }else{

                listView.setVisibility(View.VISIBLE);
                noMessages.setVisibility(View.GONE);

            }






            String[] from = { LoginValidate.C_MESSAGE_CREATED_AT, LoginValidate.C_MESSAGE_TEXT, LoginValidate.C_MESSAGE_SENDER};
            int[] to = { R.id.messagecreatedat, R.id.messagetext, R.id.messagesender};

            myAdapter = new MyAdapter(nfcscannerapplication, R.layout.rowmessages, null, from, to, 0);
            listView.setAdapter(myAdapter);
            listView.setOnItemClickListener(myAdapter);

             loadermanager.initLoader(1, null, this);

    }//end of onCreate







@Override
    protected void onResume() {
        super.onResume();


    }




private class MyAdapter extends SimpleCursorAdapter implements OnItemClickListener {


    Cursor c;
    String messageGuid;


        public MyAdapter(Context context, int layout, Cursor c, String[] from,
                int[] to, int flags) {
            super(context, layout, c, from, to, flags);


        }









@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    Log.e(TAG, "inside3 onCreateLoader in ViewMessagesActivityAsync");




    String[] projection = { LoginValidate.C_ID_MESSAGE,LoginValidate.C_MESSAGE_GUID,LoginValidate.C_MESSAGE_CREATED_AT, LoginValidate.C_MESSAGE_TEXT, 
                            LoginValidate.C_MESSAGE_SENDER , LoginValidate.C_MESSAGE_REPLIED, LoginValidate.C_MESSAGE_SEEN, LoginValidate.C_MESSAGE_DISPLAYED,
                             LoginValidate.C_MESSAGE_REPLY_MESSAGE, LoginValidate.C_MESSAGE_IS_STANDALONE};


    cursorLoader = new CursorLoader(this, RR3ContentProvider.CONTENT_URI_MESSAGES, projection, null, null, null);
    return cursorLoader;
}







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

    if(myAdapter!=null && cursor!=null)
        myAdapter.swapCursor(cursor); //swap the new cursor in.
    else
        Log.v(TAG,"OnLoadFinished: mAdapter is null");

}







@Override
public void onLoaderReset(Loader<Cursor> arg0) {
    if(myAdapter!=null)
        myAdapter.swapCursor(null);
    else
        Log.v(TAG,"OnLoadFinished: mAdapter is null");

}



}

ContentProvider

public class RR3ContentProvider extends ContentProvider {

   private static final String TAG = RR3ContentProvider.class.getSimpleName();
   NfcScannerApplication nfcAppObj; 

   static final String PROVIDER_NAME = "com.carefreegroup.rr3.ContentProvider";
   static final String URLPHONENUMBERS = "content://" + PROVIDER_NAME + "/phonenumbers";
   static final Uri CONTENT_URI_PHONE_NUMBERS = Uri.parse(URLPHONENUMBERS);


   static final String _ID_PHONENUMBERS = "_id";
   static final String PHONE_NAME = "phonename";
   static final String PHONE_NUMBER = "phonenumber";

   static final String TABLEPHONE = "phone";

   private static HashMap<String, String> PHONE_PROJECTION_MAP;

   static final int PHONES = 1;
   static final int PHONE_ID = 2;


   static final String URLMESSAGES = "content://" + PROVIDER_NAME + "/messages";
   static final Uri CONTENT_URI_MESSAGES = Uri.parse(URLMESSAGES);


   static final String _ID_MESSAGES = "_id";
   static final String MESSAGE_CREATED_AT = "messagecreatedat";
   static final String MESSAGE_TEXT = "messagetext";
   static final String MESSAGE_SENDER = "messagesender";

   static final String TABLEMESSAGE = "message";

   private static HashMap<String, String> MESSAGE_PROJECTION_MAP;

   static final int MESSAGES = 3;
   static final int MESSAGE_ID = 4;


   static final UriMatcher uriMatcher;
   static{
      uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
      uriMatcher.addURI(PROVIDER_NAME, "phonenumbers", PHONES);
      uriMatcher.addURI(PROVIDER_NAME, "phonenumbers/#", PHONE_ID);
      uriMatcher.addURI(PROVIDER_NAME, "messages", MESSAGES);
      uriMatcher.addURI(PROVIDER_NAME, "messages/#", MESSAGE_ID);
   }

   /**
    * Database specific constant declarations
    */
   private SQLiteDatabase db;


   @Override
   public boolean onCreate() {
      Context context = getContext();
      nfcAppObj = (NfcScannerApplication) getContext();

      Log.e(TAG, "inside RR3ContentProvider onCreate");
      return (nfcAppObj == null)? false:true;
   }

   @Override
   public Uri insert(Uri uri, ContentValues values) {

       db = nfcAppObj.getDb();
      /**
       * Add a new student record
       */
      long rowID = db.insert(   TABLEPHONE, "", values);
      /** 
       * If record is added successfully
       */
      if (rowID > 0)
      {
         Uri _uri = ContentUris.withAppendedId(CONTENT_URI_PHONE_NUMBERS, rowID);
         getContext().getContentResolver().notifyChange(_uri, null);
         return _uri;
      }
      throw new SQLException("Failed to add a record into " + uri);
   }

   @Override
   public Cursor query(Uri uri, String[] projection, String selection,  
                       String[] selectionArgs, String sortOrder) {

       Log.e(TAG, "inside RR3ContentProvider query method");

       db = nfcAppObj.getDb();

      SQLiteQueryBuilder qb = new SQLiteQueryBuilder();


      switch (uriMatcher.match(uri)) {
      case PHONES:
          Log.e(TAG, "CASE PHONES");
          qb.setTables(TABLEPHONE);
          qb.setProjectionMap(PHONE_PROJECTION_MAP);
         break;

      case PHONE_ID:
          Log.e(TAG, "CASE PHONE_ID");
          qb.setTables(TABLEPHONE);
          qb.appendWhere( _ID_PHONENUMBERS + "=" + uri.getPathSegments().get(1));
         break;


      case MESSAGES:
          Log.e(TAG, "CASE MESSAGES");
          qb.setTables(TABLEMESSAGE);
          qb.setProjectionMap(MESSAGE_PROJECTION_MAP);
         break;

      case MESSAGE_ID:
          Log.e(TAG, "CASE MESAAGE_ID");
          qb.setTables(TABLEMESSAGE);
          qb.appendWhere( _ID_MESSAGES + "=" + uri.getPathSegments().get(1));
         break;

      default:

         throw new IllegalArgumentException("Unknown URI " + uri);
      }



      switch (uriMatcher.match(uri)) {
      case PHONES:

          if (sortOrder == null || sortOrder == ""){

                 sortOrder = PHONE_NAME;
              }

         break;

      case PHONE_ID:

          if (sortOrder == null || sortOrder == ""){

                 sortOrder = PHONE_NAME;
              }

         break;


      case MESSAGES:

          if (sortOrder == null || sortOrder == ""){

                 sortOrder = MESSAGE_CREATED_AT + " DESC";
              }

         break;

      case MESSAGE_ID:

          if (sortOrder == null || sortOrder == ""){

                 sortOrder = MESSAGE_CREATED_AT + " DESC";
              }

         break;

      default:

         throw new IllegalArgumentException("Unknown URI " + uri);
      }

      Log.e(TAG, "About to do the query method in content provider");

      Cursor c = qb.query(db,   projection, selection, selectionArgs, 
                          null, null, sortOrder);
      /** 
       * register to watch a content URI for changes
       */
      c.setNotificationUri(getContext().getContentResolver(), uri);

      return c;

   }//end of query





   @Override
   public int delete(Uri uri, String selection, String[] selectionArgs) {

       db = nfcAppObj.getDb();

      int count = 0;

      switch (uriMatcher.match(uri)){
      case PHONES:
         count = db.delete(TABLEPHONE, selection, selectionArgs);
         break;
      case PHONE_ID:
         String id = uri.getPathSegments().get(1);
         count = db.delete( TABLEPHONE, _ID_PHONENUMBERS +  " = " + id + 
                (!TextUtils.isEmpty(selection) ? " AND (" + 
                selection + ')' : ""), selectionArgs);
         break;

      case MESSAGES:
          count = db.delete(TABLEMESSAGE, selection, selectionArgs);
          break;
       case MESSAGE_ID:
          String id2 = uri.getPathSegments().get(1);
          count = db.delete( TABLEMESSAGE, _ID_MESSAGES +  " = " + id2 + 
                 (!TextUtils.isEmpty(selection) ? " AND (" + 
                 selection + ')' : ""), selectionArgs);
          break;
      default: 
         throw new IllegalArgumentException("Unknown URI " + uri);
      }

      getContext().getContentResolver().notifyChange(uri, null);
      return count;
   }






   @Override
   public int update(Uri uri, ContentValues values, String selection, 
                     String[] selectionArgs) {

       db = nfcAppObj.getDb();

      int count = 0;

      switch (uriMatcher.match(uri)){
      case PHONES:
         count = db.update(TABLEPHONE, values, 
                 selection, selectionArgs);
         break;
      case PHONE_ID:
         count = db.update(TABLEPHONE, values, _ID_PHONENUMBERS + 
                 " = " + uri.getPathSegments().get(1) + 
                 (!TextUtils.isEmpty(selection) ? " AND (" +
                 selection + ')' : ""), selectionArgs);
         break;

      case MESSAGES:
          count = db.update(TABLEMESSAGE, values, 
                  selection, selectionArgs);
          break;
       case MESSAGE_ID:
          count = db.update(TABLEMESSAGE, values, _ID_MESSAGES + 
                  " = " + 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;
   }//end of delete






   @Override
   public String getType(Uri uri) {
      switch (uriMatcher.match(uri)){
      /**
       * Get all  records 
       */
      case PHONES:
         return "vnd.android.cursor.dir/vnd.example.phonenumbers";
      /** 
       * Get a particular record
       */
      case PHONE_ID:
         return "vnd.android.cursor.item/vnd.example.phonenumbers";

         /**
          * Get all  records 
          */
         case MESSAGES:
            return "vnd.android.cursor.dir/vnd.example.messages";
         /** 
          * Get a particular record
          */
         case MESSAGE_ID:
            return "vnd.android.cursor.item/vnd.example.messages";
      default:
         throw new IllegalArgumentException("Unsupported URI: " + uri);
      }
   }
}

Solution

  • SOLVED

    My appologies, i make an extra call to the content provider passing in

    RR3ContentProvider.CONTENT_URI_MESSAGES
    

    in the viewMessagesAsync Activity. This is to get the count of the messages, where i can switch views if there are no messages. i don't do this in the ViewPhoneNumbers Activity.