我的 Listview 小部件中没有显示数据

Posted

技术标签:

【中文标题】我的 Listview 小部件中没有显示数据【英文标题】:no Data displayed in my Listview Widget 【发布时间】:2018-11-26 16:15:56 【问题描述】:

我想创建一个ListView 小部件,在小部件中显示ArrayList 的数据......

我花了很长时间尝试将ListView 添加到小部件,但它添加时没有显示任何数据。

虽然当我添加断点时我的数据在类之间成功获取

不知道是什么问题……

这些是我的课程:

第一类(BakingAppWidgetProvider):

package com.example.android.advancebakingapp.Widget;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

import com.example.android.advancebakingapp.BuildConfig;
import com.example.android.advancebakingapp.MainActivity;
import com.example.android.advancebakingapp.Model.Ingredient;
import com.example.android.advancebakingapp.R;

import java.lang.reflect.Array;
import java.util.ArrayList;

/**
 * Implementation of App Widget functionality.
 */
public class BakingAppWidgetProvider extends AppWidgetProvider

    public static Ingredient[] mIngredients;
    public  ArrayList<Ingredient> parcelables;
    public static ArrayList<Ingredient> ingredients1= new ArrayList<>();
    public static final String WIDGET_UPDATE_ACTION = "android.appwidget.action.APPWIDGET_UPDATE";
    private static final String TAG = "WidgetProvider";

    public BakingAppWidgetProvider()
    

    

    @Override
    public void onReceive(final Context context, final Intent intent)
    
        super.onReceive(context, intent);
        final Bundle bundle = intent.getBundleExtra("BUNDLE");
        if(bundle != null) 
            parcelables = (ArrayList<Ingredient>) bundle.getSerializable("INGREDIENTS");
            ingredients1.addAll(parcelables);
        
        else 
            Toast.makeText(context,"nuuuuuuuul",Toast.LENGTH_LONG).show();
        

        intent.setAction(WIDGET_UPDATE_ACTION);
        if (BakingAppWidgetProvider.WIDGET_UPDATE_ACTION.equals(intent.getAction()))
        
            if (BuildConfig.DEBUG)
                Log.d(BakingAppWidgetProvider.TAG, "onReceive "
                        + BakingAppWidgetProvider.WIDGET_UPDATE_ACTION);
            final AppWidgetManager appWidgetManager = AppWidgetManager
                    .getInstance(context);
            final ComponentName thisAppWidget = new ComponentName(
                    context.getPackageName(), BakingAppWidgetProvider.class.getName());
            final int[] appWidgetIds = appWidgetManager
                    .getAppWidgetIds(thisAppWidget);
            onUpdate(context, appWidgetManager, appWidgetIds);
        
    

    /**
     * method will update the ListView each time the user opens the IngredientsActivity,
     * meaning that the widget will always show the last IngredientsActivity Ingredients[] that the user seen.
     * @param context app context
     * @param appWidgetManager  app WidgetManger
     * @param appWidgetIds ids which will be updated
     * @param ingredients the ingredients that will fill the ListView
     *
     */
    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetIds[], Ingredient[] ingredients)
    
        mIngredients = ingredients;
        for (int appWidgetId : appWidgetIds)
        
            Intent intent = new Intent(context, listViewsService.class);
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.baking_app_widget_provider);
            views.setRemoteAdapter(R.id.list_view_widget, intent);
            ComponentName component = new ComponentName(context, BakingAppWidgetProvider.class);
            appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.list_view_widget);
            appWidgetManager.updateAppWidget(component, views);
        
    

    /**
     * the widget will update itself each time the IngredientsActivity will open,meaning that this method
     * is unnecessary in our implementation.
     * @param context app context
     * @param appWidgetManager the application WidgetManager
     * @param appWidgetIds ids which will be updated
     */
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
    
        if (BuildConfig.DEBUG)
            Log.d(BakingAppWidgetProvider.TAG, "onUpdate");

        Intent serviceIntent = new Intent(context,WidgetUpdateService.class);
        Bundle args1 = new Bundle();
        args1.putSerializable("INGREDIENTS",parcelables);
        serviceIntent.putExtra("BUNDLE", args1);
        context.sendBroadcast(serviceIntent);
        serviceIntent.setAction("android.appwidget.action.APPWIDGET_UPDATE");
        context.startService(serviceIntent);
    


    @Override
    public void onEnabled(Context context)
     

    @Override
    public void onDisabled(Context context)
     




第二类(WidgetUpdateService):

package com.example.android.advancebakingapp.Widget;

import android.app.IntentService;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.Nullable;
import android.widget.Toast;

import com.example.android.advancebakingapp.MainActivity;
import com.example.android.advancebakingapp.Model.Ingredient;
import com.example.android.advancebakingapp.Model.Step;

import java.util.ArrayList;

public class WidgetUpdateService extends IntentService

    public static final String WIDGET_UPDATE_ACTION = "android.appwidget.action.APPWIDGET_UPDATE";
    private Ingredient[]mIngredients;
    ArrayList<Ingredient> parcelable = new ArrayList<>();


    public WidgetUpdateService()
    
        super("WidgetUpdateService");
    



    @Override
    protected void onHandleIntent( Intent intent)
    

        if (intent != null && intent.getAction().equals(WIDGET_UPDATE_ACTION)) 

            final Bundle bundle = intent.getBundleExtra("BUNDLE");
            parcelable =(ArrayList<Ingredient>) bundle.getSerializable("INGREDIENTS");

            if (parcelable != null)
            
                mIngredients = new Ingredient[parcelable.size()];
                for (int i = 0; i < parcelable.size(); i++)
                
                    mIngredients[i] = (Ingredient) parcelable.get(i);
                
            


            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
            int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(this, BakingAppWidgetProvider.class));
            intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
            BakingAppWidgetProvider.updateAppWidget(this, appWidgetManager, appWidgetIds,mIngredients);
       
    

第三类(listViewsService):

package com.example.android.advancebakingapp.Widget;

import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.RemoteViewsService;
import android.widget.Toast;

import com.example.android.advancebakingapp.Model.Ingredient;
import com.example.android.advancebakingapp.R;

public class listViewsService extends RemoteViewsService

    public static final String TAG = "ListViewsService";


    /**
     * @param intent intent that triggered this service
     * @return new ListViewsFactory Object with the appropriate implementation
     */
    public ListViewsFactory onGetViewFactory(Intent intent)
    
        return new ListViewsFactory(this.getApplicationContext());
    


class ListViewsFactory implements RemoteViewsService.RemoteViewsFactory

    private Context mContext;
    private Ingredient[] mIngredients;

    public ListViewsFactory(Context mContext)
    
        this.mContext = mContext;
    

    @Override
    public void onCreate()
    
        mIngredients = BakingAppWidgetProvider.mIngredients;


    

    //Very Important,this is the place where the data is being changed each time by the adapter.
    @Override
    public void onDataSetChanged()
    

        mIngredients = BakingAppWidgetProvider.mIngredients;
    

    @Override
    public void onDestroy()
    

    

    @Override
    public int getCount()
    
        if (mIngredients == null)
            return 0;
        return mIngredients.length;
    

    /**
     * @param position position of current view in the ListView
     * @return a new RemoteViews object that will be one of many in the ListView
     */
    @Override
    public RemoteViews getViewAt(int position)
    
        RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.baking_app_widget_ingrediant);
        views.setTextViewText(R.id.text_view_recipe_widget, mIngredients[position].getIngredient());
        return views;
    

    @Override
    public RemoteViews getLoadingView()
    
        return null;
    

    @Override
    public int getViewTypeCount()
    
        return 1;
    

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

    @Override
    public boolean hasStableIds()
    
        return true;
    

这些是我的布局:

baking_app_widget_provider.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:background="#09C"
    android:padding="@dimen/widget_margin">

    <ListView
        android:id="@+id/list_view_widget"
        android:layout_
        android:layout_
        android:layout_marginTop="@dimen/widgetBodyMarginTop" />

</RelativeLayout>

baking_app_widget_ingrediant.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_
    android:layout_
    android:padding="@dimen/widgetPadding"
    android:background="#FFFFFF">
    <TextView
        xmlns:android="http://schemas.android.com/apk/res/android"
        style="@style/TextAppearance.AppCompat.Display1"
        android:id="@+id/text_view_recipe_widget"
        android:layout_
        android:layout_
        android:gravity="center">
    </TextView>
</LinearLayout>

谢谢。

【问题讨论】:

【参考方案1】:

您是否检查过是否调用了 onDataSetChanged()? 您是否在清单中声明了具有以下权限的 RemoteViews 服务?

android:permission="android.permission.BIND_REMOTEVIEWS"

【讨论】:

是的,我添加了权限:服务:android:name=".Widget.listViewsService" 并且成功调用了onDataSetChanged,但是该方法中(mIngredients)的数据为空:mIngredients = BakingAppWidgetProvider。 m成分【参考方案2】:

我的建议是在这种情况下不要使用静态变量:

mIngredients = BakingAppWidgetProvider.mIngredients;

我所做的是使用意图 putExtra 方法将数据传递给远程适配器,然后从我的 listViewsService 中的意图中提取数据。使用一些虚拟数据测试您的 listViewsService 代码并验证它是否显示在小部件中。如果您可以看到虚拟数据,那么您的 listViewsService 代码是正确的,您需要检查数据的来源,在这种情况下,我认为静态变量的值是问题的原因。让我知道这是否有帮助。祝你好运。

【讨论】:

以上是关于我的 Listview 小部件中没有显示数据的主要内容,如果未能解决你的问题,请参考以下文章

ListView.builder 小部件不滚动

我的 ListView 构建器的 ListTile 小部件不可滚动并且显示渲染问题

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

如何在app小部件中使用ListView并在android中填充数据?

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

使用 Firebase 填充小部件