If I scroll this list RecycleView
with the mouse wheel my items in the list look like unordered. I do not understand, why?
An incorrect clicked item in the new activity from RecycleView
I have tried to create the separate class CrimeAdapter extends RecyclerView.Adapter<CrimeAdapter.CrimeHolder>
and class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener
in the separate file, but I couldn't do it right. Unfornuntely, I do not have enough experience for this.
I do not know how to write the correct code in the method public void onClick(View v)
Crime.java
package com.bignerdranch.android.criminalintent;
import java.util.Date;
import java.util.UUID;
public class Crime{
private UUID mId;
private String mTitle;
private Date mDate;
private boolean mSolved;
private boolean mRequiresPolice;
public Crime() {
// Generate unique identifier
this(UUID.randomUUID());
}
public Crime(UUID id) {
mId = id;
mDate = new Date();
}
public UUID getId() {
return mId;
}
public String getTitle() {
return mTitle;
}
public void setTitle(String title) {
mTitle = title;
}
public Date getDate() {
return mDate;
}
public void setDate(Date date) {
mDate = date;
}
public boolean isSolved() {
return mSolved;
}
public void setSolved(boolean solved) {
mSolved = solved;
}
public boolean isRequiresPolice() {
return mRequiresPolice;
}
public void setRequiresPolice(boolean requiresPolice) {
mRequiresPolice = requiresPolice;
}
}
CrimeLab.java
package com.bignerdranch.android.criminalintent;
import android.content.Context;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class CrimeLab {
private static CrimeLab sCrimeLab;
private List<Crime> mCrimes;
public static CrimeLab get(Context context) {
if (sCrimeLab == null) {
sCrimeLab = new CrimeLab(context);
}
return sCrimeLab;
}
private CrimeLab(Context context){
mCrimes = new ArrayList<>();
for (int i = 0; i < 100; i++) {
Crime crime = new Crime();
crime.setTitle("Crime #" + i);
crime.setSolved(i % 2 == 0);
if (i % 4 == 0 ) {crime.setRequiresPolice(true);}
else {crime.setRequiresPolice(false);}
mCrimes.add(crime);
}
}
public List<Crime> getCrimes() {
return mCrimes;
}
public Crime getCrime(UUID id){
for (Crime crime : mCrimes){
int rez = id.compareTo(crime.getId());
if (crime.getId().equals(id)){
return crime;
}
}
return null;
}
}
CrimeListFragment.java
package com.bignerdranch.android.criminalintent;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.LayoutRes;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.Date;
import java.util.List;
public class CrimeListFragment extends Fragment {
private static final int REQUEST_CRIME = 1;
private static final int NOT_REQUIRES_POLICE = 0;
private static final int REQUIRES_POLICE = 1;
private RecyclerView mCrimeRecyclerView;
private CrimeAdapter mAdapter;
private TextView mTitleTextView;
private TextView mDateTextView;
private ImageView mSolvedImageView;
private Button mButtonCallPolice;
private Crime mCrime;
private CharSequence mDateFormat;
private int layout;
@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 class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public CrimeHolder(int layout, LayoutInflater inflater, ViewGroup parent ) {
super(inflater.inflate(layout, parent, false));
mTitleTextView = (TextView) itemView.findViewById(R.id.crime_title);
mDateTextView = (TextView) itemView.findViewById(R.id.crime_date);
mSolvedImageView = (ImageView) itemView.findViewById(R.id.crime_solved);
if (itemView.findViewById(R.id.call_police)!=null) {
mButtonCallPolice = (Button) itemView.findViewById(R.id.call_police);
}
itemView.setOnClickListener(this);
}
public void bind(Crime crime) {
mCrime = crime;
mTitleTextView.setText(mCrime.getTitle());
mDateFormat = DateFormat.format("EEE, MMM dd, yyyy", mCrime.getDate());
mDateTextView.setText(mDateFormat);
mSolvedImageView.setVisibility(mCrime.isSolved() ? View.VISIBLE :
View.GONE);
if(mCrime.isRequiresPolice()){
mButtonCallPolice.setEnabled(true);
}
}
@Override
public void onClick(View view) {
Intent intent = CrimePagerActivity.newIntent(getActivity(),
CrimeLab.get(requireActivity()).getCrimes().get((getAdapterPosition())).getId());
startActivityForResult(intent, REQUEST_CRIME);
}
}
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) {
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
if (viewType==1) { layout = R.layout.list_item_crime_police;}
else { layout = R.layout.list_item_crime; }
return new CrimeHolder (layout, layoutInflater, parent);
}
@Override
public void onBindViewHolder(CrimeHolder holder, int position) {
Crime crime = mCrimes.get(position);
holder.bind(crime);
}
@Override
public int getItemCount() {
return mCrimes.size();
}
public int getItemViewType(int position) {
Crime crime = mCrimes.get(position);
return (crime.isRequiresPolice()) ? 1 : 0;
}
}
@Override
public void onResume() {
super.onResume();
updateUI();
}
private void updateUI() {
CrimeLab crimeLab = CrimeLab.get(getActivity());
List<Crime> crimes = crimeLab.getCrimes();
if (mAdapter == null) {
mAdapter = new CrimeAdapter(crimes);
mCrimeRecyclerView.setAdapter(mAdapter);
} else {
mAdapter.notifyDataSetChanged();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CRIME) {
// Обработка результата
}
}
public void returnResult() {
getActivity().setResult(Activity.RESULT_OK, null);
}
}
CrimePagerActivity.java
package com.bignerdranch.android.criminalintent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import java.util.List;
import java.util.UUID;
public class CrimePagerActivity extends AppCompatActivity {
private static final String EXTRA_CRIME_ID = "com.bignerdranch.android.criminalintent.crime_id";
private ViewPager mViewPager;
private List<Crime> mCrimes;
MyAdapter mAdapter;
public static Intent newIntent(Context packageContext, UUID crimeId) {
Intent intent = new Intent(packageContext, CrimePagerActivity.class);
intent.putExtra(EXTRA_CRIME_ID, crimeId);
return intent;
}
@Override
protected void onCreate( Bundle savedInstanceState ) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crime_pager);
UUID crimeId = (UUID) getIntent().getSerializableExtra(EXTRA_CRIME_ID);
mViewPager = (ViewPager) findViewById(R.id.crime_view_pager);
mCrimes = CrimeLab.get(this).getCrimes();
mAdapter = new MyAdapter(getSupportFragmentManager(),mCrimes);
mViewPager.setAdapter(mAdapter);
for (int i = 0; i < mCrimes.size(); i++) {
if (mCrimes.get(i).getId().equals(crimeId)) {
mViewPager.setCurrentItem(i);
break;
}
}
}
public static class MyAdapter extends FragmentStatePagerAdapter {
private List<Crime> mCrimesCopy;
public MyAdapter(FragmentManager fm, List<Crime> mCrimesParametr) {
//super(fm);
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
this.mCrimesCopy = mCrimesParametr;
}
@Override
public int getCount() {
return mCrimesCopy.size();
}
@Override
public Fragment getItem(int position) {
Crime crime = mCrimesCopy.get(position);
return CrimeFragment.newInstance(crime.getId());
}
}
}
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"/>
fragment_crime.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:orientation="vertical">
<TextView
style="?android:listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/crime_title_label"/>
<EditText
android:id="@+id/crime_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/crime_title_hint"
android:inputType=""
android:autofillHints="" />
<TextView
style="?android:listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/crime_details_label"/>
<Button
android:id="@+id/crime_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<CheckBox
android:id="@+id/crime_solved"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/crime_solved_label"/>
</LinearLayout>
list_item_crime_police.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/crime_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="@string/crime_title"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_constraintEnd_toStartOf="@+id/crime_solved"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/crime_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="@string/crime_date"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/crime_solved" />
<Button
android:id="@+id/call_police"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:text="@string/call_police"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/crime_date" />
<ImageView
android:id="@+id/crime_solved"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
android:contentDescription="@string/todo"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_solved" />
</androidx.constraintlayout.widget.ConstraintLayout>
list_item_crime.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/crime_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:text="@string/crime_title"
android:textColor="@android:color/black"
android:textSize="18sp"
app:layout_constraintEnd_toStartOf="@+id/crime_solved"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/crime_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:text="@string/crime_date"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/crime_solved" />
<ImageView
android:id="@+id/crime_solved"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_solved"
android:contentDescription="@string/todo" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_crime_pager.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.viewpager.widget.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/crime_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.viewpager.widget.ViewPager>
activity_fragment.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" />
I think the items in the RecyclerView
are unordered because the references for views
which are present in your list_item_crime_police.xml
or list_item_crime.xml
layout file is declared as class members of CrimeListFragment
and not inside CrimeHolder
class as:
public class CrimeListFragment extends Fragment {
// your other views and variables related declarations
// these are problematic declaration that keeps on being reused
private TextView mTitleTextView;
private TextView mDateTextView;
private ImageView mSolvedImageView;
private Button mButtonCallPolice;
// your other declarations
// your other code
}
That's why, the same view
instances such as mTitleTextView
, mDateTextView
, mSolvedImageView
, mButtonCallPolice
, etc. are being reused for every CrimeHolder
instances causing the unordering of the items in the list. Now, in order to fix this problem, you can simply move these lines to code to CrimeHolder
class as class variable which would ensures that every new CrimeHolder
instance will have separate instances of above-mentioned views as:
private class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
// declare all of them here so there will be unique instances of these views for unique viewholder
private TextView mTitleTextView;
private TextView mDateTextView;
private ImageView mSolvedImageView;
private Button mButtonCallPolice;
public CrimeHolder(int layout, LayoutInflater inflater, ViewGroup parent ) {
View itemView = inflater.inflate(layout, parent, false));
super(itemView);
mTitleTextView = (TextView) itemView.findViewById(R.id.crime_title);
mDateTextView = (TextView) itemView.findViewById(R.id.crime_date);
mSolvedImageView = (ImageView) itemView.findViewById(R.id.crime_solved);
if (itemView.findViewById(R.id.call_police)!=null) {
mButtonCallPolice = (Button) itemView.findViewById(R.id.call_police);
}
itemView.setOnClickListener(this);
}
public void bind(Crime crime) {
mCrime = crime;
mTitleTextView.setText(mCrime.getTitle());
mDateFormat = DateFormat.format("EEE, MMM dd, yyyy", mCrime.getDate());
mDateTextView.setText(mDateFormat);
mSolvedImageView.setVisibility(mCrime.isSolved() ? View.VISIBLE :
View.GONE);
if(mCrime.isRequiresPolice()){
mButtonCallPolice.setEnabled(true);
}
}
@Override
public void onClick(View view) {
Intent intent = CrimePagerActivity.newIntent(getActivity(),
CrimeLab.get(requireActivity()).getCrimes().get((getAdapterPosition())).getId());
startActivityForResult(intent, REQUEST_CRIME);
}
}
It fixed my problem and I hope it will fix yours too.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.