A fragment is an independent Android component which can be used by an activity. A fragment encapsulates functionality so that it is easier to reuse within activities and layouts. Introduction to fragments you can read here.
Fragments simplify the reuse of components in different layouts, e.g., you can build single-panel layouts for handsets (phones) and multi-pane layouts for tablets. This is not limited to tablets; for example, you can use fragments also to support different layout for landscape and portrait orientation on a smartphone.
To increase reuse of fragments, they should not directly communicate with each other. Every communication of the fragments should be done via the host activity.
There are three ways a fragment and an activity can communicate:
For this purpose a fragment should define an interface as an inner type and require that the activity, which uses it, must implement this interface. This way you avoid that the fragment has any knowledge about the activity which uses it. In its onAttach()
method it can check if the activity correctly implements this interface.
In demo application I use one main activity and one detailed activity. On a tablet the main activity contains both fragments in its layout, on a handheld it only contains the main fragment.
Key points
Full code you can see on github.
Model class
import java.util.ArrayList; import java.util.List; public class Movie { private String title; private Integer year; public static List<Movie> items = new ArrayList<>(); public static void generate() { items.add(new Movie("The Shawshank Redemption", 1994)); items.add(new Movie("The Godfather ", 1972)); items.add(new Movie("The Godfather: Part II ", 1974)); } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Integer getYear() { return year; } public void setYear(Integer year) { this.year = year; } public Movie(String title, Integer year) { this.title = title; this.year = year; } }
Main activity
import android.support.v4.app.FragmentTransaction; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.Toolbar; public class MainActivity extends AppCompatActivity implements MovieListFragment.MovieListListener { private Toolbar toolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // creating toolbar and setting it as actionbar for the activity toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setTitle(" IMDB"); toolbar.setLogo(android.R.drawable.ic_dialog_info); toolbar.setTitleTextColor(0xFFFFFFFF); setSupportActionBar(toolbar); if (savedInstanceState == null) { Movie.generate(); // set list fragment MovieListFragment frg = new MovieListFragment(); getSupportFragmentManager().beginTransaction().add(R.id.flMovieList, frg).commit(); // set detail fragment if (findViewById(R.id.flMovieDetail) != null) { Bundle arguments = new Bundle(); arguments.putInt(MovieDetailFragment.ARG_ITEM_POS, 0); MovieDetailFragment fragment = new MovieDetailFragment(); fragment.setArguments(arguments); getSupportFragmentManager().beginTransaction().add(R.id.flMovieDetail, fragment).commit(); } } } @Override public void itemClicked(int pos) { if (findViewById(R.id.flMovieDetail) == null) { // start detail activity Intent detailIntent = new Intent(this, MovieDetailActivity.class); detailIntent.putExtra(MovieDetailFragment.ARG_ITEM_POS, pos); startActivity(detailIntent); } else { // replace detail fragment Bundle arguments = new Bundle(); arguments.putInt(MovieDetailFragment.ARG_ITEM_POS, pos); MovieDetailFragment fragment = new MovieDetailFragment(); fragment.setArguments(arguments); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.flMovieDetail, fragment); ft.addToBackStack(null); ft.commit(); } } }
Model adapter
import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import java.util.List; public class MovieAdapter extends BaseAdapter { private Context context; private List<Movie> movies; public MovieAdapter(Context context, List<Movie> movies) { this.context = context; this.movies = movies; } @Override public int getCount() { return movies.size(); } @Override public Object getItem(int position) { return movies.get(position); } @Override public long getItemId(int position) { return movies.indexOf(getItem(position)); } private class ViewHolder{ TextView tvTitle; TextView tvYear; } public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; LayoutInflater inflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE); Movie movie = movies.get(position); if (convertView == null) { convertView = inflater.inflate(R.layout.movie_list_item, null); holder = new ViewHolder(); holder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle); holder.tvYear = (TextView) convertView.findViewById(R.id.tvYear); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.tvTitle.setText(movie.getTitle()); holder.tvYear.setText(movie.getYear().toString()); return convertView; } }
Detail activity (host for detail fragment)
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MovieDetailActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.movie_detail_activity); if (savedInstanceState == null) { MovieDetailFragment fragment = new MovieDetailFragment(); Bundle arguments = new Bundle(); arguments.putInt(MovieDetailFragment.ARG_ITEM_POS, getIntent().getIntExtra(MovieDetailFragment.ARG_ITEM_POS, 0)); fragment.setArguments(arguments); getSupportFragmentManager().beginTransaction().add(R.id.flMovieDetail, fragment).commit(); } } }
Detail fragment
import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class MovieDetailFragment extends Fragment { public static final String ARG_ITEM_POS = "moviePOS"; private Movie movie; public MovieDetailFragment() {} @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments().containsKey(ARG_ITEM_POS)) { movie = Movie.items.get(getArguments().getInt(ARG_ITEM_POS)); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.movie_detail_fragment, container, false); if (movie != null) { TextView tvTitle = (TextView)v.findViewById(R.id.tvTitle); tvTitle.setText(movie.getTitle()); TextView tvYear = (TextView)v.findViewById(R.id.tvYear); tvYear.setText(movie.getYear().toString()); } return v; } }
List fragment
import android.app.Activity; import android.os.Bundle; import android.support.v4.app.ListFragment; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import android.widget.Toast; public class MovieListFragment extends ListFragment { MovieAdapter adapter; static interface MovieListListener { void itemClicked(int pos); }; private MovieListListener listener; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.movie_list_fragment, container, false); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); adapter = new MovieAdapter(getActivity(), Movie.items); setListAdapter(adapter); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); getActivity().getMenuInflater().inflate(R.menu.movie_list_menu, menu); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { this.listener = (MovieListListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement MovieListListener"); } } @Override public void onDetach() { super.onDetach(); this.listener = null; } @Override public void onListItemClick(ListView l, View v, int position, long id) { Movie item = Movie.items.get(position); Toast.makeText(getActivity(), item.getTitle(), Toast.LENGTH_SHORT).show(); if (listener != null) { listener.itemClicked(position); } } @Override public boolean onOptionsItemSelected(MenuItem item) { // handle item selection switch (item.getItemId()) { case R.id.some_item: Toast.makeText(getActivity(), "Some action", Toast.LENGTH_LONG).show(); return true; default: return super.onOptionsItemSelected(item); } } }