5

So I've been stuck on the third tutorial on the Android Developer Site about Fragments for few days. I just can't understand how the app populates data when I run the app on a tablet (big screen layout). I can understand how the data is being populated on a smaller screen (phone screen).

How does the bigger screen list populate with data?

Here is a link of the whole project from Android.com tutorials.

MainActivity Class

public class MainActivity extends FragmentActivity 
    implements HeadlinesFragment.OnHeadlineSelectedListener {

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Here, the system will decide which news_article layout it will use based on the screen size. Will use layout if small or layout-large if it's big. 
        setContentView(R.layout.news_articles);

        // Check whether the activity is using the layout version with
        // the fragment_container FrameLayout. If so, we must add the first fragment
        //This check is to determine which layout to be used, either small screen or big screen.
        //fragment_container used FrameLayout for small screens.
        //fragment_container is the id of FrameLayout in news_article for small screen. 
        if (findViewById(R.id.fragment_container) != null) {

            // However, if we're being restored from a previous state,
            // then we don't need to do anything and should return or else
            // we could end up with overlapping fragments.
            if (savedInstanceState != null) {
                return;
            }

            // Create an instance of ExampleFragment
            HeadlinesFragment firstFragment = new HeadlinesFragment();

            // In case this activity was started with special instructions from an Intent,
            // pass the Intent's extras to the fragment as arguments
             firstFragment.setArguments(getIntent().getExtras());

            // Add the fragment to the 'fragment_container' FrameLayout
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.fragment_container, firstFragment).commit();
        }
    }

    public void onArticleSelected(int position) {
        // The user selected the headline of an article from the HeadlinesFragment

        // Capture the article fragment from the activity layout
        ArticleFragment articleFrag = (ArticleFragment)
            getSupportFragmentManager().findFragmentById(R.id.article_fragment);

        if (articleFrag != null) {
            // If article frag is available, we're in two-pane layout...

            // Call a method in the ArticleFragment to update its content
            articleFrag.updateArticleView(position);

        } else {
            // If the frag is not available, we're in the one-pane layout and must swap frags...

            // Create fragment and give it an argument for the selected article
            ArticleFragment newFragment = new ArticleFragment();
            Bundle args = new Bundle();
            args.putInt(ArticleFragment.ARG_POSITION, position);
            newFragment.setArguments(args);
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            // Replace whatever is in the fragment_container view with this fragment,
            // and add the transaction to the back stack so the user can navigate back
            transaction.replace(R.id.fragment_container, newFragment);
            transaction.addToBackStack(null);

            // Commit the transaction
            transaction.commit();
        }
    }
}

HeadLineFragment

public class HeadlinesFragment extends ListFragment {

// The container Activity must implement this interface so the frag can deliver messages
    public interface OnHeadlineSelectedListener {
        /** Called by HeadlinesFragment when a list item is selected */
        public void onArticleSelected(int position);
    }

    OnHeadlineSelectedListener mCallback;

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

        // We need to use a different list item layout for devices older than Honeycomb
        int layout = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ?
            android.R.layout.simple_list_item_activated_1 : android.R.layout.simple_list_item_1;

        // Create an array adapter for the list view, using the Ipsum headlines array
        setListAdapter(new ArrayAdapter<String>(getActivity(), layout, Ipsum.Headlines));

    }

    @Override
    public void onStart() {
        super.onStart();

        // When in two-pane layout, set the listview to highlight the selected list item
        // (We do this during onStart because at the point the listview is available.)
        if (getFragmentManager().findFragmentById(R.id.article_fragment) != null) {
            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        }
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception.
        try {
            mCallback = (OnHeadlineSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Notify the parent activity of selected item
        mCallback.onArticleSelected(position);

        // Set the item as checked to be highlighted when in two-pane layout
        getListView().setItemChecked(position, true);
    }
}

Layout for small screen news_article.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Layout for bigscreen news_article.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <fragment android:name="com.example.android.fragments.HeadlinesFragment"
              android:id="@+id/headlines_fragment"
              android:layout_weight="1"
              android:layout_width="0dp"
              android:layout_height="match_parent" />

    <fragment android:name="com.example.android.fragments.ArticleFragment"
              android:id="@+id/article_fragment"
              android:layout_weight="2"
              android:layout_width="0dp"
              android:layout_height="match_parent" />

</LinearLayout>
Michael Celey
  • 12,645
  • 6
  • 57
  • 62
W J
  • 51
  • 1
  • 1
  • 4

2 Answers2

5

Notice the placement of the two layouts.

Large screen is in a tablet bin (folder) res/layout-large/main.xml while small screen layout is in generic res/layout/main.xml

Since the java asks if the findViewById is null we know if the device is a large screen or normal layout.

 ArticleFragment articleFrag = (ArticleFragment) getSupportFragmentManager().findFragmentById(R.id.article_fragment);
    if (articleFrag != null) { 
        /* not null because we are in res/layout-large */
    } else {
        /* we are in single pain view /res/layout/... */
    }

When you call setContentView(int); they system handles loading the best layout you provided for the device based on the DPI bins provided.

JBirdVegas
  • 10,855
  • 2
  • 44
  • 50
  • Thank you for answering. My issue is that i can't understand how the bigger screen is being populated with data. I can't trace a reference in the MainActivity that fire setListAdapter(new ArrayAdapter(getActivity(), layout, Ipsum.Headlines)); I'm i missing somthing? – W J Mar 20 '13 at 21:27
  • `ArticleFragment` layout is just `TextView` that is set from `ArticalFragment` line 64. All the second fragment does is display the corresponding message. The arrays are both the same length so it just displays the message in the second array in the corresponding position – JBirdVegas Mar 20 '13 at 21:45
  • What about HeadLinesFragment, where does it get the data from when in 2-pane layout (the larger layout? I mean what code populates it? – W J Mar 20 '13 at 22:32
  • `HeadlinesFragment` line 44 says `setListAdapter(new ArrayAdapter(getActivity(), layout, Ipsum.Headlines));` – JBirdVegas Mar 20 '13 at 22:41
  • `MainActivity` receives a call back when user selects a list item because it implements the interface `HeadlinesFragment.OnHeadlineSelectedListener` with the method `public void onArticleSelected(int position)` on line 55 it uses the supplied position to determine which Ipsum Article position to use while populating the second view – JBirdVegas Mar 20 '13 at 22:45
  • Before user selects anything at the very beginning when the app initiates, if you are going to trace this from the MainActivity, i can't find any code that creates an instance of HeadlinesFragment to fire onCreate(). I just started Android learning few days ago and i really appreciate your help. – W J Mar 20 '13 at 22:52
  • The instance is created in the xml. In this example we just don't need a reference to `HeadlinesFragment` so we don't call findViewById(int) to get a reference... The inflation you are looking for is handled by the system through our xml `fragment` declaration – JBirdVegas Mar 20 '13 at 23:55
  • Has your question been answered? Or am I missing something / you have more questions? – JBirdVegas Mar 25 '13 at 06:28
0

I think, this question is related with this post: http://developer.android.com/training/multiscreen/screensizes.html

Note: large qualifier mean that layout will be selected on devices with screens classified as large (for example, 7" tablets and above). The other layout (without qualifiers) will be selected for smaller devices;

Also if you want to use for small screens two-pane layout, create directory: res/layout-sw600dp/main.xml;

About Data Population: In MainActivity you have implemented interface OnHeadlineSelectedListener, when you click on item from list (HeadLinesFragment class)
interface mCallback call function from MainActivity onArticleSelected(position);

in this function you have articleFlag

ArticleFragment articleFlag = (ArticleFragment) getSupportFragmentManager(). findFragmentById(R.id.article_fragment);

    if(articleFlag != null){
        //we have 2 panes (big screen)
articleFlag.updateArticleView(position);

    }else{
        //small screen 
       ArticleFragment newFragment = new ArticleFragment();
        Bundle args = new Bundle();
        args.putInt(ArticleFragment.ARG_POSITION, position);
        newFragment.setArguments(args);
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // Replace whatever is in the fragment_container view with this fragment,
        // and add the transaction to the back stack so the user can navigate back
        transaction.replace(R.id.fragment_container, newFragment);
        transaction.addToBackStack(null);

        //Commit the transaction 
        transaction.commit();

}

EugenUngurean
  • 429
  • 3
  • 14