Simple Android News App Compatible With Phones and Tablets

This example shows you how to implement a simple news app use RecyclerView, Fragment, Qualifier, PercentRelativeLayout etc. If you do not know how to use those android widget, you can read previous articles about them. I will list all the related article at the end of this example.

1. Android News App Example Screen Shots.

This android news app can automatically load different layout file to match the android device screen size.

When run in a tablet, it shows two panel. Left panel is the news title list. When click a news title, right panel shows the news content.

If you can not watch the above video, you can see it on the youtube URL https://youtu.be/z-O2YVo6Bxg

When run in a mobile phone which has small screen size. It will first show the news title list in one panel. When click news title, a new activity will open to show the news content.

If you can not watch the above video, you can see it on the youtube URL https://youtu.be/KGTQMfOHPJU

2. Android News App Example Source Code.

2.1 Main Activity Java File.

NewsAppActivity.java

package com.dev2qa.example.fragment.newsapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import com.dev2qa.example.R;

public class NewsAppActivity extends AppCompatActivity {

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

        setTitle("dev2qa.com - Simple Android News App");
    }
}

2.2 Main Activity Layout Xml File.

There are two main activity layout file. The two file name are same. But they are saved in different directory. One is saved in app / res / layout, the other is saved in app / res / layout-large.

app / res / layout / activity_news_app.xml

This layout file is used when the device screen size is small like mobile phone. There is only the news title fragment in it.

<fragment
    android:id="@+id/news_title_fragment"
    android:name="com.dev2qa.example.fragment.newsapp.FragmentNewsTitle"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

app / res / layout-large / activity_news_app.xml

This layout file is used when the device screen size is large like tablet. There are two fragments, news title fragment and news content fragment in it.

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <fragment
        android:id="@+id/news_title_fragment"
        android:name="com.dev2qa.example.fragment.newsapp.FragmentNewsTitle"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"/>

    <fragment
        android:id="@+id/news_content_fragment"
        android:name="com.dev2qa.example.fragment.newsapp.FragmentNewsContent"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="3"/>

</LinearLayout>

2.3 News Title Fragment Java File.

This fragment use a RecyclerView to list all the news title in it. This file includes two inner class which are used by RecyclerView. They are NewsTitleAdapter and NewsTitleViewHolder.

FragmentNewsTitle.java

package com.dev2qa.example.fragment.newsapp;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.dev2qa.example.R;

import java.util.ArrayList;
import java.util.List;

public class FragmentNewsTitle extends Fragment {

    // Whether the app has two panel( tablet ) or one panel( phone ).
    //private boolean hasTwoPanel = false;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        // Inflate news title fragment.
        View ret = inflater.inflate(R.layout.fragment_news_title, container, false);

        // Get RecyclerView.
        RecyclerView newsTitleRecyclerView = (RecyclerView)ret.findViewById(R.id.news_title_recycler_view);

        // Create a LinearLayoutManager.
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
        // Set the LinearLayoutManager to the news title recycler view.
        newsTitleRecyclerView.setLayoutManager(linearLayoutManager);

        // Create and set News Title Adapter.
        NewsTitleAdapter newsTitleAdapter = new NewsTitleAdapter(this.generateNewsList());
        newsTitleRecyclerView.setAdapter(newsTitleAdapter);

        return ret;
    }


    private List<NewsDTO> generateNewsList()
    {
        List<NewsDTO> ret = new ArrayList<NewsDTO>();

        for(int i=0;i<100;i++)
        {
            NewsDTO newsDto = new NewsDTO();

            newsDto.setNewsTitle("News number " + (i + 1));

            newsDto.setNewsContent((i + 1) + ". dev2qa.com is a good android example website.");

            ret.add(newsDto);
        }

        return ret;
    }



    // This class is used to save adapter data for news title RecyclerView.
    class NewsTitleAdapter extends RecyclerView.Adapter<NewsTitleViewHolder> {

        private List<NewsDTO> newsDtoList;

        public NewsTitleAdapter(List<NewsDTO> newsDtoList) {
            this.newsDtoList = newsDtoList;
        }

        @Override
        public NewsTitleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            // Get LayoutInflator.
            final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());

            // Inflate the news title item layout view.
            View itemView = layoutInflater.inflate(R.layout.fragment_news_title_item, parent, false);

            // Create a view holder.
            final NewsTitleViewHolder retViewHolder = new NewsTitleViewHolder(itemView);

            // Get current view data position.
            int itemPosition = retViewHolder.getAdapterPosition();

            // If two panel, their has a right fragment which is used to display news content.
            final FragmentNewsContent fragmentNewsContent = (FragmentNewsContent)getFragmentManager().findFragmentById(R.id.news_content_fragment);

            // For the first news data.
            if(itemPosition==-1)
            {
                // Get related position view data dto.
                final NewsDTO itemNewsDto = newsDtoList.get(0);

                // If has two panel then show the first news detail content in right fragment by default.
                if(fragmentNewsContent!=null)
                {
                    fragmentNewsContent.showNews(itemNewsDto.getNewsTitle(), itemNewsDto.getNewsContent());
                }
            }

            // When click itemView.
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {

                    // Get current view data position.
                    int itemPosition = retViewHolder.getAdapterPosition();

                    // Get related position view data dto.
                    NewsDTO itemNewsDto = newsDtoList.get(itemPosition);

                    // If right fragment do not exist then single panel app.
                    if(fragmentNewsContent==null)
                    {
                        NewsContentActivity.startNewsContentActivity(getActivity(), itemNewsDto.getNewsTitle(), itemNewsDto.getNewsContent());
                    }
                    // If right fragment exist then two panel app.
                    else
                    {
                        fragmentNewsContent.showNews(itemNewsDto.getNewsTitle(), itemNewsDto.getNewsContent());
                    }
                }
            });

            return retViewHolder;
        }

        @Override
        public void onBindViewHolder(NewsTitleViewHolder holder, int position) {
            NewsDTO newsDto = newsDtoList.get(position);
            holder.newsTitleTextView.setText(newsDto.getNewsTitle());
        }

        @Override
        public int getItemCount() {
            int ret = 0;
            if(newsDtoList!=null)
            {
                ret = newsDtoList.size();
            }
            return ret;
        }
    }


    // This class is used by NewsTitleAdapter.
    class NewsTitleViewHolder extends RecyclerView.ViewHolder {

        private TextView newsTitleTextView;

        public NewsTitleViewHolder(View itemView) {
            super(itemView);
            if(itemView!=null)
            {
                newsTitleTextView = itemView.findViewById(R.id.news_title_item);
            }
        }
    }
}

2.4 News Title Fragment Layout Xml File.

There is only a RecyclerView in it.

fragment_news_title.xml

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

    <android.support.v7.widget.RecyclerView
        android:id="@+id/news_title_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

2.5 News Title Fragment Item View Layout Xml File.

This layout file is used to display RecyclerView’s item.

fragment_news_title_item.xml

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

    <TextView
        android:id="@+id/news_title_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:singleLine="true"
        android:textSize="20dp"
        android:layout_margin="5dp"
        android:padding="5dp"
        android:textColor="@android:color/holo_red_light"
        android:background="#00FF00"/>

</LinearLayout>

2.6 News DTO Java File.

NewsDTO.java

package com.dev2qa.example.fragment.newsapp;

public class NewsDTO {

    private String newsTitle;

    private String newsContent;

    public String getNewsTitle() {
        return newsTitle;
    }

    public void setNewsTitle(String newsTitle) {
        this.newsTitle = newsTitle;
    }

    public String getNewsContent() {
        return newsContent;
    }

    public void setNewsContent(String newsContent) {
        this.newsContent = newsContent;
    }
}

2.7 News Content Fragment Java File.

Show news content in fragment.

FragmentNewsContent.java

package com.dev2qa.example.fragment.newsapp;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.dev2qa.example.R;

public class FragmentNewsContent extends Fragment {

    private View newsContentFragView = null;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View ret = inflater.inflate(R.layout.fragment_news_content, container, false);
        newsContentFragView = ret;
        return ret;
    }

    public void showNews(String title, String content)
    {
        TextView titleTextView = (TextView)newsContentFragView.findViewById(R.id.news_title);
        TextView contentTextView = (TextView)newsContentFragView.findViewById(R.id.news_content);

        titleTextView.setText(title);
        contentTextView.setText(content);
    }
}

2.8 News Content Fragment Layout Xml File.

fragment_news_content.xml

<android.support.percent.PercentRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_marginTop="10dp"
        android:gravity="center"
        android:id="@+id/news_title"
        app:layout_widthPercent="100%"
        app:layout_heightPercent="10%"
        android:textSize="20dp"/>

    <View
        android:id="@+id/news_content_split_line"
        android:layout_below="@id/news_title"
        app:layout_widthPercent="100%"
        app:layout_heightPercent="1%"
        android:background="#D3D3D3"/>

    <TextView
        android:id="@+id/news_content"
        android:layout_below="@id/news_content_split_line"
        app:layout_widthPercent="100%"
        app:layout_heightPercent="85%"
        android:padding="8dp"
        android:textSize="18dp"/>

</android.support.percent.PercentRelativeLayout>

2.9 News Content Activity Java File.

This activity is started only when run news app in small screen size device such as mobile phone and when news title is clicked.

NewsContentActivity.java

package com.dev2qa.example.fragment.newsapp;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;

import com.dev2qa.example.R;

public class NewsContentActivity extends AppCompatActivity {

    private final static String INTENT_KEY_NEWS_CONTENT = "INTENT_KEY_NEWS_CONTENT";

    private final static String INTENT_KEY_NEWS_TITLE = "INTENT_KEY_NEWS_TITLE";

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

        setTitle("dev2qa.com - News app content.");

        Intent intent = getIntent();
        String title = intent.getStringExtra(INTENT_KEY_NEWS_TITLE);
        String content = intent.getStringExtra(INTENT_KEY_NEWS_CONTENT);

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentNewsContent fragmentNewsContent = (FragmentNewsContent)fragmentManager.findFragmentById(R.id.news_content_fragment);

        fragmentNewsContent.showNews(title, content);
    }

    public static void startNewsContentActivity(Context ctx, String title, String content)
    {
        Intent intent = new Intent(ctx, NewsContentActivity.class);
        intent.putExtra(INTENT_KEY_NEWS_TITLE, title);
        intent.putExtra(INTENT_KEY_NEWS_CONTENT, content);
        ctx.startActivity(intent);
    }
}

2.10 News Content Activity Layout Xml File.

There is only news content fragment in this xml file.

activity_news_content.xml

<fragment
    android:id="@+id/news_content_fragment"
    android:name="com.dev2qa.example.fragment.newsapp.FragmentNewsContent"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

3. Reference.

  1. Android RecyclerView Example
  2. Android Multiple Fragments In One Activity Example
  3. How To Support Multiple Screen Size In Android
  4. Android PercentFrameLayout PercentRelativeLayout Example

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.