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

问题描述

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

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

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

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

我的 appwidgetprovider

void printIntArray( int rows,int cols,int array[ rows ][ cols ] )
{
    for ( int ii = 0; ii < rows; ii++ )
    {
        for ( int jj = 0; jj < cols; jj++ )
        {
            printf( "%d ",array[ ii ][ jj ] );
        }
        printf( "\n" );
    }
}

WidgetFactory 和 WidgetService

 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,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);
        }
    }

这是我的日志:


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);
    }
}

my_widget.xml


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_list_item.xml


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@color/colorPrimary"
    android:padding="@dimen/widget_margin">
    <TextView
        android:id="@+id/appwidget_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        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_width="match_parent"
        android:layout_margin="8dp"
        tools:listitem="@layout/my_widget_list_item"
        android:layout_height="wrap_content"
        android:background="@color/colorAccent"
        android:layout_below="@id/appwidget_text">
    </ListView>
</RelativeLayout>

解决方法

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

public void onDataSetChanged() -> 您可以在这里同步进行举升。例如,如果您需要处理图像,从网络中获取某些内容等,可以在此处同步进行。小部件将在此处完成工作时保持其当前状态,因此您无需担心小部件被锁定。

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