Java 什么会导致计时器在RecyclerView中闪烁?
我正在尝试为用户生成的帖子创建一个计时器,该计时器显示在帖子上。我正在使用Firestore来存储关于帖子的所有信息 我的代码确实显示了计时器,但当多个用户发布多篇文章时,计时器在正确的时间和另一个倒计时之间闪烁,就我所见,倒计时与倒计时无关。以下是我所拥有的: 这就是我创建每个帖子的方式Java 什么会导致计时器在RecyclerView中闪烁?,java,android,google-cloud-firestore,countdowntimer,Java,Android,Google Cloud Firestore,Countdowntimer,我正在尝试为用户生成的帖子创建一个计时器,该计时器显示在帖子上。我正在使用Firestore来存储关于帖子的所有信息 我的代码确实显示了计时器,但当多个用户发布多篇文章时,计时器在正确的时间和另一个倒计时之间闪烁,就我所见,倒计时与倒计时无关。以下是我所拥有的: 这就是我创建每个帖子的方式 post.setTimer(data.getStringExtra("timerDuration")); Calendar cal = Calendar.getInstance(); cal.add(Cale
post.setTimer(data.getStringExtra("timerDuration"));
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, setEndDate());
Date endtime = cal.getTime();
post.setTimerEndDate(endtime);
addPhotoInfoToDatabase();
finish();
片段的我的适配器:
adapter = new FirestoreRecyclerAdapter<Post, PostViewHolder>(options) {
@Override
protected void onBindViewHolder(@NonNull PostViewHolder postViewHolder, int position, @NonNull Post post) {
postViewHolder.setPost(post);
}
@NonNull
@Override
public PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_view_layout, parent, false);
return new PostViewHolder(view);
}
};
每次创建新计时器时,
RecyclerView
中的项目在滚动后被回收。每次滚动项目时,timeLeft
变量也会更改,这会初始化一个新的计时器,我想这就是闪烁的原因
因此,我建议在适配器中安装一个阵列。这是用来保存所有的倒计时。在适配器的构造函数中,正确初始化它以获得正确的值。让我们以下面的示例实现为例
CountDownTimer[] timers = new CountDownTimer[data.size()];
// Let us assume the list of Data is dataItems which is being passed to your adapter.
// Your constructor might take other parameters
public MyAdapter(ArrayList<Data> dataItems) {
for(int i = 0; i < dataItems.size(); i++) {
long timeLeft = getTimeLeftValue(dataItems.get(i));
timers[i] = new CountDownTimer(timeLeft, 1000) {
@SuppressLint("DefaultLocale")
public void onTick(long millisUntilFinished) {
timer.setText(String.format("%d:%d:%d",
(int) ((millisUntilFinished / (1000 * 60 * 60)) % 24),
(int) ((millisUntilFinished / (1000 * 60)) % 60),
(int) (millisUntilFinished / 1000) % 60));
//here you can have your logic to set text to edittext
}
public void onFinish() {
timer.setText("done!");
}
}.start();
}
}
private long getTimeLeftValue(Data post) {
Date date = java.util.Calendar.getInstance().getTime();
long currentTime = date.getTime();
long endTime = post.getTimerEndDate().getTime();
timeLeft = endTime - currentTime;
return timeLeft.
}
声明两个数组,如下所示
CountDownTimer[] timers = new CountDownTimer[data.size()];
// Let us assume the list of Data is dataItems which is being passed to your adapter.
// Your constructor might take other parameters
public MyAdapter(ArrayList<Data> dataItems) {
for(int i = 0; i < dataItems.size(); i++) {
long timeLeft = getTimeLeftValue(dataItems.get(i));
timers[i] = new CountDownTimer(timeLeft, 1000) {
@SuppressLint("DefaultLocale")
public void onTick(long millisUntilFinished) {
timer.setText(String.format("%d:%d:%d",
(int) ((millisUntilFinished / (1000 * 60 * 60)) % 24),
(int) ((millisUntilFinished / (1000 * 60)) % 60),
(int) (millisUntilFinished / 1000) % 60));
//here you can have your logic to set text to edittext
}
public void onFinish() {
timer.setText("done!");
}
}.start();
}
}
private long getTimeLeftValue(Data post) {
Date date = java.util.Calendar.getInstance().getTime();
long currentTime = date.getTime();
long endTime = post.getTimerEndDate().getTime();
timeLeft = endTime - currentTime;
return timeLeft.
}
现在,在适配器的构造函数中执行如下操作
CountDownTimer[] timers = new CountDownTimer[data.size()];
// Let us assume the list of Data is dataItems which is being passed to your adapter.
// Your constructor might take other parameters
public MyAdapter(ArrayList<Data> dataItems) {
for(int i = 0; i < dataItems.size(); i++) {
long timeLeft = getTimeLeftValue(dataItems.get(i));
timers[i] = new CountDownTimer(timeLeft, 1000) {
@SuppressLint("DefaultLocale")
public void onTick(long millisUntilFinished) {
timer.setText(String.format("%d:%d:%d",
(int) ((millisUntilFinished / (1000 * 60 * 60)) % 24),
(int) ((millisUntilFinished / (1000 * 60)) % 60),
(int) (millisUntilFinished / 1000) % 60));
//here you can have your logic to set text to edittext
}
public void onFinish() {
timer.setText("done!");
}
}.start();
}
}
private long getTimeLeftValue(Data post) {
Date date = java.util.Calendar.getInstance().getTime();
long currentTime = date.getTime();
long endTime = post.getTimerEndDate().getTime();
timeLeft = endTime - currentTime;
return timeLeft.
}
我假设RecyclerView
中的每个项目都有一个计时器实例,该实例显示CountDownTimer
您没有指定逻辑在适配器中的确切位置
逻辑应该在onBindViewHolder(…)
中。您可以使用viewHolder.findViewById(…)
另外,CountDownTimer
是它自己的线程,编辑TextView
或任何小部件都可能导致异常。将timer.setText(…)
调用包装在runOnUiThread()
中首先,您应该知道,每次滚动屏幕上最后一个可见项目时,RecyclerView都会重新使用其视图持有者
基于用户每次滚动通过
屏幕上最后可见的项目或帖子,因为它位于
Recycle查看列表中的原始第一项,甚至其他项
滚动过去的项目将被回收,下一个项目将成为新项目
第一项,但填充了不同的post值,如下所示
预料之中
但请记住,您的代码为
列表中每增加一个新帖子(其中50个帖子等于50个)
倒计时和50篇帖子并不一定意味着50次浏览,因为
一些视图可能会被RecyclerView循环使用;您得到了逻辑),因此它允许
多个倒计时器访问同一视图的可能性
导致闪存,并肯定会导致内存泄漏,从而导致
当用户长时间连续滚动时,OutOfMemoryError
名单
建议实施
在ViewHolder类中创建倒计时
public static class PostViewHolder extends RecyclerView.ViewHolder {
...
CountDownTimer countdowntimer;
public FeedViewHolder(View itemView) {
...
}
}
访问setPost方法中的计时器
void setPost(final Post post) {
...
long currentTime = date.getTime();
long endTime = post.getTimerEndDate().getTime();
long timeLeft = endTime - currentTime;
if (countdowntimer != null) {
//there is an existing timer so we cancel it to prevent duplicates
countdowntimer.cancel();
}
countdowntimer = new CountDownTimer(timeLeft, 1000) {
@SuppressLint("DefaultLocale")
public void onTick(long millisUntilFinished) {
timer.setText(String.format("%02d:%02d:%02d",
(int) ((millisUntilFinished / (1000 * 60 * 60)) % 24),
(int) ((millisUntilFinished / (1000 * 60)) % 60),
(int) (millisUntilFinished / 1000) % 60));
//here you can have your logic to set text to edittext
}
public void onFinish() {
timer.setText("done!");
}
}.start();
}
“不同时间之间的闪光”很难理解。强调,澄清。这样更好吗?因此,我目前在视图保持架中安装了计时器,但从您的回答来看,我会将其移动到回收视图的适配器上,对吗?视图保持架
也应该有计时器实例。否则,您无法从适配器将计时器实际设置为ViewHodler
中的计时器实例。是的,您是对的,您需要在适配器中移动计时器的实现。它似乎不是触发行为的滚动。即使只有一个帖子,它现在也在做,不应该。这个想法不是每次分配计时器实例时都创建一个新的计时器实例。但是,深入研究代码可能会更有帮助。请在您的问题中发布一些相关代码。我添加了带有onBindViewHolder
的适配器,我不确定是否有任何其他代码与此问题相关。PostViewHolder
在包含onBindViewHolder
的片段中运行。我没有包括完整的PostViewHolder
,因为其中有很多代码是不相关的。另外,当我尝试在runOnUiThread()中包装timer.setText(…)
调用时,我得到一个无法解决的符号错误