RecycleView not displaying properly?

Miljan Puletic :

I'm following Big Nerd Ranch Guide (2015 edition). We started with fragments. In this chapter RecycleView was introduced.

The goal is to display 100 Crimes using RecycleView, like this: enter image description here

The authors are using Crime as data object (with fields: id, title, resolved, Date).

We have a superclass Activity called SingleFragmentActivity:

    public abstract class SingleFragmentActivity extends FragmentActivity {

    protected abstract Fragment createFragment();
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment); //container for different fragments...

        FragmentManager fm = getSupportFragmentManager();
        Fragment fragment = fm.findFragmentById(R.id.fragment_container);

        if (fragment == null) {
            fragment = createFragment();
            fm.beginTransaction()
                    .add(R.id.fragment_container, fragment)
                    .commit();
        }
    }
}

Accompanying layout (as you can see in SingleFragmentActivity) is fragment_container.xml:

<?xml version="1.0" encoding="utf-8"?>
<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" />

Then we have a subclass, called CrimeListActivity:

public class CrimeListActivity extends SingleFragmentActivity {
    @Override
    protected Fragment createFragment() {
        return new CrimeListFragment();
    }
}

CrimeListFragment is, as you can imagine, a Fragment with inner classes of ViewHolder, Adapter required by RecycleView to create necessary Views and recycles them.

public class CrimeListFragment extends Fragment {
    private RecyclerView mCrimeRecyclerView;
    private CrimeAdapter mAdapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_crime_list, container, false);

        mCrimeRecyclerView = (RecyclerView) view.findViewById(R.id.crime_recycler_view);

        mCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

        updateUI();

        return view;
    }

    private void updateUI() {
        CrimeLab crimeLab = CrimeLab.get(getActivity());
        List<Crime> crimes = crimeLab.getCrimes();
        mAdapter = new CrimeAdapter(crimes);
        mCrimeRecyclerView.setAdapter(mAdapter);
    }

    private class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
        private Crime mCrime;
        private TextView mTitleTextView;
        private TextView mDateTextView;
        private CheckBox mSolvedCheckBox;

        public CrimeHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            mTitleTextView = (TextView)
                    itemView.findViewById(R.id.list_item_crime_title_text_view);
            mDateTextView = (TextView)
                    itemView.findViewById(R.id.list_item_crime_date_text_view);
            mSolvedCheckBox = (CheckBox)
                    itemView.findViewById(R.id.list_item_crime_solved_check_box);
        }

        public void bindCrime(Crime crime) {
            mCrime = crime;
            mTitleTextView.setText(mCrime.getTitle());
            mDateTextView.setText(mCrime.getDate().toString());
            mSolvedCheckBox.setChecked(mCrime.isSolved());
        }

        @Override
        public void onClick(View v) {
            Toast.makeText(getActivity(),mCrime.getTitle() + " clicked!", Toast.LENGTH_SHORT)
                    .show();
        }
    }

    private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {
        private List<Crime> mCrimes;
        public CrimeAdapter(List<Crime> crimes) {
            mCrimes = crimes;
        }
        @Override
        public CrimeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            /*onCreateViewHolder is called by the RecyclerView when it needs a new View to display an item. In
            this method, you create the View and wrap it in a ViewHolder. The RecyclerView does not expect that
            you will hook it up to any data yet.
            For the View, you inflate a layout from the Android standard library called simple_list_item_1. This
            layout contains a single TextView, styled to look nice in a list. Later in the chapter, you will make a
            more advanced View for the list items*/
            LayoutInflater layoutInflater = LayoutInflater.from(getActivity());

            View view = layoutInflater.inflate(R.layout.list_item_crime, parent, false);

            return new CrimeHolder(view);

        }
        @Override
        public void onBindViewHolder(CrimeHolder holder, int position) {
            /*onBindViewHolder: This method will bind a ViewHolder’s View to your model object. It receives
            the ViewHolder and a position in your data set. To bind your View, you use that position to find the
            right model data. Then you update the View to reflect that model data.
            In your implementation, that position is the index of the Crime in your array. Once you pull it out, you
            bind that Crime to your View by sending its title to your ViewHolder’s TextView.*/
            Crime crime = mCrimes.get(position);
            holder.bindCrime(crime);
        }
        @Override
        public int getItemCount() {
            return mCrimes.size();
        }
    }




}

Accompanying layout for this fragment is naturally RecycleView in xml format, named fragment_crime_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/crime_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

And finally the actual ViewItem through which Adapter is going to bound the data is given in form of two TextViews (one for Date of the Crime, one for title of the Crime) and one CheckBox to mark is crime resolved.

It is named list_item_crime.xml and looks like this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <CheckBox
        android:id="@+id/list_item_crime_solved_check_box"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:padding="4dp"/>

    <TextView
        android:id="@+id/list_item_crime_title_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/list_item_crime_solved_check_box"
        android:textStyle="bold"
        android:padding="4dp"
        tools:text="Crime Title"/>

    <TextView
        android:id="@+id/list_item_crime_date_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/list_item_crime_solved_check_box"
        android:layout_below="@id/list_item_crime_title_text_view"
        android:padding="4dp"
        tools:text="Crime Date"/>

</RelativeLayout>

Now, this is from the book, I double checked everything, I hope I didn't miss something. My Crime item, appears only at the top of the screen, I need to scroll down to the bottom of the screen and only the the second Crime item appears. Like this:

enter image description here

Anyone knows what am I missing here? I was looking last three days for this one to fix. Actually asking here is my last hope :)

Vucko :

The problem is a very hard one to catch. Take a closer look at your list_item_crime.xml file. Particularly at this line:

android:layout_height="match_parent"

You're setting the height of one single item to the whole available height. If you try to scroll, you should see other items below taking up the same height. Simple fix, change to:

android:layout_height="wrap_content"

When I was first starting out with Android, I hated the RecyclerView cause so many things can go wrong with it. This has happened to me more than once :-)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=12302&siteId=1