Search code examples
androidandroid-recyclerviewandroid-cardview

Data on cardview are changed while scrolling RecyclerView


I am newbie to Android apps development. I have a class, which contains RecyclerView.

public class ScreenOne extends Fragment implements SwipeRefreshLayout.OnRefreshListener {

    private RecyclerView mRecyclerView;
    private FilmSetAdapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;

    SwipeRefreshLayout mSwipeRefreshLayout;

    RequestTask requestTask;
    ArrayList<Film> listOfFilms;
    ArrayList<Cinema> listOfCinemas;
    ArrayList<String> cityIDs;

    public ScreenOne() {
    }

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

        View rootView = inflater.inflate(R.layout.screen_one, container,
                false);

        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
        mLayoutManager = new LinearLayoutManager(getActivity());
        //mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(mLayoutManager);
        //mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        listOfFilms = new ArrayList<>();
        mAdapter = new FilmSetAdapter(listOfFilms);
        mRecyclerView.setAdapter(mAdapter);

        mSwipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh);
        mSwipeRefreshLayout.setOnRefreshListener(this);
        mSwipeRefreshLayout.setColorScheme(R.color.blue, R.color.cyan, R.color.grey_blue, R.color.lightblue);

        try {
            updateFilms();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return rootView;
    }


    private void updateFilms() throws InterruptedException {
        requestTask = new RequestTask();
        try {
            requestTask.execute().get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    private boolean isNetworkConnected() {
        ConnectivityManager cm =
                (ConnectivityManager) getActivity().getSystemService(getActivity().CONNECTIVITY_SERVICE);
        NetworkInfo netInfo = cm.getActiveNetworkInfo();
        return netInfo != null && netInfo.isConnectedOrConnecting();
    }

    @Override
    public void onRefresh() {
        Toast.makeText(getActivity(), R.string.refresh_started, Toast.LENGTH_SHORT).show();
        mSwipeRefreshLayout.setRefreshing(true);
        mAdapter.setDataset(new ArrayList<Film>());
        mAdapter.notifyDataSetChanged();
        try {
            updateFilms();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        DatabaseHandler database = new DatabaseHandler(getActivity());
        mAdapter = new FilmSetAdapter(database.getAllFilms());
        mRecyclerView.swapAdapter(mAdapter, false);
        database.close();

        mSwipeRefreshLayout.postDelayed(new Runnable() {
            @Override
            public void run() {
                mSwipeRefreshLayout.setRefreshing(false);
                Toast.makeText(getActivity(), R.string.refresh_finished, Toast.LENGTH_SHORT).show();
            }
        }, 3000);
    }

    class RequestTask extends AsyncTask<Void, Void, Void> {

        protected void getPreferenciesCity()
        {
            cityIDs = new ArrayList<>();
            SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
            SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
            Set<String> selections = sharedPrefs.getStringSet("cities", null);
            try {
                Log.d("SHARED PREFERENCES CITY", selections.toString());
                cityIDs.addAll(selections);
            }catch (NullPointerException e){Log.d("SHARED PREFERENCES CITY", "SP are empty");}

        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            listOfFilms = new ArrayList<>();
            getPreferenciesCity();
        }

        @Override
        protected Void doInBackground(Void... params) {
            if(isNetworkConnected()) {
                DatabaseHandler database = new DatabaseHandler(getActivity());
                database.clearFilms();
                try {
                    HttpHandler httpHandler = new HttpHandler();
                    listOfFilms = new ArrayList<>(httpHandler.listOfFilmsRequest(cityIDs));
                    listOfCinemas = new ArrayList<>(httpHandler.listOfCinemasRequest());

                    Film film;
                    Cinema cinema;
                    for (Iterator<Film> filmiterator = listOfFilms.iterator(); filmiterator.hasNext(); ) {
                        film = filmiterator.next();
                        if (database.isInDatabase(film.getID()))
                            database.updateFilm(film);
                        else
                            database.addFilm(film);
                    }

                    for (Iterator<Cinema> cinemaiterator = listOfCinemas.iterator(); cinemaiterator.hasNext(); ) {
                        cinema = cinemaiterator.next();
                        if (database.CinemaIsInDatabase(cinema.getIDCinema()))
                            database.updateCinema(cinema);
                        else
                            database.addCinema(cinema);
                    }
                    database.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            DatabaseHandler database = new DatabaseHandler(getActivity());
            mAdapter.setDataset(database.getAllFilms());
            mAdapter.notifyDataSetChanged();
        }
    }
}

It executes a method, which is placed in the AsyncTask class. This method downloads data from server, puts it to database first and after that sets the recycler view adapter. The problem is that sometimes text data are changed while scrolling it. See attached video.

Code of adapter is:

public class FilmSetAdapter extends RecyclerView.Adapter<FilmSetAdapter.ViewHolder>{

    private ArrayList<Film> mDataset;
    final static String LOG_TAG = "FilmSetAdapter";

    public void setDataset(ArrayList<Film> allFilms) {
        mDataset = new ArrayList<>(allFilms);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public static TextView filmTitle;
        public TextView country;
        public TextView ticketsFrom;
        public TextView rating;
        public TextView format;
        public ImageView poster;
        public int id;

        public ViewHolder(final View itemView) {
            super(itemView);
            filmTitle = (TextView) itemView.findViewById(R.id.filmtitle);
            country = (TextView)itemView.findViewById(R.id.country);
            ticketsFrom = (TextView) itemView.findViewById(R.id.ticketsfrom);
            rating = (TextView)itemView.findViewById(R.id.rating);
            poster = (ImageView) itemView.findViewById(R.id.poster);
            format = (TextView) itemView.findViewById(R.id.format);
            format.setTypeface(null, Typeface.BOLD_ITALIC);
        }
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.cardview, parent, false);

        final ViewHolder vh = new ViewHolder(v);
        v.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                Log.d(LOG_TAG, "Нажата карточка. Вызов из activity "+v.toString());
                Intent intent = new Intent(v.getContext(),FilmInfoActivity.class);
                intent.putExtra("EXTRA_FILM_ID", vh.id);
                v.getContext().startActivity(intent);
            }
        });
        return vh;
    }

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        holder.filmTitle.setText(mDataset.get(position).getTitle().toString()+" ID="+mDataset.get(position).getID()+" POS="+position);
        holder.country.setText(mDataset.get(position).getCountry());
        holder.ticketsFrom.setText(holder.ticketsFrom.getContext().getString(R.string.tickets_from) +
                mDataset.get(position).getRating().toString());
        holder.rating.setText(holder.rating.getContext().getString(R.string.rating_kinopoisk) +
                mDataset.get(position).getRating());
        holder.id = mDataset.get(position).getID();
        holder.format.setText(mDataset.get(position).getFormat());

        Picasso.with(holder.poster.getContext()).
                load(mDataset.get(position).getPoster()).
                skipMemoryCache().
                into(holder.poster);
    }

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

    public FilmSetAdapter(ArrayList<Film> myDataset) {
        mDataset = new ArrayList<>(myDataset);
    }
}

I have no clue on how to sort it out.


Solution

  • it seem to that there is a typo mistake in your code, look at that, you have in your ViewHolder:

        public static TextView filmTitle;
    

    But then you work with it like with your other fields:

    @Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        holder.filmTitle.setText(mDataset.get(position).getTitle() + ...);
    ...   
    }
    

    A little advice for you as a newbie: just.. pay more attention to your code, and you'll be fine in programming :)