Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 什么会导致计时器在RecyclerView中闪烁?_Java_Android_Google Cloud Firestore_Countdowntimer - Fatal编程技术网

Java 什么会导致计时器在RecyclerView中闪烁?

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

我正在尝试为用户生成的帖子创建一个计时器,该计时器显示在帖子上。我正在使用Firestore来存储关于帖子的所有信息

我的代码确实显示了计时器,但当多个用户发布多篇文章时,计时器在正确的时间和另一个倒计时之间闪烁,就我所见,倒计时与倒计时无关。以下是我所拥有的:

这就是我创建每个帖子的方式

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(…)
调用时,我得到一个无法解决的符号错误