Search code examples
javaandroidandroid-recyclerviewandroidx

Android RecyclerView is showing nothing


I created an app which has an RecyclerView inside a Fragment to display data from a database. Some weeks ago I created another app with a RecyclerView with android support package and everything was fine. Now, with androidx, the view shows nothing. Here is my RecyclerViewAdapter class:

public class HistoryRecyclerViewAdapter extends RecyclerView.Adapter<HistoryRecyclerViewAdapter.ViewHolder> {
    private static final String TAG = "HistoryRecyclerView";

    private List<HistoryType> mHistory;

    HistoryRecyclerViewAdapter(List<HistoryType> history){
        mHistory = history;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Context context = parent.getContext();
        LayoutInflater inflater = LayoutInflater.from(context);

        View historyView = inflater.inflate(R.layout.history_list_item,parent,false);

        ViewHolder viewHolder = new ViewHolder(historyView);
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        HistoryType history = mHistory.get(position);

        SimpleDateFormat formatter;
        Calendar calendar;


        TextView nameText = holder.mNameText;
        nameText.setText(history.getName());

        TextView durationText = holder.mDurationText;
        formatter = new SimpleDateFormat("HH:mm:ss");
        calendar = Calendar.getInstance();
        calendar.setTimeInMillis(history.getDuration());
        String durationString = formatter.format(calendar.getTime());
        durationText.setText(durationString);

        TextView distanceText = holder.mDistanceText;
        distanceText.setText(String.format("%.2f km",history.getDistance()));

        TextView totalAirTimeText = holder.mTotalAirTimeText;
        formatter = new SimpleDateFormat("mm:ss.SS");
        calendar = Calendar.getInstance();
        calendar.setTimeInMillis(history.getTotalAirTime());
        String totalAirTimeString = formatter.format(calendar.getTime());
        totalAirTimeText.setText(totalAirTimeString);

        TextView dateText= holder.mDateText;
        formatter = new SimpleDateFormat("dd MMMM yyyy");
        String dateString = formatter.format(history.getDate());
        dateText.setText(dateString);
    }

    @Override
    public int getItemCount() {
        return mHistory.size();
    }


    public class ViewHolder extends RecyclerView.ViewHolder{

        public TextView mNameText;
        public TextView mDurationText;
        public TextView mDistanceText;
        public TextView mTotalAirTimeText;
        public TextView mDateText;

        public ViewHolder(View itemView) {
            super(itemView);

            mNameText = (TextView) itemView.findViewById(R.id.history_name);
            mDurationText = (TextView) itemView.findViewById(R.id.history_duration);
            mDistanceText = (TextView) itemView.findViewById(R.id.history_distance);
            mTotalAirTimeText = (TextView) itemView.findViewById(R.id.history_airtime);
            mDateText = (TextView) itemView.findViewById(R.id.history_date);

        }
    }

And here the fragment, calling the adapter (the ArrayList has one item):

public class HistoryFragment extends Fragment {

    private ArrayList<HistoryType> mHistoryList = new ArrayList<>();
    private RecyclerView mRecyclerView;
    private HistoryRecyclerViewAdapter mHistoryAdapter;
    private SQLiteOpenHelper mSqliteOpenHelper;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_history, container, false);

        mRecyclerView = (RecyclerView) view.findViewById(R.id.history_recycler);

        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mHistoryAdapter = new HistoryRecyclerViewAdapter(mHistoryList);

        mRecyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
        mRecyclerView.setAdapter(mHistoryAdapter);

        mSqliteOpenHelper = new SQLiteOpenHelper(getActivity());
        mHistoryList = mSqliteOpenHelper.getHistory();

        for (HistoryType dataSet: mHistoryList) {
            mHistoryAdapter.notifyItemInserted(mHistoryList.indexOf(dataSet));
        }

    }

fragment_history.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
    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"
    android:id="@+id/history_recycler"
    android:layout_marginLeft="@dimen/text_margin"
    android:layout_marginRight="@dimen/text_margin"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>

history_list_item.xml

<?xml version="1.0" encoding="utf-8"?>

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    //Name
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/history_name"
        android:layout_margin="@dimen/text_margin"
        android:text="activity name"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:textSize="@dimen/big_text_size"
        android:textStyle="bold"
        />

    //Duration
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/history_duration_icon"
        android:layout_marginTop="@dimen/text_margin"
        android:layout_marginRight="@dimen/icon_margin"
        android:layout_marginLeft="@dimen/text_margin"
        app:layout_constraintTop_toBottomOf="@id/history_name"
        app:layout_constraintLeft_toLeftOf="parent"
        android:background="@drawable/timer_24" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/history_duration"
        android:text="01.01.2021"
        android:layout_margin="@dimen/text_margin"
        app:layout_constraintTop_toBottomOf="@id/history_name"
        app:layout_constraintLeft_toRightOf="@id/history_duration_icon"
        android:textSize="@dimen/medium_text_size"/>

    //Distance
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/history_distance_icon"
        android:layout_marginTop="@dimen/text_margin"
        android:layout_marginLeft="@dimen/text_margin"
        android:layout_marginRight="@dimen/icon_margin"
        app:layout_constraintTop_toBottomOf="@id/history_name"
        app:layout_constraintLeft_toRightOf="@id/history_duration"
        android:background="@drawable/arrow_right_alt_24"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/history_distance"
        android:text="1h 35min"
        android:layout_marginTop="@dimen/text_margin"
        android:layout_marginLeft="@dimen/icon_margin"
        app:layout_constraintTop_toBottomOf="@id/history_name"
        app:layout_constraintLeft_toRightOf="@id/history_distance_icon"
        android:textSize="@dimen/medium_text_size"/>

    //Total Airtime
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/history_airtime_icon"
        android:layout_marginTop="@dimen/text_margin"
        android:layout_marginLeft="@dimen/text_margin"
        android:layout_marginRight="@dimen/icon_margin"
        app:layout_constraintTop_toBottomOf="@id/history_name"
        app:layout_constraintLeft_toRightOf="@id/history_distance"
        android:background="@drawable/keyboard_arrow_up_24"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/history_airtime"
        android:text="1h 35min"
        android:layout_marginTop="@dimen/text_margin"
        android:layout_marginLeft="@dimen/icon_margin"
        app:layout_constraintTop_toBottomOf="@id/history_name"
        app:layout_constraintLeft_toRightOf="@id/history_airtime_icon"
        android:textSize="@dimen/medium_text_size"/>

    //Date
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/history_date"
        android:text="01.01.2021"
        android:layout_margin="@dimen/text_margin"
        app:layout_constraintTop_toBottomOf="@id/history_duration_icon"
        app:layout_constraintLeft_toLeftOf="parent"
        android:textSize="@dimen/small_text_size" />


</androidx.constraintlayout.widget.ConstraintLayout>

Does somebody help me? Thanks a lot


Solution

  • As far as I can see, you have a problem with your references. First you declare your adapter with an empty instance of the ArrayList, which is okay. The adapter is now connected with this ArrayList. But then you reassign the list to another instance, that is, the one returned from

    mSqliteOpenHelper.getHistory()
    

    If you compare the two instances, you'd notice that they are not the same. What you should do is add the results from 'mSqliteOpenHelper.getHistory()' to the list that is already connected with the adapter (the empty ArrayList you have already defined), using 'addAll()'.

    EDIT: Just to make myself clearer: In the beginning you declare and initialize your list

    private ArrayList<HistoryType> mHistoryList = new ArrayList<>();
    

    Let's call this instance Instance#1. You set Instance#1 as the data source to the adapter. The adapter now has an empty data source.

    Afterwards, you reassign this list

            mHistoryList = mSqliteOpenHelper.getHistory();
    

    This is a different ArrayList instance, let's call it Instance#2. And although the mHistoryList variable holds this instance, the adapter is still linked with Instance#1, only you don't have a reference to it anymore. So the adapter is linked with the empty ArrayList (Instance#1), rather than the one that has data (Instance#2). Don't reassign the variable, make it final. ArrayList is mutable, so you can add data to it. So, add the data to it and notify the adapter that it has been changed.

    Let me know if you have any questions