2

I am developing an android app based on GCM. The functionality is working perfectly, but I am running into an issue where when I am using the app and on the list screen, the list does not automatically refresh when the app receives a message from GCM. Notifications work fine, but I do not know how to get the message to appear in the list while I'm viewing it.

Here is my GcmBroadcastReceiver:

  public class GcmBroadcastReceiver extends BroadcastReceiver {
    static final String TAG = "GCMDemo";
    public static final int NOTIFICATION_ID = 1;
    private NotificationManager mNotificationManager;
    NotificationCompat.Builder builder;
    private MessageDatabaseHelper MDH;
    Context ctx;



    @Override
    public void onReceive(Context context, Intent intent) {
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
        ctx = context;
        String messageType = gcm.getMessageType(intent);
        if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
            try {
                sendNotification("Send error: " + intent.getExtras().toString());
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
            try {
                sendNotification("Deleted messages on server: " +
                        intent.getExtras().toString());
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else {
            try {
                if(intent.getExtras().getString("message") != null){
                    sendNotification(intent.getExtras().getString("message"));
                }
            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        setResultCode(Activity.RESULT_OK);
    }

    // Put the GCM message into a notification and post it.
    private void sendNotification(String msg) throws JSONException {
        mNotificationManager = (NotificationManager)
                ctx.getSystemService(Context.NOTIFICATION_SERVICE);



        SharedPreferences prefs1 = ctx.getSharedPreferences("UNIQUE", Context.MODE_PRIVATE);
        int unique_id = prefs1.getInt("UNIQUE_ID", 0);
        SharedPreferences.Editor editor = prefs1.edit();
        unique_id++;
        editor.putInt("UNIQUE_ID", unique_id);
        editor.commit();
        Log.v("TEST", "sharedprefs - " + prefs1.getInt("UNIQUE_ID", 0));



        JSONObject JSdata = new JSONObject(msg);

        String category = "";
        String text = "";
        String subject = "";
        String from = "";
        if(JSdata.getString("Category") != null){
            Log.v("TEST", "CATEGORY - " + JSdata.getString("Category"));
            category = JSdata.getString("Category");
        }
        if(JSdata.getString("Subject") != null){
            Log.v("TEST", "SUBJECT - " + JSdata.getString("Subject"));
            subject = JSdata.getString("Subject");
        }
        if(JSdata.getString("Message") != null){
            Log.v("TEST", "Message - " + JSdata.getString("Message"));
            text = JSdata.getString("Message");
        }
        if(JSdata.getString("From") != null){
            Log.v("TEST", "FROM - " + JSdata.getString("From"));
            from = JSdata.getString("From");
        }

        String dateTime = "";
        Time now = new Time();
        now.setToNow();
        dateTime = (now.month + 1) + "/" + now.monthDay + " " + now.hour + ":" + now.minute;
        Log.v("date", "date - " + dateTime);

        Message message = new Message(1, category, text, subject, from, dateTime);
        MDH = new MessageDatabaseHelper(ctx);
        MDH.addMessage(message);

//        new AsyncTask() {
//          @Override
//          protected String doInBackground(Object... arg0) {
//              Intent mainIntent = new Intent(ctx, MainActivity.class);
//              mainIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//              ctx.startActivity(mainIntent);
//              Log.v("GCMDEMO", "background");
//              return "";
//          }
//      }.execute(null, null, null);



        Intent gcmIntent = new Intent(ctx, MessageActivity.class);
        gcmIntent.putExtra("message1", message);

        PendingIntent contentIntent = PendingIntent.getActivity(ctx, unique_id,
                gcmIntent, PendingIntent.FLAG_CANCEL_CURRENT);


        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(ctx)
        .setSmallIcon(R.drawable.ic_launcher)
        .setContentTitle("Choice Cloud Notification")
        .setContentText(JSdata.getString("Subject") + " " + JSdata.getString("Category"))
        .setAutoCancel(true);

        NotificationCompat.InboxStyle big = new NotificationCompat.InboxStyle(
                mBuilder);
        big.setSummaryText(JSdata.getString("Subject") + " " + JSdata.getString("Category"));
        big.addLine(JSdata.getString("Message"));

        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(unique_id, big.build());


        //mBuilder.setContentIntent(contentIntent);
        //mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }
} 

And here is my MainActivity

public class MainActivity extends Activity{



private MessageDatabaseHelper MDH;
private boolean initialLaunch = false;
private StableArrayAdapter adapter;
private ListView listview;
private List<Message> mList;
private Spinner spinner;

public static final String EXTRA_MESSAGE = "message";
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";

private static final String SENDER_ID = "469307705305"; //This is the project number under the API

static final String TAG = "GCMDemo";

GoogleCloudMessaging gcm;
AtomicInteger msgId = new AtomicInteger();
SharedPreferences prefs;
Context context;

String regid;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    context = getApplicationContext();
    regid = getRegistrationId(context);

    if (regid.length() == 0) {
        registerBackground();
    }
    gcm = GoogleCloudMessaging.getInstance(this);

    spinner = (Spinner) findViewById(R.id.category_spinner);

    MDH = new MessageDatabaseHelper(this);

    //On first launch of app, add some mock messages for testing
    if(isInitialLaunch()){
        setInitialLaunch(true);

        Message m1 = new Message(1, "RateCenter", "rates are low", "Sub1", "From1", "7/31 8:45");
        MDH.addMessage(m1);

        SharedPreferences prefs1 = getSharedPreferences("UNIQUE", MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs1.edit();
        editor.putInt("UNIQUE_ID", 0);
        editor.commit();
    }

    //Message m1 = new Message(1, "RateCenter", "rates are low", "Sub1", "From1");
    //MDH.addMessage(m1);

    //Grab all categories dynamically from database
    List<String> cList = new ArrayList<String>();
    cList = MDH.getAllCategories();
    HashSet hs = new HashSet();
    hs.addAll(cList);
    cList.clear();
    cList.addAll(hs);

    //Add those categories to arraylist for use in spinner
    List<String> categories = new ArrayList<String>();
    //categories.add("Please select a category");
    categories.add("All");
    for(String s:cList){
        categories.add(s);
    }

    // Create an ArrayAdapter using the string array and a default spinner layout
    ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this,
            android.R.layout.simple_spinner_item, categories);
    // Specify the layout to use when the list of choices appears
    adapter1.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    // Apply the adapter to the spinner
    spinner.setAdapter(adapter1);
    //add onitemselected listener to spinner
    spinner.setOnItemSelectedListener(new OnItemSelectedListener(){
        public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {
            //Refresh main activity with correct set of messages pertaining to category selected
            String test1 = parent.getItemAtPosition(pos).toString();
            String test2 = MyApplication.globalCategory;
            if(!(test1.equals(test2))){
                MyApplication.sPos = pos;
                MyApplication.globalCategory = parent.getItemAtPosition(pos).toString();
                Intent intent = getIntent();
                finish();
                startActivity(intent);
            }
          }
          public void onNothingSelected(AdapterView<?> arg0) {      
          }});

    //Creates a listview to be used to store messages
    listview = (ListView) findViewById(R.id.list);
    listview.setItemsCanFocus(false);
    //grab messages from database for use in listview corresponding to category selected
    mList = new ArrayList<Message>();
    if(MyApplication.globalCategory.equals("All")){
        mList = MDH.getAllMessages();
    }
    else {
        mList = MDH.getMessagesWithCategory(MyApplication.globalCategory);
    }

    //instantiates adapter and adds it to listview
    adapter = new StableArrayAdapter(this, mList);
    listview.setAdapter(adapter);
    listview.setClickable(true);

    //adds click listener to list
    listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, final View view,
            int position, long id) {

            Log.v("GCMDemo", "Registration id is - " + getRegistrationId(MainActivity.this));
            Message clickedMessage = (Message)parent.getItemAtPosition(position);
            clickedMessage.setUnread(false);
            MDH.updateUnread(clickedMessage);

            //starts new messageactivity, passing the message clicked on as an extra to the intent
            listview.invalidateViews();
            Intent startMessageActivityIntent = new Intent();
            startMessageActivityIntent.putExtra("message1", clickedMessage);
            startMessageActivityIntent.setClass(MainActivity.this,
                    MessageActivity.class);
            startActivity(startMessageActivityIntent);
            finish();
        }
      });
}


@SuppressWarnings("unchecked")
private void registerBackground() {
    new AsyncTask() {
        @Override
        protected String doInBackground(Object... arg0) {
            String msg = "";
            try {
                if (gcm == null) {
                    gcm = GoogleCloudMessaging.getInstance(context);
                }
                regid = gcm.register(SENDER_ID);
                msg = "Device registered, registration id=" + regid;
                // Save the regid - no need to register again.
                setRegistrationId(context, regid);
            } catch (IOException ex) {
                msg = "Error :" + ex.getMessage();
            }
            Log.v("GCMDEMO", "GCMWHAT - " + msg);
            return msg;
        }
    }.execute(null, null, null);
}



 private void setRegistrationId(Context context, String regid) {
     final SharedPreferences prefs = getGCMPreferences(context);
        int appVersion = getAppVersion(context);
        Log.v(TAG, "Saving regId on app version " + appVersion);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(PROPERTY_REG_ID, regid);
        editor.putInt(PROPERTY_APP_VERSION, appVersion);
        editor.commit();    
}


private String getRegistrationId(Context context) {
    final SharedPreferences prefs = getGCMPreferences(context);
    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
    if (registrationId.length() == 0) {
        Log.v(TAG, "Registration not found.");
        return "";
    }
    // check if app was updated; if so, it must clear registration id to
    // avoid a race condition if GCM sends a message
    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
    int currentVersion = getAppVersion(context);
    if (registeredVersion != currentVersion) {
        Log.v(TAG, "App version changed");
        return "";
    }
    return registrationId;
}

private int getAppVersion(Context context2) {
    try {
        PackageInfo packageInfo = context.getPackageManager()
                .getPackageInfo(context.getPackageName(), 0);
        return packageInfo.versionCode;
    } catch (NameNotFoundException e) {
        // should never happen
        throw new RuntimeException("Could not get package name: " + e);
    }
}


private SharedPreferences getGCMPreferences(Context context2) {
    return getSharedPreferences(MainActivity.class.getSimpleName(), 
            Context.MODE_PRIVATE);
}


private class StableArrayAdapter extends ArrayAdapter<Message> {
    //adapter class for use with listview, maps items to positions
    //HashMap<Message, Integer> hMap = new HashMap<Message, Integer>();
    private final Context context1;
    private final List<Message> adaptList;


    public StableArrayAdapter(Context cont,
        List<Message> objects) {
      super(context, R.layout.ccm_list_item, objects);
     //for (int i = 0; i < objects.size(); i++) {
     //   hMap.put(objects.get(i), i);
      //}
      this.context1 = cont;
      this.adaptList = new ArrayList<Message>();
      this.adaptList.addAll(objects);
    }

    private class ViewHolder {
          public TextView text;
          public TextView text2;
          public TextView textTime;
          public CheckBox checkBox;
        }

    @Override
    public boolean hasStableIds() {
      return true;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent){
        ViewHolder holder = null;
        Log.v("ConvertView", String.valueOf(position));


        if (convertView == null) {
            LayoutInflater vi = (LayoutInflater)getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
            convertView = vi.inflate(R.layout.ccm_list_item, null);
            holder = new ViewHolder();
            LayoutInflater inflater = (LayoutInflater) context1
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            holder.text = (TextView) convertView.findViewById(R.id.rowText);
            holder.text2 = (TextView) convertView.findViewById(R.id.rowText2);
            holder.textTime = (TextView) convertView.findViewById(R.id.rowTextTime);
            holder.checkBox = (CheckBox) convertView
                    .findViewById(R.id.listCheck);
            holder.checkBox.setFocusable(false);
            holder.checkBox.setFocusableInTouchMode(false);

            convertView.setTag(holder);

            holder.checkBox.setOnClickListener(new View.OnClickListener() { 
                public void onClick(View v) { 
                    CheckBox cb = (CheckBox) v; 
                    Message message = (Message)cb.getTag(); 
                    Toast.makeText(getApplicationContext(),
                            "Clicked on Checkbox: " + cb.getText() +
                            " is " + cb.isChecked(),
                            Toast.LENGTH_LONG).show();
                    //country.setSelected(cb.isChecked());
                } 
            }); 
        }
        else {
            holder = (ViewHolder) convertView.getTag();
        }


        int count = 0;
        Message m1 = new Message();
        if(MyApplication.globalCategory.equals("All")){
            mList = MDH.getAllMessages();
            for (Message m: mList) {
              if(count == position){
                  m1 = m;
              }
              count++;
            }
        }
        else {
            mList = MDH.getMessagesWithCategory(MyApplication.globalCategory);
            for (Message m: mList) {
                  if(count == position){
                      m1 = m;
                  }
                  count++;
                }
        }

        if (m1.getUnread() == false) {
            holder.text.setText(m1.toString());
            holder.text2.setText(m1.getText());
            holder.textTime.setText(m1.getTime());
          convertView.setBackgroundColor(Color.LTGRAY);
        } else {
            holder.text.setText(m1.toString());
            holder.text2.setText(m1.getText());
            holder.textTime.setText(m1.getTime());
            convertView.setBackgroundColor(Color.WHITE);
            holder.text.setTypeface(null, Typeface.BOLD);
            holder.text2.setTypeface(null, Typeface.BOLD);
        }
        holder.checkBox.setFocusable(false);
        holder.checkBox.setFocusableInTouchMode(false);
        holder.text.setFocusable(false);
        holder.text.setFocusableInTouchMode(false);



        ((ViewGroup) convertView).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);


        return convertView;

    }

  }

public void setInitialLaunch(boolean initialLaunch) {
    SharedPreferences settings = getSharedPreferences("APPLAUNCH", 0);
    SharedPreferences.Editor editor = settings.edit();
    editor.putBoolean("APPLAUNCHKEY", false);
    editor.commit();
    this.initialLaunch = initialLaunch;
}

public boolean isInitialLaunch() {
    SharedPreferences settings = getSharedPreferences("APPLAUNCH", 0);
    this.initialLaunch = settings.getBoolean("APPLAUNCHKEY", true);
    return initialLaunch;
}

@Override
protected void onStart() {
    //on start, grabs message from database and updates adapter with changes to data
    super.onStart();
    if(MyApplication.globalCategory.equals("All")){
        mList = MDH.getAllMessages();
        for (Message m: mList) {
        }
    }
    else {
        mList = MDH.getMessagesWithCategory(MyApplication.globalCategory);
        for (Message m: mList) {
        }
    }
    MainActivity.this.runOnUiThread(new Runnable() {         
        public void run() {
            adapter.notifyDataSetChanged() ; 
        }
    });
    spinner.setSelection(MyApplication.sPos);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    super.onCreateOptionsMenu(menu);
    return true;
}

//option item about added to menu and starts aboutactivity when selected
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.action_settings) {
        Intent startActivityIntent = new Intent(this,
                AboutActivity.class);
        startActivity(startActivityIntent);
        return true;
    }
    return true;
}

}

superdiazepam
  • 457
  • 5
  • 13
  • I can see that you are using `notifyDataSetChanged()` in your `onStart()` of `MainActivity` to populate the list the first time. Could be that I'm missing something, but when you get your message, are you updating the dataset that the list adapter is referencing and then calling `notifyDataSetChanged()`? – CodeMonkey Aug 02 '13 at 00:51
  • I do not...I'm not sure how to call that method from GcmBroadcastReceiver, which is where I actually receive my notifications. – superdiazepam Aug 02 '13 at 16:43
  • There is a great answer [here](http://stackoverflow.com/a/7282739/716588) from @CommonsWare about the ways to interact between `BroadcastReceivers` and `Activities`. There are a couple of things to take into consideration such as the instance where the Activity is destroyed and the BroadcastReceiver is trying to access it, but have a look at that link and see if the answer there helps! – CodeMonkey Aug 05 '13 at 07:00

0 Answers0