计时器小部件ListView中不会更新计时器

zap*_*tny 12 android listview widget chronometer

我有一个显示计时器的应用程序小部件.定时器可以启动,停止或恢复.

在Android 8计时器上有时不打勾(50/50).一些用户在Android 7上抱怨这个问题,但我不能确定它是否是同一个问题.在安装了Android 6的Nexus 5上,一切运行良好.如果向下滚动列表视图(直到计时器不可见)并向上滚动 - 计时器开始计时.如果我再将一个Chronometer放在ListView上方并启动 - 那么天文台计时器就会很好

ActivitiesRemoteViewsFactory

public RemoteViews getViewAt(int position) {
...

    RemoteViews remoteViews = new RemoteViews(mContext.getPackageName(), getItemLayoutId());

    if (timeLog.getState() == TimeLog.TimeLogState.RUNNING) {          

        remoteViews.setChronometer(R.id.widget_timer,
                SystemClock.elapsedRealtime() - (duration * 1000 + System.currentTimeMillis() - timeLog.getStartDate().getTime()), null, true);
    } else {
        long timerValue = SystemClock.elapsedRealtime() - duration * 1000;
        remoteViews.setChronometer(R.id.widget_timer, timerValue, null, false);

    }

    return remoteViews;
Run Code Online (Sandbox Code Playgroud)

更新从AppWidgetProvider的onReceive方法发送

public void onReceive(Context context, Intent intent) {   
   AppWidgetManager widgetManager = AppWidgetManager.getInstance(ctx);
    ...
   widgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_activities_list);
}
Run Code Online (Sandbox Code Playgroud)

TargetSDK是25

更新 此问题也在主应用程序中重现.listView有问题,因为它在RecyclerView中运行良好.添加了在https://github.com/zaplitny/WidgetIssue上重现该问题的简单示例

Che*_*amp 7

Chronometer插件是API 25和API 26,以防止不可见的计时器从更新之间更新.(这是我从查看底层代码的最佳猜测.)具体来说,该updateRunning()方法已更改为考虑是否显示窗口小部件.来自Chronometer.java:

对于API 25: boolean running = mVisible && mStarted;

对于API 26: boolean running = mVisible && mStarted && isShown();

isShown()是您的问题的根源,它会阻止您Chronometers重复使用.对于API 26+,重用Chronometers它们似乎不会更新,当它们在一个ListView.

有几种方法可以解决这个问题.首先是不重复使用Chronometers.在getView()适配器中,您可以使用以下代码:

if (view == null || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    view = LayoutInflater.from(getContext()).inflate(R.layout.widget_timer, parent, false);
}
Run Code Online (Sandbox Code Playgroud)

使用此代码,您将始终创建新代码Chronometers并且永远不会重复使用它们.

另一种方法是chronometer.start()在小部件布局后调用并且isShown()为真.将以下代码添加到getView():

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
    chronometer.start();
} else {
    view.post(new Runnable() {
        @Override
        public void run() {
            chronometer.start();
        }
    });
} 
Run Code Online (Sandbox Code Playgroud)

无论哪种方式都有效,还有其他方式.

  • issuestracker.google.com/issues/74058586 在 2019 年 6 月 27 日上午 07:38 被标记为“不会修复(已过时)”...Cheticamp 选项仍然有效!:) 谢谢! (2认同)