带有 ListView 的小部件为找到的每个项目显示 'Loading'
Widget with ListView shows 'Loading' for each item found
我正在尝试为我的 Android 应用构建一个小部件,我 运行 遇到了一个问题,即 ListView 确实 查找数据(通过调试器,我可以看到我的 RemoteViewFactory 实现中的 getViewAt 方法被调用并返回一个正确的 RemoteViews),找到的每个条目在我的小部件中简单地显示为 "Loading..."
郑重声明:在我的数据库中确实找到了 4 个条目,getViewAt 方法被调用了四次,每次都返回一个正确的列表项。
我的代码基于 Android documentation, having used the StackView sample 作为技术参考。
为了解决这个问题,我咨询了 Whosebug 并找到了一些 past questions。最常见的修复建议是:
- 确保 getViewTypeCount 方法 returns 不是 0 的值(通常为 1,因为大多数小部件将只使用一种视图类型);
- 确保只使用 supported views;
- 关于应该或不应该使用某些任意视图属性的一些更模糊的建议。
我已经尝试了上面的所有建议,并且只使用了支持的视图,但我的项目仍然没有显示。这里有人有想法吗?
我写过的相关代码列表:
条目已添加到我的 AndroidManifest.xml 文件
<service
android:name=".widget.DfdWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<receiver android:name=".widget.DfdWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/dfd_widget_info" />
</receiver>
小部件布局xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#80DDE8ED"
android:padding="@dimen/widget_margin">
<ListView
android:id="@+id/widgetRemindersListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/dfd_widget_list_item">
</ListView>
<TextView
android:id="@+id/widgetEmptyViewText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="You have no reminders for today, nice!"
android:textAlignment="center"
android:textSize="20sp" />
</RelativeLayout>
小部件列表项 xml
(作为测试,我确实尝试删除除 TextViews 之外的所有内容,以查看 Android 是否发现 ImageViews 有问题。没关系。)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/widgetListItem"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/widgetCompletedCheckBox"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentStart="true"
android:layout_marginStart="10dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
app:srcCompat="@android:drawable/checkbox_off_background" />
<TextView
android:id="@+id/widgetReminderName"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toEndOf="@id/widgetCompletedCheckBox"
android:text="Reminder name"
android:textColor="#000000"
android:textSize="24sp" />
<TextView
android:id="@+id/widgetReminderDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/widgetReminderName"
android:layout_toEndOf="@id/widgetCompletedCheckBox"
android:text="Ma 1 jan"
android:textColor="#2196F3" />
<ImageView
android:id="@+id/widgetReminderRepeating"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_below="@id/widgetReminderName"
android:layout_toEndOf="@id/widgetReminderDate"
android:background="#00FFFFFF"
app:srcCompat="@android:drawable/ic_menu_revert"
tools:visibility="invisible" />
<ImageView
android:id="@+id/widgetIsImportant"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentEnd="true"
app:srcCompat="@android:drawable/btn_star_big_off" />
</RelativeLayout>
小部件提供程序class
public class DfdWidget extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
Intent intent = new Intent(context, DfdWidgetService.class);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.dfd_widget);
remoteViews.setRemoteAdapter(R.id.widgetRemindersListView, intent);
remoteViews.setEmptyView(R.id.widgetRemindersListView, R.id.widgetEmptyViewText);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
@Override
public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
super.onRestored(context, oldWidgetIds, newWidgetIds);
}
}
小部件服务Class
public class DfdWidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new DfdRemoteViewsFactory(getApplicationContext());
}
class DfdRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private final Context context;
private ReminderRepository reminderRepository;
private List<Reminder> reminders;
public DfdRemoteViewsFactory(Context context) {
this.context = context;
this.reminderRepository = ReminderRepository.getReminderRepository(context);
}
@Override
public void onCreate() {
reminders = reminderRepository.getAllRemindersForTodayList();
}
@Override
public void onDataSetChanged() {
reminders = reminderRepository.getAllRemindersForTodayList();
}
@Override
public void onDestroy() {
reminders.clear();
}
@Override
public int getCount() {
return reminders.size();
}
@Override
public RemoteViews getViewAt(int position) {
Reminder reminder = reminders.get(position);
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.id.widgetListItem);
remoteView.setTextViewText(R.id.widgetReminderName, reminder.getName());
// Removed code that sets the other fields as I tried it with and without and it didn't matter. So removed for brevity
return remoteView;
}
@Override
public RemoteViews getLoadingView() {
return null;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public long getItemId(int position) {
return reminders.get(position).getId();
}
@Override
public boolean hasStableIds() {
return true;
}
}
}
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.id.widgetListItem)
RemoteViews
constructor that you are trying to use将布局资源ID作为第二个参数。您正在传递小部件 ID。
因此,将 R.id.widgetListItem
替换为 R.layout.whateverYourLayoutNameIsForTheListItems
,将 whateverYourLayoutNameIsForTheListItems
替换为列表项的布局名称。
我正在尝试为我的 Android 应用构建一个小部件,我 运行 遇到了一个问题,即 ListView 确实 查找数据(通过调试器,我可以看到我的 RemoteViewFactory 实现中的 getViewAt 方法被调用并返回一个正确的 RemoteViews),找到的每个条目在我的小部件中简单地显示为 "Loading..."
郑重声明:在我的数据库中确实找到了 4 个条目,getViewAt 方法被调用了四次,每次都返回一个正确的列表项。
我的代码基于 Android documentation, having used the StackView sample 作为技术参考。
为了解决这个问题,我咨询了 Whosebug 并找到了一些 past questions。最常见的修复建议是:
- 确保 getViewTypeCount 方法 returns 不是 0 的值(通常为 1,因为大多数小部件将只使用一种视图类型);
- 确保只使用 supported views;
- 关于应该或不应该使用某些任意视图属性的一些更模糊的建议。
我已经尝试了上面的所有建议,并且只使用了支持的视图,但我的项目仍然没有显示。这里有人有想法吗?
我写过的相关代码列表:
条目已添加到我的 AndroidManifest.xml 文件
<service
android:name=".widget.DfdWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<receiver android:name=".widget.DfdWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/dfd_widget_info" />
</receiver>
小部件布局xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#80DDE8ED"
android:padding="@dimen/widget_margin">
<ListView
android:id="@+id/widgetRemindersListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/dfd_widget_list_item">
</ListView>
<TextView
android:id="@+id/widgetEmptyViewText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="You have no reminders for today, nice!"
android:textAlignment="center"
android:textSize="20sp" />
</RelativeLayout>
小部件列表项 xml
(作为测试,我确实尝试删除除 TextViews 之外的所有内容,以查看 Android 是否发现 ImageViews 有问题。没关系。)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/widgetListItem"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/widgetCompletedCheckBox"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentStart="true"
android:layout_marginStart="10dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
app:srcCompat="@android:drawable/checkbox_off_background" />
<TextView
android:id="@+id/widgetReminderName"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_toEndOf="@id/widgetCompletedCheckBox"
android:text="Reminder name"
android:textColor="#000000"
android:textSize="24sp" />
<TextView
android:id="@+id/widgetReminderDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/widgetReminderName"
android:layout_toEndOf="@id/widgetCompletedCheckBox"
android:text="Ma 1 jan"
android:textColor="#2196F3" />
<ImageView
android:id="@+id/widgetReminderRepeating"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_below="@id/widgetReminderName"
android:layout_toEndOf="@id/widgetReminderDate"
android:background="#00FFFFFF"
app:srcCompat="@android:drawable/ic_menu_revert"
tools:visibility="invisible" />
<ImageView
android:id="@+id/widgetIsImportant"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentEnd="true"
app:srcCompat="@android:drawable/btn_star_big_off" />
</RelativeLayout>
小部件提供程序class
public class DfdWidget extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
Intent intent = new Intent(context, DfdWidgetService.class);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.dfd_widget);
remoteViews.setRemoteAdapter(R.id.widgetRemindersListView, intent);
remoteViews.setEmptyView(R.id.widgetRemindersListView, R.id.widgetEmptyViewText);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
@Override
public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
super.onRestored(context, oldWidgetIds, newWidgetIds);
}
}
小部件服务Class
public class DfdWidgetService extends RemoteViewsService {
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new DfdRemoteViewsFactory(getApplicationContext());
}
class DfdRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
private final Context context;
private ReminderRepository reminderRepository;
private List<Reminder> reminders;
public DfdRemoteViewsFactory(Context context) {
this.context = context;
this.reminderRepository = ReminderRepository.getReminderRepository(context);
}
@Override
public void onCreate() {
reminders = reminderRepository.getAllRemindersForTodayList();
}
@Override
public void onDataSetChanged() {
reminders = reminderRepository.getAllRemindersForTodayList();
}
@Override
public void onDestroy() {
reminders.clear();
}
@Override
public int getCount() {
return reminders.size();
}
@Override
public RemoteViews getViewAt(int position) {
Reminder reminder = reminders.get(position);
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.id.widgetListItem);
remoteView.setTextViewText(R.id.widgetReminderName, reminder.getName());
// Removed code that sets the other fields as I tried it with and without and it didn't matter. So removed for brevity
return remoteView;
}
@Override
public RemoteViews getLoadingView() {
return null;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public long getItemId(int position) {
return reminders.get(position).getId();
}
@Override
public boolean hasStableIds() {
return true;
}
}
}
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.id.widgetListItem)
RemoteViews
constructor that you are trying to use将布局资源ID作为第二个参数。您正在传递小部件 ID。
因此,将 R.id.widgetListItem
替换为 R.layout.whateverYourLayoutNameIsForTheListItems
,将 whateverYourLayoutNameIsForTheListItems
替换为列表项的布局名称。