计时器小部件ListView

时间:2018-02-28 09:38:37

标签: android listview widget chronometer

我有一个显示计时器的app小部件。定时器可以启动,停止或恢复。

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

更新是从 AppWidgetProvider 的onReceive方法发送的

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

TargetSDK是25

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

重现问题的简单示例

2 个答案:

答案 0 :(得分:7)

在API 25和API 26之间更新了Chronometer窗口小部件,以防止不可见的计时器更新。 (这是我从查看底层代码的最佳猜测。)具体来说,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);
}

使用此代码,您将始终创建新的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();
        }
    });
} 

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

答案 1 :(得分:1)

在您的应用程序清单中添加:

 <!-- Widget Receiver -->
        <receiver android:name=".widgets.WidgetProvider">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/widget_provider" />
        </receiver>

现在,当您想要从应用程序中更新小部件时,请调用:

                  try {
                        Intent intent = new Intent(ctxt, WidgetProvider.class);
                        intent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
                        int ids[] = AppWidgetManager.getInstance(ctxt).getAppWidgetIds(new ComponentName(ctxt, WidgetProvider.class));
                        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,ids);
                        ctxt.sendBroadcast(intent);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

我用它来更新我的小部件。 谢谢。