Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Android Build a Self-Destructing Message Android App Retrieving and Viewing Messages Retrieving Messages

Chris Esser
Chris Esser
2,241 Points

Refresh the Inbox - Ribbit

I haven't been able to figure out how to refresh the inbox messages if one gets sent to me while I have the app open. If I add a refresh button to the Over Flow menu, that onOptionsItemSelected() method only applies to the MainActivity, not to the fragments housed in the MainActivity.

Has anyone figured out how to trigger an action in the InboxFragment from the MainActivity's overflow menu?

3 Answers

This is how I did it:

1) Modify SectionsPagerAdapter to store the InboxFragment as a local member variable that is created in the constructor and then returned by getItem e.g.

class SectionsPagerAdapter extends FragmentPagerAdapter {

    private final Context mContext;
    private InboxFragment mInboxFragment;

    public SectionsPagerAdapter(Context context, FragmentManager fm) {
        super(fm);
        mContext = context;
        mInboxFragment = new InboxFragment();
    }

    @Override
    public Fragment getItem(int position) {
        // getItem is called to instantiate the fragment for the given page.
        // Return a MainActivityFragment (defined as a static inner class below).
        switch(position) {
            case 0:
                return mInboxFragment;
            case 1:
                return new FriendsFragment();
        }
        return null;
    }

2) Add the following method to MainActivity:

    protected void updateInboxFragment() {
        SectionsPagerAdapter adapter = (SectionsPagerAdapter) mViewPager.getAdapter();
        ((InboxFragment)adapter.getItem(0)).refreshInboxList();
    }

3) Call the new updateInboxFragment() method from the onOptionsItemSelected() method.

4) In the InboxFragment I can't remember if the refreshInboxList() was part of the tutorial or not, however it is basically the code that is run within onResume() (I may have refactored it out to this method).

Hope that makes sense. I don't know if its the best method, however it works for me. And, I recommend using the Push notification from Parse. It works well for updating and does it automatically without requiring a manual refresh.

Chris Esser
Chris Esser
2,241 Points

Thanks, I followed that outline and it worked!

I agree that using the push notifications would be better. I played around with them and now I can send and receive push notifications in the app (Following the documentation on Parse). By default, the pushes showed up in the notification bar, and I could launch an activity by clicking on them.

I wanted to make it so every time a message is received, the inbox updates automatically, even if I have it open and am viewing it. So I set the pushes up to use a custom receiver and not show up in the notification bar. The custom receiver is working (I can run a Log() command to see that i'm getting a message) but I haven't figured out how to use that custom receiver to trigger an update on the InboxFragment (or any other activity, since I can now communicate between all of them thanks to your previous answer).

How did you end up using the Push Notifications?

Aha!

That is exactly what I wanted to do. I did it this way... Add this method to your MainActivity.

    protected BroadcastReceiver parsePushBroadcastReceiver;
    private void registerForPushNotifications() {

        // Change the MyTeam to be your channel identifier
        PushService.subscribe(this, "MyTeam", MainActivity.class);

        // Create an intent filter for Push notification
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.google.android.c2dm.intent.RECEIVE");

        parsePushBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updateInboxFragment();
            }
        };
        registerReceiver(parsePushBroadcastReceiver, intentFilter);
    }

Then call this in your onResume() and add unregisterReceiver(parsePushBroadcastReceiver); to onPause().

I take it you stop the notification by using the call to abortBroadcast() in the broadcast receiver? I should probably do the same, although what I'd like to do is add a single notification for all that come in (rather than having multiple notifications in the tray). I'll have a look at that.

Chris Esser
Chris Esser
2,241 Points
            Again, thanks! Thats exactly what I needed. It makes much more sense to declare you Receiver inside the scope of Main Activity.

I actually tweaked what you have here a little to better suit what I am trying.

I haven't used the code formatter in the comments yet, so my code may look really ugly. I can't figure out how to get the code to format nicely in these comments. The triple bar ticks wasn't working.

1) I moved the PushService.subscribe into the onCreate of my Application class. Since I don't plan on updating the subscription status for this app, I only wanted to perform that call once, instead of each time the activity resumed.

2) I changed the com.google.android.c2d.intent.RECEIVE in the intent filter to a name that better suits my app. I used com.cesser.ribbit.RECEIVE. Then, when I formated the push notification before i send it, I added that to the 'Action' parameter in the JSON formated push notification. As long as the IntentFilter and Action parameters match, you'll get the push.

Change to Intent Filter

intentFilter = new IntentFilter();
intentFilter.addAction("com.cesser.ribbit.RECEIVE");

Sending Push Notification

public void sendRefreshPush() { JSONObject data = new JSONObject();
try { // Omitting these prevents push from showing in notification bar //data.put("alert", "Push Notification Text");
//data.put("title", "Push Notification Title");
data.put("action", "com.cesser.ribbit.RECEIVE");
data.put("keyTestJSONData", "Test Data!"); } catch (JSONException e) { e.printStackTrace(); }
ParsePush push = new ParsePush(); // Create a new Push Object push.setChannel("Channel_Ribbit"); // Set the channel the Push will be sent on push.setData(data); // Add the JSONObject to the Push push.sendInBackground(); // Send the Push }

3) I moved the unregister(...) method to the onDestroy() instead of the onPause() of my MainActivity. I added a check in my onResume() method to only peform the Ribbit actions if the network was available, and this included registering the receiver. What I found, is that if the network is not available, and the receiver does not get registered, when the unregister() is called in onPause(), the app crashes. It can't unregister() the reciever, since it wasn't registered in the first place. I bet there is a way to check if a receiver is registered before calling unregister(), but I haven't found it yet.This doesn't seem to be the perfect solution, but I haven't seen my app crash since I implemented it.

4) The way I prevented the notification from showing up in the notification bar is by add a JSON data object to the push notification. You can see this in Step 2 above. If you simply omit the "alert" and "title" fields, it doesn't show up in the notification bar.

Thanks again for your help! Let me know if you can figure out how to perform the unregister() only if a receiver is registered already, that's that only thing I haven't figured out yet.

Chris Esser
Chris Esser
2,241 Points

I posted my comment in the answer section...moved it