如何在RecyclerView中处理多个倒计时器?

时间:2015-08-27 19:06:58

标签: android android-layout android-intent android-recyclerview countdown

我有一个Recyclerview,我需要在每一行显示一个倒计时。

这是一个类似的问题 coutndown timers in listview 它有一个很好的解决方案,但我需要使用recyclerview

它有一个很好的解决方案,但我需要使用recyclerview

enter image description here

修改

我在尝试,这是我的代码适配器 MyAdapter

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

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);

    }



}

6 个答案:

答案 0 :(得分:2)

CountDownTimer中添加ViewHolder成员。在getView()中设置并启动计数器,并且不要忘记在ViewHolder的同一实例中取消任何现有的计数器。在onTick()中,您需要更新显示屏上的值,而不是启动计数器。

答案 1 :(得分:2)

简单的解决方案是:

Handler handler=new Handler();
handler.postDelayed(new UpdateTimerThread(holder),0); 

public Class UpdateTimerThread implements Runnable{
Holder holder;

    public UpdateTimerThread(Holder holder){
        this.holder=holder;
    }
    @Override
    public void run() {
        lgetCreatedTime = lgetCreatedTime + 1000;
        long diffSeconds;
        long diffMinutes;
        long diffHours;
        diffSeconds = lgetCreatedTime / 1000 % 60;
        diffMinutes = lgetCreatedTime / (60 * 1000) % 60;
        diffHours = lgetCreatedTime / (60 * 60 * 1000) % 24;
        holder.GameTimer.setText(String.format("%02d:%02d:%02d", diffHours,   diffMinutes, diffSeconds));
        handler.postDelayed(this,1000);
    }
}

注意: 1.holder是ViewHolder类的对象

2.创建一个类UpdateTimerThread实现Runnable

3.将日期和时间转换为长并存入lgetCreatedTime

4.Run Handler每1秒打勾时间

答案 2 :(得分:0)

您可以在ViewHolder类中创建CountDownTimer引用,并在适配器的onBindViewHolder方法中创建其实例。

效果很好。

自我测试。

答案 3 :(得分:0)

6小时后,我终于找到了使用方法。但是,我在Runnable中找不到相同的方式。

我正在使用此代码,它对我有用:

@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
    try {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date event_date = dateFormat.parse(laterStart.toString());
        current_date = dateFormat.parse(laterCurrent.toString());
        Date diff = event_date.getTime() - current_date.getTime();

    } catch (Exception e) {
        e.printStackTrace();
    }

    //Very important code for some problems
    if (holder.timer != null) {
        holder.timer.cancel();
    }

    holder.timer = new CountDownTimer(diff, 900) {
        @Override
        public void onTick(long millisUntilFinished) {
            long day = TimeUnit.MILLISECONDS.toDays(millisUntilFinished);
            millisUntilFinished -= TimeUnit.DAYS.toMillis(day);

            long hour = TimeUnit.MILLISECONDS.toHours(millisUntilFinished);
            millisUntilFinished -= TimeUnit.HOURS.toMillis(hour);

            long minute = TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished);
            millisUntilFinished -= TimeUnit.MINUTES.toMillis(minute);

            long second = TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished);


            holder.timeText.setText(day+":"+hour+":"+minute+":"+second);
        }

        @Override
        public void onFinish() {
        }
    }.start();
}

和RecycleView ViewHolder类:

public class ViewHolder extends RecyclerView.ViewHolder {
***your codes***

   //Just add CountDownTimer
   CountDownTimer timer;

*** your codes ***
}

答案 4 :(得分:0)

在这里我要扩展 AppCompatTextView 并在其中添加 CountDownTimer。我正在处理 onStoponStart,以便 CountDownTimer 在后台不起作用。

class TimeCounterView : androidx.appcompat.widget.AppCompatTextView {
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

var countDownTimer: CountDownTimer? = null

fun startCountDown(expireTimeStamp: Long, removeItem: () -> Unit) {
    stopCounter()
    text = calculateTimeExpire(expireTimeStamp)//custom method to calculate time until expireTime
    countDownTimer = object : CountDownTimer(
        expireTimeStamp * 1000 - System.currentTimeMillis(),
        ONE_MINUTE_MILLIS / 16
    ) {
        override fun onTick(millisUntilFinished: Long) {
            text = calculateTimeExpire(expireTimeStamp)
        }

        override fun onFinish() {
            text = context.getString(R.string.choice_finished)
            removeItem()
        }
    }
    countDownTimer?.start()
}

fun stopCounter() {
    countDownTimer?.cancel()
}

companion object {
    const val ONE_MINUTE_MILLIS: Long = 60000
}
}

然后像这样在你的 itemview xml 中使用它作为普通视图

....
    <com.example.custom.TimeCounterView
        android:id="@+id/timeTV"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp"
        android:layout_weight="0"
        android:textColor="@color/colorText"
        tools:text="23:59" />
....

然后在您的适配器中,您将需要实现非常重要的方法 onViewRecycled,该方法将被调用以从计时器对象中释放内存。

 override fun onViewRecycled(holder: ChannelChoiceViewHolder) {
        super.onViewRecycled(holder)
        holder.stopCounter()
    }

然后在持有人内你会这样做

fun bind(item: ChannelPageChoice, position: Int) {
    //...
    binding.timeTV.startCountDown(item.expire){ removeItem(position) }
    //...
}
fun stopCounter() {
    binding.timeTV.stopCounter()
}

然后在活动/片段中,您必须在 onStop 中将 recyclerview 设置为 null 并通过执行此操作在 onStart 中再次重新附加它 onViewRecycled 将在您的所有视图上调用,并且如果回收器将停止计时器在屏幕上不可见。

override fun onStop() {
    super.onStop()
    currentItemPosition =
        (binding.recyclerView.layoutManager as? LinearLayoutManager)
            ?.findFirstVisibleItemPosition() ?: 0

    binding.recyclerView.adapter = null
}

override fun onStart() {
    super.onStart()
    binding.recyclerView.adapter = myCustomAdapter
    binding.recyclerView.scrollToPosition(currentItemPosition)
}

答案 5 :(得分:-1)

您可以在此处查看并下载Countdown timers in a RecyclerView

的源代码

<强> activity_main.xml中

<RelativeLayout android:layout_width=”match_parent”
android:layout_height=”match_parent”
xmlns:android=”http://schemas.android.com/apk/res/android”&gt;

<android.support.v7.widget.RecyclerView
android:id=”@+id/recycler_view”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:scrollbars=”vertical” />

</RelativeLayout>

<强> adapter_layout.xml

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

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="15dp"
    android:padding="10dp"
    android:id="@+id/tv_timer"/>

</LinearLayout>

<强> MainActivity.java

package com.androidsolutionworld.multipletimer;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.LinearLayout;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ArrayList al_data = new ArrayList<>();
private Adapter obj_adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    recyclerView = (RecyclerView)findViewById(R.id.recycler_view);
    al_data.add("1234");
    al_data.add("1257");
    al_data.add("100");
    al_data.add("1547");
    al_data.add("200");
    al_data.add("500");
    al_data.add("2000");
    al_data.add("1000");

    obj_adapter = new Adapter(al_data);
    LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext(),LinearLayoutManager.VERTICAL,false);
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setAdapter(obj_adapter);
}
}

自定义适配器:

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();
}

}