【问题标题】:Android widget displays only one item from DBAndroid 小部件仅显示数据库中的一项
【发布时间】:2023-03-18 13:01:01
【问题描述】:

伙计们,

我的 Android 小部件仅显示我数据库中的一条记录。我确定从数据库中检索到不止一项。

WidgetProvider 的 onUpdate 方法:

public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {
    super.onUpdate(context, appWidgetManager, appWidgetIds);

    if (items == null) {
        items = new ItemsData(new DbHelper(context));
    }

    final int N = appWidgetIds.length;

    Item[] iii = items.getItemsArray();
    Log.d(TAG, "got " + iii.length + " items from db");

    ComponentName thisWidget = new ComponentName(context, WidgetProvider.class);

    for (int i = 0; i < N; i++) {
        int appWidgetId = appWidgetIds[i];

        Log.d(TAG, "updating widget " + appWidgetId);

        RemoteViews rv = new RemoteViews(context.getPackageName(),
                R.layout.widgetlayout);

        for (Item item : iii) {

            Log.d(TAG, "updating item " + item.id + ", " + item.title);

            RemoteViews views = new RemoteViews(context.getPackageName(),
                    R.layout.row);
            views.setTextViewText(R.id.textViewShortName, item.title);
            views.setTextViewText(R.id.textViewDesc, item.description);
            views.setTextViewText(R.id.textViewDue, new StringBuilder()
                    .append(item.dueDate).toString());
            rv.addView(R.id.llWidget, views);
        }

        appWidgetManager.updateAppWidget(thisWidget, rv);

    }

}

而我的布局只是:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/llWidget"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" 
    android:background="#ff99ff">

    <include
        android:id="@+id/row"
        layout="@layout/row" />

</LinearLayout>

'row' 是三个 TextView 项目,按我的需要排列。

会发生什么:当我将项目添加到数据库和小部件更新时,只有最后一个项目 看得到。它位于顶部。

我搜索了 android 小部件指南、堆栈溢出、其他一些网站、一本书中的教程,但即使有些人提供了类似的示例,我也无法让它工作...... Google Android 小部件指南显示了如何使用集合,但它仅适用于 3.0+。 学习 Android 书描述了一个将元素添加为行的小部件,所以我跟着它 - 但无法取得任何进展...... 人们询问如何从小部件内部(例如 Android: get Widget Data from database )从 db 获取数据,据我所知,还没有遇到过这样的问题。他们的解决方案对我不起作用。

现在我什至不知道如何查找错误... 奇怪的是,在 LogCat 中我可以看到“更新项目 X”行。

有什么想法吗?

更新 1。 根据 Sergey Benner 的信息更新方法(相关部分):

    Item[] iii = items.getItemsArray();
    for (int i = 0; i < N; i++) {
        int appWidgetId = appWidgetIds[i];
        RemoteViews rv = new RemoteViews(context.getPackageName(),
                R.layout.widgetlayout);
        for (Item item : iii) {
            RemoteViews views = new RemoteViews(context.getPackageName(),
                    R.layout.row);
            views.setTextViewText(R.id.textViewShortName, item.title);
            views.setTextViewText(R.id.textViewDesc, item.description);
            views.setTextViewText(R.id.textViewDue, new StringBuilder()
                    .append(item.dueDate).toString());
            rv.addView(R.id.llWidget, views);
        }

        appWidgetManager.updateAppWidget(appWidgetId, rv);
    }

更新 2。

AndroidManifest 文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.whatnot.todoex"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:debuggable="true"
        android:name=".ToDoExApp" >

        <activity
            android:label="@string/app_name"
            android:name=".ListItemsActivity" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>


        <activity android:label="@string/titleAdd" android:name=".AddItemActivity" />

        <activity android:label="@string/titleRemindments" android:name=".RemindmentListActivity" />

        <activity android:label="@string/titleAddRemindment" android:name=".AddRemindmentActivity" />

        <activity android:label="@string/titleSetDate" android:name=".ChooseDateActivity" />

        <receiver android:name=".WidgetProvider" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                    android:resource="@xml/widgetprovider" />
        </receiver>

    </application>

</manifest>

widgetprovider.xml:

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="294dp"
    android:minHeight="160dp"
    android:updatePeriodMillis="3000"

    android:initialLayout="@layout/widgetlayout" >

</appwidget-provider>

row.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textViewShortName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/textViewDesc"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_weight="0.80"
            android:textAppearance="?android:attr/textAppearanceSmall" />

        <TextView
            android:id="@+id/textViewDue"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="right"
            android:textAppearance="?android:attr/textAppearanceSmall" />
    </LinearLayout>

</LinearLayout>

并在本文开头更新了 onUpdate 方法。 WidgetProvider 中没有其他内容:一个空的构造函数,onEnabled,只有 super.onEnabled.. 另外:我已经放置了整个小部件布局和行 xmls。

更新 3. 现在,每次更改项目时,我都会运行此方法:

private void updateWidget(Item item) {
    Log.d(TAG, "updateWidget(). Sending broadcast to widget.");

    Intent intent = new Intent(WidgetProvider.UPDATE);
    intent.putExtra(WidgetProvider.UPDATE_ITEM, item.id);
    sendBroadcast(intent);
}

我的小部件的 onReceived 现在看起来像这样:

public void onReceive(Context context, Intent intent) {

    if (intent.getAction().equals(UPDATE)) {
        Log.d(TAG, "onReceived detected new update");
        AppWidgetManager appWidgetManager = AppWidgetManager
                .getInstance(context); // 13
        this.onUpdate(context, appWidgetManager, appWidgetManager
                .getAppWidgetIds(new ComponentName(context,
                        WidgetProvider.class)),
                intent.getExtras().getLong(WidgetProvider.UPDATE_ITEM));
    } else {
        super.onReceive(context, intent);
    }
}

onUpdate 的一个特殊修改版本是这样的:

public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds, long itemId) {
    super.onUpdate(context, appWidgetManager, appWidgetIds);

    if (items == null) {
        items = ((ToDoExApp) ((ContextWrapper) context).getBaseContext()).itemsData;
    }

    Item item = items.getItem2(itemId);
    if (item == null) {
        Log.d(TAG, "Item with id = " + itemId + " not found.");
        return;
    }

    final int N = appWidgetIds.length;
    for (int i = 0; i < N; i++) {
        int appWidgetId = appWidgetIds[i];

        Log.d(TAG, "updating widget " + appWidgetId);

        RemoteViews views = new RemoteViews(context.getPackageName(),
                R.layout.row);
        views.setTextViewText(R.id.textViewShortName, item.title);
        views.setTextViewText(R.id.textViewDesc, item.description);
        views.setTextViewText(R.id.textViewDue,
                new StringBuilder().append(item.dueDate).toString());
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

}

现在,每当我更改时,将一个项目添加到数据库中,有关此的信息就会广播到小部件。然后它被接收和处理。但是,小部件上仅显示此项目。 Yamba 应用程序(来自 Learning Android)有一些非常相似的东西 - 每次发现更新时,它都会被添加到小部件中。我看到的唯一严重区别是 Yamba 使用内容解析器,而我使用数据库......

【问题讨论】:

    标签: android android-widget


    【解决方案1】:

    我使用以下内容将项目添加到我的小部件作为示例:

        for(Server srv:mylist){
          newView = new RemoteViews(context.getPackageName(), R.layout.widget_row);
          newView.setTextViewText(R.id.servername,srv.getServerName());
          newView.setTextViewText(R.id.serverstatus,srv.getServerStatus());
          remoteViews.addView(R.id.widget,newView);
        }
    

    这基本上在remoteViews 中添加了一个“行”newView

    编辑:

    在 2.2 上运行小部件。小部件可以根据您的 当然是启动器。

    编辑:

    尝试使用以下内容 在 onUpdate()


        ComponentName thisWidget = new ComponentName(context, MyWidget.class);
        Item[] iii = items.getItemsArray();
        RemoteViews rv = new RemoteViews(context.getPackageName(),
                R.layout.widgetlayout);
        for (Item item : iii) {
            RemoteViews views = new RemoteViews(context.getPackageName(),
                    R.layout.row);
            views.setTextViewText(R.id.textViewShortName, item.title);
            views.setTextViewText(R.id.textViewDesc, item.description);
            views.setTextViewText(R.id.textViewDue, new StringBuilder()
                    .append(item.dueDate).toString());
            rv.addView(R.id.llWidget, views);
        }
    
        appWidgetManager.updateAppWidget(thisWidget, rv);
    

    我还是不明白这是什么意思

            for (int i = 0; i < N; i++) {
                 int appWidgetId = appWidgetIds[i];
    

    工作示例: 你可能还想实现一个服务


    public class StatusWidget extends AppWidgetProvider {
         LayoutInflater  inflater;
        int[] appWidgetIds;
        AppWidgetManager appWidgetManager;
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                             int[] appWidgetIds) {
            this.appWidgetIds=appWidgetIds;
            this.appWidgetManager=appWidgetManager;
            Timer timer = new Timer();
            timer.scheduleAtFixedRate(new MyTime(context, appWidgetManager), 1, 30000); //30 seconds timeout
        }
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
                final int appWidgetId = intent.getExtras().getInt(
                                    AppWidgetManager.EXTRA_APPWIDGET_ID,
                                    AppWidgetManager.INVALID_APPWIDGET_ID);
    
                if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
                    this.onDeleted(context, new int[]{appWidgetId});
                }
            } else {
                super.onReceive(context, intent);
            }
        }
    
        private class MyTime extends TimerTask {
            RemoteViews remoteViews;
            AppWidgetManager appWidgetManager;
            ComponentName thisWidget;
            Context context;
            public MyTime(Context context, AppWidgetManager appWidgetManager) {
                this.context = context;
                this.appWidgetManager = appWidgetManager;
                remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_message);
                thisWidget = new ComponentName(context, StatusWidget.class);
            }
    
            @Override
            public void run() {
                remoteViews.removeAllViews(R.id.widget);
                 Date date = new Date();
                DateFormat format = SimpleDateFormat.getTimeInstance(
                SimpleDateFormat.LONG, Locale.getDefault());        
                InputStream is = null;
                ImageAdapter myServers =null;
                   List<Server> mylist =null;
                try {
                    is = new ByteArrayInputStream(Utils.fetch("http://mystatusserver/status", null).toByteArray());
                } catch (Exception cte) {
                }
    
                try {
                    String l = Utils.readInputStream(is);
                 List<Server> list= Utils.parseServers(l);
                 mylist=   Utils.loadMyServerList(context, list);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                 RemoteViews newView =null;
                for(Server srv:mylist){
                  newView = new RemoteViews(context.getPackageName(), R.layout.widget_row);
                  newView.setTextViewText(R.id.servername,srv.getServerName());
                  newView.setTextViewText(R.id.serverstatus,srv.getServerStatus());
                  remoteViews.addView(R.id.widget,newView);
                }
                newView = new RemoteViews(context.getPackageName(), R.layout.datetime);
                newView.setTextViewText(R.id.time,"Last Updated At: "+format.format(date));
                remoteViews.addView(R.id.widget,newView);
               appWidgetManager.updateAppWidget(thisWidget, remoteViews);
    
            }
        }
    
    }
    

    希望对你有所帮助

    【讨论】:

    • 谢谢,但是由于某种原因,我无法再看到小部件上的任何项目。小部件只是空白。我的小部件布局只是一个带有“包含行”的 LinearLayout。我确实为 Android 2.2 开发。
    • 你必须把它放到你的问题中。无法阅读。
    • 不幸的是,小部件中没有显示一行:(
    • 你调试了吗?您是否在 Manifest 文件中正确注册了 udpate?你的appwidget-provider 怎么样?展示一切。你的清单是如何注册的。然后向您展示小部件。
    • 我已经发布了补充。我不知道从哪里开始调试。 LogCat 向我显示正在从数据库中检索项目并在循环中进行处理。
    猜你喜欢
    • 1970-01-01
    • 2020-03-16
    • 1970-01-01
    • 1970-01-01
    • 2023-02-05
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    相关资源
    最近更新 更多