Set counter inside RecyclerView

偶尔善良 提交于 2019-12-01 09:29:23

问题


I have count down timer as image below :

now these timers will start count down in each item, i tried many times to change this from my Adapter and it's not work,here is my code:

Edit :

public class AdapterItems extends RecyclerView.Adapter {

private ArrayList<TopCompetitions> mListItems = new ArrayList<>();
private ImageLoader mImageLoader;
private Context context;
private Handler handler;
/******************************************/
String current_date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d1 = null;
Date d2 = null;
long diff;
long diffSeconds;
long diffMinutes;
long diffHours;
long diffDays;

String reachableDate = "";
/******************************************/
private ScheduledFuture updateFuture;

public AdapterItems(Context context) {

    this.context = context;
    mImageLoader = AppController.getInstance().getImageLoader();

}

public void setmListItems(ArrayList<TopCompetitions> mListItems) {
    this.mListItems = mListItems;
    //update the adapter to reflect the new set of mListItems
    notifyDataSetChanged();
}


@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {


    View itemView = LayoutInflater.
            from(parent.getContext()).
            inflate(R.layout.custom_horizontal_row, parent, false);
    return new ItemHolder(itemView);


}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {


    final TopCompetitions currentItem = mListItems.get(position);
    final ItemHolder itemHolder = (ItemHolder) holder;

   /* start_date , name_com_ar , name_com_en,
            question_en,answer_ar1,answer_ar2,answer_ar3
            ,answer_en1,answer_en2,answer_en3,right_answer;
    */
    itemHolder.item_id.setText(currentItem.getPrize_id());
    itemHolder.item_description.setText(currentItem.getName_com_ar());
    itemHolder.start_date.setText(currentItem.getStart_date());
    itemHolder.end_date.setText(currentItem.getEnd_date());
    itemHolder.name_com_ar.setText(currentItem.getName_com_ar());
    itemHolder.name_com_en.setText(currentItem.getName_com_en());
    itemHolder.answer_en1.setText(currentItem.getAnswer_en1());
    itemHolder.answer_en2.setText(currentItem.getAnswer_en2());
    itemHolder.answer_en3.setText(currentItem.getAnswer_en3());
    itemHolder.answer_ar1.setText(currentItem.getAnswer_ar1());
    itemHolder.answer_ar2.setText(currentItem.getAnswer_ar2());
    itemHolder.answer_ar3.setText(currentItem.getAnswer_ar3());
    itemHolder.right_answer.setText(currentItem.getRight_answer());
    itemHolder.question_en.setText(currentItem.getQuestion_en());
    itemHolder.question_ar.setText(currentItem.getQuestion_ar());
    itemHolder.desc_ar.setText(currentItem.getPrize_desc_ar());
    itemHolder.desc_en.setText(currentItem.getPrize_desc_en());

    String urlLogo = currentItem.getPrize_pic1();
    loadImages(urlLogo, itemHolder);
    setDefferinceTimer(itemHolder , currentItem.getEnd_date());


    if (updateFuture == null) {
        final Handler mainHandler = new Handler(Looper.getMainLooper());
        updateFuture = Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                setDefferinceTimer(itemHolder , currentItem.getEnd_date());
                notifyDataSetChanged();
                mainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        notifyDataSetChanged();
                    }
                });
            }
        }, 0, 1000, TimeUnit.MILLISECONDS);
    }

  /*  new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            new CountDownTimer(20000, 1000) {

                public void onTick(long millisUntilFinished) {
                    startCountDown(itemHolder, currentItem.getEnd_date() + " 00:00:00");
                    notifyDataSetChanged();
                }

                public void onFinish() {
                    //counterTextView.setText("done!");
                }
            }.start();
        }
    });
      */

}

public void setDefferinceTimer(final RecyclerView.ViewHolder holder , String itemEndDate){

    final ItemHolder itemHolder = (ItemHolder) holder;

    current_date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
   // reachableDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(itemEndDate);

    try {
        d1 = format.parse(current_date);
        d2 = format.parse(itemEndDate+" 00:00:00");
    } catch (ParseException e) {
        e.printStackTrace();
    }

    diff = d2.getTime() - d1.getTime();

    diffSeconds = diff / 1000 % 60;
    diffMinutes = diff / (60 * 1000) % 60;
    diffHours = diff / (60 * 60 * 1000) % 24;
    diffDays = diff / (24 * 60 * 60 * 1000);

    itemHolder.days_tf.setText(""+diffDays);
    itemHolder.hours_tf.setText(""+diffHours);
    itemHolder.minutes_tf.setText(""+diffMinutes);
    itemHolder.seconds_tf.setText(""+diffSeconds);

}

private void loadImages(String urlThumbnail, final RecyclerView.ViewHolder holder) {
    final ItemHolder itemHolder = (ItemHolder) holder;
    mImageLoader.get(urlThumbnail, new ImageLoader.ImageListener() {
        @Override
        public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
            itemHolder.item_image.setImageBitmap(response.getBitmap());
            //holder.salon_gender.setImageBitmap(response.getBitmap());
        }

        @Override
        public void onErrorResponse(VolleyError error) {

        }
    });
}


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


private class ItemHolder extends RecyclerView.ViewHolder {

    public TextView item_id, item_description, end_date,
            start_date, name_com_ar, name_com_en, question_ar,
            question_en, answer_ar1, answer_ar2, answer_ar3, answer_en1,
            answer_en2, answer_en3, right_answer , desc_ar , desc_en;
    public TextView days_tf, hours_tf, minutes_tf, seconds_tf;
    public CircleImageView item_image;

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

        start_date = (TextView) itemView.findViewById(R.id.start_date);
        end_date = (TextView) itemView.findViewById(R.id.end_date);
        name_com_ar = (TextView) itemView.findViewById(R.id.name_com_ar);
        name_com_en = (TextView) itemView.findViewById(R.id.name_com_en);
        question_en = (TextView) itemView.findViewById(R.id.question_en);
        question_ar = (TextView) itemView.findViewById(R.id.question_ar);
        desc_ar = (TextView) itemView.findViewById(R.id.desc_ar);
        desc_en = (TextView) itemView.findViewById(R.id.desc_en);
        answer_ar1 = (TextView) itemView.findViewById(R.id.answer_ar1);
        answer_ar2 = (TextView) itemView.findViewById(R.id.answer_ar2);
        answer_ar3 = (TextView) itemView.findViewById(R.id.answer_ar3);
        answer_en1 = (TextView) itemView.findViewById(R.id.answer_en1);
        answer_en2 = (TextView) itemView.findViewById(R.id.answer_en2);
        answer_en3 = (TextView) itemView.findViewById(R.id.answer_en3);
        right_answer = (TextView) itemView.findViewById(R.id.right_answer);


        item_id = (TextView) itemView.findViewById(R.id.item_id);
        item_description = (TextView)              itemView.findViewById(R.id.item_description);
        item_image = (CircleImageView) itemView.findViewById(R.id.item_image);


        days_tf = (TextView) itemView.findViewById(R.id.days_tf);
        hours_tf = (TextView) itemView.findViewById(R.id.hours_tf);
        minutes_tf = (TextView) itemView.findViewById(R.id.minutes_tf);
        seconds_tf = (TextView) itemView.findViewById(R.id.seconds_tf);

    }



}

回答1:


Edit

Here's a sample that can be used to update the visible items in your RecyclerView. I assume you use LinearLayoutManager for your RecyclerView's layout.

First of all, remove CountDownTimer from your code. The problem with it is that it uses the main thread's looper to loop through the messages (actually it uses the "current thread" but since you initialize it in your main thread, current thread is main thread now) and it can only be scheduled for a finite interval.

Now the new part. Assume there's your fragment that inits the RecyclerView and all its related parts. Let's say that these are the fields available in your fragment:

private AdapterItems myAdapter;
private LinearLayoutManager layoutManager;
private ScheduledFuture updateFuture;

Then put the following part into your onCreateView(...) after you're done with all the view, adapter and other initializations:

if (updateFuture == null) {
    final Handler mainHandler = new Handler(Looper.getMainLooper());
    updateFuture = Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            final int firstVisible = layoutManager.findFirstVisibleItemPosition();
            final int lastVisible = layoutManager.findLastVisibleItemPosition();

            mainHandler.post(new Runnable() {
                @Override
                public void run() {
                    myAdapter.notifyItemRangeChanged(firstVisible, lastVisible - firstVisible + 1);
                }
            });
        }
    }, 0, 1000, TimeUnit.MILLISECONDS);
}

Here's a little explanation of the code. We create a new single threaded ScheduledExecutorService which can be used to schedule runnables at fixed rate (scheduleAtFixedRate(...)). Every 1000 milliseconds from the call of this method, there's going to be a new execution.

Now the inner part. Every layout manager (except the base class LayoutManager) has two very important methods: findFirstVisibleItemPosition() and findLastVisibleItemPosition(). As the names show, these can be used to find the first and last visible items' position in the adapter. Then we use these informations to call the RecyclerView's adapter's (myAdapter) notifyItemRangeChanged(...) which will update only the given items' view in the range by calling onBindViewHolder(...) automatically.

Note the mainHandler which is used to call the notifyItemRangeChanged(...) method on the UI thread as you cannot update the UI from a non-UI thread (and the one created by the ScheduledExecutorService is non-UI).

Don't forget to cancel your ScheduledFuture when you don't need the updates anymore by calling its cancel() method (e.g. in your fragment's onDestroyView()).

if (updateFuture != null) {
    updateFuture.cancel(true);
    updateFuture = null;
}

Original

You have your Items class which, I assume, contains all the data (images, text, etc.) for the list items. You should put the target date to this class as well, this way all your items can have different target dates. If you want to update this date later on, you'll have to change it in the appropriate Items instance and call notifyItemChanged(position) on your adapter.




回答2:


Here you can find the source code of Countdown Timer in Recycler Listview here

Adapter.java

import android.os.CountDownTimer;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.ArrayList;

public class Adapter extends RecyclerView.Adapter{

private ArrayList al_data;

public class MyViewHolder extends RecyclerView.ViewHolder{
    public TextView tv_timer;
    CountDownTimer timer;

    public MyViewHolder (View view){
        super(view);
        tv_timer = (TextView)view.findViewById(R.id.tv_timer);

    }


}

public Adapter(ArrayList al_data) {
    this.al_data = al_data;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_layout,parent,false);


    return new MyViewHolder(view);
}

@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {

    holder.tv_timer.setText(al_data.get(position));

    if (holder.timer != null) {
        holder.timer.cancel();
    }
     long timer = Long.parseLong(al_data.get(position));

    timer = timer*1000;

    holder.timer = new CountDownTimer(timer, 1000) {
        public void onTick(long millisUntilFinished) {
          holder.tv_timer.setText("" + millisUntilFinished/1000 + " Sec");
        }

        public void onFinish() {
            holder.tv_timer.setText("00:00:00");
        }
    }.start();


}

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



}


来源:https://stackoverflow.com/questions/32166375/set-counter-inside-recyclerview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!