带有集合(ListView)的Android小部件不显示项目

Posted

技术标签:

【中文标题】带有集合(ListView)的Android小部件不显示项目【英文标题】:Android Widget with collection (ListView) not displaying items 【发布时间】:2021-04-23 00:37:52 【问题描述】:

我正在尝试为我的应用程序做一个简单的小部件,它使用 ListView 在小部件上显示来自 API 的数据,但即使日志显示数据已成功下载,列表也是空的。 显示空白列表视图,其中没有数据。没有显示错误。是什么原因造成的?

我在尝试解决此问题时使用的资源:

官方文档-https://developer.android.com/guide/topics/appwidgets#collections

类似问题 - How to use listview in a widget?

我的 AppWidgetProvider

 public class Widget extends AppWidgetProvider 
    RemoteViews views;

    void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                         int appWidgetId) 

        CharSequence widgetText = context.getString(R.string.appwidget_text);
        // Construct the RemoteViews object
        views = new RemoteViews(context.getPackageName(), R.layout.my_widget);
        views.setTextViewText(R.id.appwidget_text, widgetText);

        // Instruct the widget manager to update the widget
        appWidgetManager.updateAppWidget(appWidgetId, views);
    

    @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) 
            RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.my_widget);
            Intent intent = new Intent(context, WidgetService.class);
            remoteViews.setRemoteAdapter(R.id.appwidget_list_view, intent);
            appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
        
    

WidgetFactory 和 WidgetService


public class WidgetFactory implements RemoteViewsService.RemoteViewsFactory
    final Context context;
    List<SimpleCoin> list;
    List<Coin> coinList;

    public WidgetFactory(Context context, Intent intent) 
        this.context = context;
    

    @Override
    public void onCreate() 
        //get data from database
        CoinDatabase coinDatabase = CoinDatabase.buildDatabase(context);
        list = coinDatabase.coinDao().getAllSimpleCoinsNonLive();
        coinList = new ArrayList<>();
    

    @Override
    public void onDataSetChanged() 
        //based on data from database download content (JSON)
        if(list != null) 
            Log.d("Widget", "Coin size -> " + list.size());
            StringBuilder id = new StringBuilder("id=" + list.get(0).getId());
            for (int j = 0; j < list.size(); j++) 
                id.append(",");
                id.append(list.get(j).getId());
            
            String finalUrl = URL + id.toString() + API_KEY;
            Observable.fromCallable(() -> 
                HttpURLConnection connection = null;
                BufferedReader reader = null;
                java.net.URL url1 = new URL(finalUrl);
                connection = (HttpURLConnection) url1.openConnection();
                connection.connect();
                InputStream stream = connection.getInputStream();
                reader = new BufferedReader(new InputStreamReader(stream));
                StringBuilder buffer = new StringBuilder();
                String line = "";
                while ((line = reader.readLine()) != null) 
                    buffer.append(line).append("\n");
                
                connection.disconnect();
                reader.close();
                return buffer.toString();
            ).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<String>() 
                @Override
                public void onSubscribe(@NonNull Disposable d) 
                
                @Override
                public void onNext(@NonNull String s) 
                    if (s != null) 
                        try 
                            //Create new coin and update list of coins
                            JSONObject object = new JSONObject(s);
                            for (int i = 0; i < list.size(); i++) 
                                JSONObject jsonObject = object.getJSONObject("data").getJSONObject(String.valueOf(list.get(i).getId()));
                                Log.d("Widget", "Coin -> " + jsonObject.getString("name") +  jsonObject.getJSONObject("quote").getJSONObject("USD").getDouble("price") + jsonObject.getJSONObject("quote").getJSONObject("USD").getDouble("percent_change_7d"));
                                Coin coin = new Coin(jsonObject.getString("name"), jsonObject.getJSONObject("quote").getJSONObject("USD").getDouble("price"), jsonObject.getJSONObject("quote").getJSONObject("USD").getDouble("percent_change_7d"), false);
                                coinList.add(coin);
                                getViewAt(i);
                            

                         catch (JSONException e) 
                            Log.d("Widget", "Coin -> " + e.toString());
                            e.printStackTrace();
                        
                    
                

                @Override
                public void onError(@NonNull Throwable e) 
                

                @Override
                public void onComplete() 
                
            );
        
    

    @Override
    public void onDestroy() 

    @Override
    public int getCount() 
        return list.size();
    

    @Override
    public RemoteViews getViewAt(int i) 
        //Set ListData based on coinList
        Log.d("Widget", "Coin size getViewAt -> " + list.size() + "item num ->" + i);
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.my_widget_list_item);
        if(coinList !=  null)
        if(coinList.size() > i) 
            Log.d("Widget", "Coin position added" + coinList.get(i).getName());
            remoteViews.setTextViewText(R.id.widgetItemTaskNameLabel, coinList.get(i).getName());
        
        return remoteViews;
    

    @Override
    public RemoteViews getLoadingView() 
        return null;
    

    @Override
    public int getViewTypeCount() 
        return 1;
    

    @Override
    public long getItemId(int i) 
        return i;
    

    @Override
    public boolean hasStableIds() 
        return true;
    


public class WidgetService extends RemoteViewsService 
    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) 
        return new WidgetFactory(this.getApplicationContext(), intent);
    


这是我的日志:


D/Widget: Coin size getViewAt -> 1 item num ->0

D/Widget: Coin size getViewAt -> 1 item num ->0

D/Widget: Coin -> testCoin0.00.0

D/Widget: Coin size getViewAt -> 1 item num ->0

D/Widget: Coin position added testCoin

my_widget.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@color/colorPrimary"
    android:padding="@dimen/widget_margin">
    <TextView
        android:id="@+id/appwidget_text"
        android:layout_
        android:layout_
        android:layout_centerVertical="true"
        android:layout_margin="8dp"
        android:background="@color/colorPrimary"
        android:contentDescription="@string/appwidget_text"
        android:text="@string/appwidget_text"
        android:textColor="#ffffff"
        android:textSize="24sp"
        android:textStyle="bold|italic" />
    <ListView
        android:id="@+id/appwidget_list_view"
        android:layout_
        android:layout_margin="8dp"
        tools:listitem="@layout/my_widget_list_item"
        android:layout_
        android:background="@color/colorAccent"
        android:layout_below="@id/appwidget_text">
    </ListView>
</RelativeLayout>

my_widget_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_
    android:paddingLeft="@dimen/widget_listview_padding_x"
    android:paddingRight="@dimen/widget_listview_padding_x"
    android:paddingStart="@dimen/widget_listview_padding_x"
    android:paddingEnd="@dimen/widget_listview_padding_x"
    android:minHeight="@dimen/widget_listview_item_height"
    android:weightSum="2"
    android:layout_>

    <TextView
        android:id="@+id/widgetItemTaskNameLabel"
        android:layout_
        android:gravity="start"
        android:layout_weight="1"
        android:textColor="@color/colorPrimary"
        android:layout_gravity="center_vertical"
        android:layout_ />

</LinearLayout>

【问题讨论】:

【参考方案1】:

我发现了我的错误,结果证明我的 API 调用不应该是异步的,因为正如文档所述:

public void onDataSetChanged() -> 你可以在这里同步地做起重。例如,如果你需要处理一张图片,从网络中取一些东西等等,这里就可以了,同步的。在此处完成工作时,小部件将保持其当前状态,因此您无需担心锁定小部件。

所以从异步调用中获取我的数据是没有显示数据的原因

【讨论】:

以上是关于带有集合(ListView)的Android小部件不显示项目的主要内容,如果未能解决你的问题,请参考以下文章

带有 ListView 的 Android 可点击小部件在 ListItems 上不可点击

带有 ListView 自定义项的 Android 小部件

带有 ListView 的小部件为找到的每个项目显示“正在加载”

Android:使用 ListView 和 Service 从应用小部件开始活动

Android小部件ListView项目点击不起作用

Android:我的带有 ListView 的 App Widget 未通过按钮或更新周期进行更新