Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android Build a Self-Destructing Message Android App Using Fragments for Tabs Why Fragments?

Read this: Your going to run into some problems later in this class

What we're going to go over in this class includes Tabs from the ActionBar, which is code that was deprecated in 2014. Look in the questions as you go, I've included a solution in the related lesson at this link:

https://teamtreehouse.com/forum/this-is-the-droid-you-are-looking-for-how-to-get-past-this-lesson-while-knowing-the-modern-standard

Please let me know if you have any questions. In the future, android is looking to get rid of tabs due to space restraints, but they've provided the PagerTabStrip as a low profile, non-clickable tab, so we can continue the classes with very little changed.

1 Answer

jenyufu
jenyufu
3,311 Points

So I got it to run and work without bugs and I didn't change anything (am running in Android Studio 1.2.2)

Am I doing something wrong? Here is my MainActivity.java:

package com.joinedit.ribbitpractice;

import java.util.Locale;

import android.support.v4.app.FragmentActivity;

import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.FragmentPagerAdapter;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.parse.ParseAnalytics;
import com.parse.ParseUser;


public class MainActivity extends ActionBarActivity implements ActionBar.TabListener { // 3.4 implements interface: ActionBar.TabListener means that this MainActivity class is acting as the listener for the tabs

    // create TAG variable for Log.e(TAG, currentUser.getUsername());
    public static final String TAG = MainActivity.class.getSimpleName();

    /**
     * The {@link android.support.v4.view.PagerAdapter} that will provide
     * fragments for each of the sections. We use a
     * {@link FragmentPagerAdapter} derivative, which will keep every
     * loaded fragment in memory. If this becomes too memory intensive, it
     * may be best to switch to a
     * {@link android.support.v4.app.FragmentStatePagerAdapter}.
     */
    SectionsPagerAdapter mSectionsPagerAdapter;

    /**
     * The {@link ViewPager} that will host the section contents.
     */
    ViewPager mViewPager;

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

        ParseAnalytics.trackAppOpenedInBackground(getIntent()); //Lesson 2.3 copy/pasted in code from Parse.com analytics to enable analytic tracking

        //Check to see if anyone is logged in before we start these intent
        //so we don't redirect users to the LogIn screen after the Logged in and arrived at the MainActivity
        //Whenever you use any signup or login methods, the user is cached on disk. You can treat this
        //cache as a session and automatically assume the user is logged in:
        ParseUser currentUser = ParseUser.getCurrentUser();
        if(currentUser == null) {
            //Intent launch LogInActivity
            navigateToLogin(); //refactor>Extract>Method  all the intent stuff to navigateToLogin()
        }
        else {
            Log.i(TAG,currentUser.getUsername());
        }

        // Set up the action bar. Action bar displays the tabs and allows us to tap on them. Simple.
        final ActionBar actionBar = getSupportActionBar();
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        // Create the adapter that will return a fragment for each of the three
        // primary sections of the activity.
        mSectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());

        // Set up the ViewPager with the sections adapter.
        mViewPager = (ViewPager) findViewById(R.id.pager);
        mViewPager.setAdapter(mSectionsPagerAdapter);

        // When swiping between different sections, select the corresponding
        // tab. We can also use ActionBar.Tab#select() to do this if we have
        // a reference to the Tab.
        mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        //^3.7 .setOnPageChangeListener == when we Swipe. Swipe triggers a page change thus the name of the method
            @Override
            public void onPageSelected(int position) {
                actionBar.setSelectedNavigationItem(position);
                //^3.7 sets tab to this navigational item when swiped.
                // this makes sure ViewPager and ActionBar tab stay in sync.
                // So we won't be at a Inbox Fragment but on the ActionBar show "Friends" tab
            }
        });

        // we add the tabs and titles to the ActionBar.
        // And then we're also setting the tab listener to use this activity.
        // For each of the sections in the app, add a tab to the action bar.
        for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {         // Notice that we call the getCount method of the adapter to see how many tabs we need. // And for each tab that we add, we are calling the getPageTitle method from the adapter to get the titles we set earlier.


            // Create a tab with text corresponding to the page title defined by
            // the adapter. Also specify this Activity object, which implements
            // the TabListener interface, as the callback (listener) for when
            // this tab is selected.
            actionBar.addTab(
                    actionBar.newTab()
                            .setText(mSectionsPagerAdapter.getPageTitle(i))
                            .setTabListener(this)); //*simple to implement: from implements ActionBar.TabListener up at the top
                                                   // and a few methods down below*
        }
    }

    private void navigateToLogin() {
        Intent intent = new Intent(this, LoginActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //add Flags so when you hit the back key on your phone it won't send you to the MainActivity
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); //basically: logging in should be a new task and the old task should be cleared so we can't go back to it.
        startActivity(intent);
    }

    // The menu [...] // Lesson 2.10 Logging out: Log out, clear the cache, and show login screen.
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu); // R.menu.menu_main == (Res> Menu > menu_main.xml)
        return true;
    }

    //Lesson 2.10 onOptionsItemSelected
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.

        //*One thing we check is the id of the item:
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_logout) { //if (user taps on logout option)
            ParseUser.logOut(); //<-- this from Parse User documentation
            navigateToLogin(); //push the user back to LogIn screen
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
        // When the given tab is selected, switch to the corresponding page in
        // the ViewPager.
        mViewPager.setCurrentItem(tab.getPosition());
    }

    @Override
    public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }

    @Override
    public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
    }
}

Here is my SectionsPagerAdapter.java

package com.joinedit.ribbitpractice;

import java.util.Locale;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.content.Context;


/**
 * Created by Fu on 8/12/2015.
 */
/**
 * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
 * one of the sections/tabs/pages.
 */

public class SectionsPagerAdapter extends FragmentPagerAdapter { //Adapts fragments for a ViewPager

    protected Context mContext; //3.4 getString method below* needs the Context, thus create Context here

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

    @Override
    //3.4
    // The ViewPager in MainActivity uses this adapter and it will
    // call this getItem method each time it needs a fragment.
    // This will be each time the user taps on a tab or swipes to the next one.
    //That's why this method returns a Fragment     (accessModifier ReturnDataType methodName)
    public Fragment getItem(int position) { //3.4 the 'int' parameter is used for indexing the fragment in the 'ViewPager'. It's just like an array that starts at zero. (Section 1, Section 2, etc)

        // getItem is called to instantiate the fragment for the given page.
        // Return a PlaceholderFragment (defined as a static inner class below).

        //Simple: switch statement to return a different fragment based on the position: ie: in "Inbox" or "Friends"
        switch(position){
            case 0:
                return new InboxFragment();
            case 1:
                return new FriendsFragment();
        }

        return null;
    }

    @Override
    public int getCount() { //simply returns the "number of tabs in the ViewPager"
        // Show 2 total pages.
        return 2;
    }

    @Override
    //Change the title of the tabs. Change from "Section 1" and "Section 2" to "Inbox" and "Friends".
    public CharSequence getPageTitle(int position) {
        Locale l = Locale.getDefault();
        switch (position) {
            case 0:
                return mContext.getString(R.string.title_section1).toUpperCase(l); //getString method* needs the Context, thus create Context here
            case 1:
                return mContext.getString(R.string.title_section2).toUpperCase(l);
        }
        return null;
    }
}
Jakub Farobek
Jakub Farobek
1,959 Points

I would like to have an answer on this too.