【问题标题】:ListView in AppWidget doesnt show data from firebaseApp Widget中的ListView不显示来自firebase的数据
【发布时间】:2021-07-10 03:23:07
【问题描述】:

我有一个带有 ListView 的 AppWidget。当使用一个虚拟数组列表exampleData 时,ListView 会显示它的数据。但是当我尝试从 firebase RD 检索数据到todayList 时,我的 ListView 没有显示数据。当我检查todayList 的大小时,它不是0,这意味着todayList 成功检索到的数据。你能帮帮我吗?

使用todayList时的ListView

ListView 使用虚拟exampleData

这是我的ExampleWidgetItemFactory 班级:

internal class ExampleWidgetItemFactory(private val context: Context, intent: Intent) :
    RemoteViewsFactory {
    private lateinit var database: DatabaseReference
    private lateinit var preferences: Preferences
    private val mGoogleSignInClient: GoogleSignInClient? = null
    private lateinit var auth: FirebaseAuth
    private lateinit var user: FirebaseUser

    private lateinit var userId: String
    private lateinit var userName:String

    private var todayList: ArrayList<Task> = arrayListOf()
    private val appWidgetId: Int
    private val exampleData = arrayListOf(
        "one", "two", "three", "four",
        "five", "six", "seven", "eight", "nine", "ten"
    )

    override fun onCreate() {
        //connect to data source
        //Initialize
        database = FirebaseDatabase.getInstance().reference
        auth = Firebase.auth

        //User
        user = auth.currentUser
        userId = user.uid.toString()

        //Calendar
        val calendar = Calendar.getInstance()
        val year = calendar.get(Calendar.YEAR)
        val month = calendar.get(Calendar.MONTH) + 1
        val day = calendar.get(Calendar.DAY_OF_MONTH)
        val date = String.format("%02d/%02d/%04d", day, month, year)

        database
                .child("users")
                .child(userId)
                .child("tasks")
                .addValueEventListener(object : ValueEventListener {
                    override fun onDataChange(snapshot: DataSnapshot) {
                        //Hapus data dalam arraylist agar tidak jadi penumpukan data
                        todayList.clear()

                        //Ambil semua child dalam goal dan masukan ke items
                        var items = snapshot.children
                        //Lakukan iterasi pada setiap item lalu buat class dan tambahkan ke list
                        items.forEach {
                            var task = it.getValue(Task::class.java)
                            todayList.add(task!!)
                        }
                        Log.v("GAL", todayList.size.toString())
                        Log.v("GAL", todayList[0].title.toString())
                        SystemClock.sleep(3000)
                    }

                    override fun onCancelled(error: DatabaseError) {
                        TODO("Not yet implemented")
                    }

                })
    }

    override fun onDataSetChanged() {

    }
    override fun onDestroy() {
        //close data source
    }

    override fun getCount(): Int {
        return exampleData.size
    }

    override fun getViewAt(position: Int): RemoteViews {
        val views = RemoteViews(context.packageName, R.layout.example_widget_item)
        views.setTextViewText(R.id.example_widget_item_text, todayList[position].title)
        val fillIntent = Intent()
        fillIntent.putExtra(ExampleWidgetProvider().EXTRA_ITEM_POSITION, position)
        views.setOnClickFillInIntent(R.id.example_widget_item_text, fillIntent)
        SystemClock.sleep(500)
        return views
    }

    override fun getLoadingView(): RemoteViews? {
        return null
    }

    override fun getViewTypeCount(): Int {
        return 1
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun hasStableIds(): Boolean {
        return true
    }

    init {
        appWidgetId = intent.getIntExtra(
            AppWidgetManager.EXTRA_APPWIDGET_ID,
            AppWidgetManager.INVALID_APPWIDGET_ID
        )
    }
}

**ExampleWidgetProvider **

class ExampleWidgetProvider : AppWidgetProvider() {
    val ACTION_TOAST = "actionToast"
    val EXTRA_ITEM_POSITION = "extraItemPosition"

    override fun onUpdate(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetIds: IntArray
    ) {
        super.onUpdate(context, appWidgetManager, appWidgetIds)
        for (appWidgetId in appWidgetIds) {
            val buttonIntent = Intent(context, HomeActivity::class.java)
            val buttonPendingIntent = PendingIntent.getActivity(
                context,
                0, buttonIntent, 0
            )
            val prefs = context.getSharedPreferences(
                ExampleAppWidgetConfig().SHARED_PREFS,
                Context.MODE_PRIVATE
            )
            val buttonText = prefs.getString(
                ExampleAppWidgetConfig().KEY_BUTTON_TEXT + appWidgetId,
                "Press me"
            )
            val serviceIntent = Intent(context, ExampleWidgetService::class.java)
            serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
            serviceIntent.data = Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME))

            val clickIntent =
                Intent(
                    context,ExampleWidgetProvider::class.java
                )
            clickIntent.action = ACTION_TOAST

            val clickPendingIntent = PendingIntent.getBroadcast(
                context,
                0, clickIntent, 0
            )

            val views = RemoteViews(context.packageName, R.layout.example_widget)
            views.setRemoteAdapter(R.id.example_widget_stack_view, serviceIntent)
            views.setEmptyView(R.id.example_widget_stack_view, R.id.example_widget_empty_view)
            views.setPendingIntentTemplate(R.id.example_widget_stack_view, clickPendingIntent)
            
            val appWidgetOptions = appWidgetManager.getAppWidgetOptions(appWidgetId)
            resizeWidget(appWidgetOptions, views)
            appWidgetManager.updateAppWidget(appWidgetId, views)
        }
    }

    override fun onAppWidgetOptionsChanged(
        context: Context,
        appWidgetManager: AppWidgetManager,
        appWidgetId: Int,
        newOptions: Bundle
    ) {
        val views = RemoteViews(context.packageName, R.layout.example_widget)
        resizeWidget(newOptions, views)
        appWidgetManager.updateAppWidget(appWidgetId, views)
    }

    private fun resizeWidget(appWidgetOptions: Bundle, views: RemoteViews) {
        val minWidth = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH)
        val maxWidth = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH)
        val minHeight = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT)
        val maxHeight = appWidgetOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT)
    }

    override fun onDeleted(context: Context?, appWidgetIds: IntArray?) {
        Toast.makeText(context, "onDeleted", Toast.LENGTH_SHORT).show()
    }

    override fun onEnabled(context: Context?) {
        Toast.makeText(context, "onEnabled", Toast.LENGTH_SHORT).show()
    }

    override fun onDisabled(context: Context?) {
        Toast.makeText(context, "onDisabled", Toast.LENGTH_SHORT).show()
    }

    override fun onReceive(context: Context?, intent: Intent) {
        if (ACTION_TOAST == intent.action) {
            val clickedPosition = intent.getIntExtra(EXTRA_ITEM_POSITION, 0)
            Toast.makeText(context, "Clicked position: $clickedPosition", Toast.LENGTH_SHORT).show()
        }
        super.onReceive(context, intent)
    }

}

**When I try getting size and element in `todayList`:**

    Log.v("GAL", todayList.size.toString())
    Log.v("GAL", todayList[0].title.toString())

**The logcat result:**

    2021-04-15 11:57:41.554 8756-8756/com.giftech.taskmastertest V/GAL: 4
    2021-04-15 11:57:41.554 8756-8756/com.giftech.taskmastertest V/GAL: vv

【问题讨论】:

  • 这个 answer 可能会有所帮助。

标签: android kotlin listview firebase-realtime-database android-appwidget


【解决方案1】:

为什么您认为您的项目应该显示在列表中?您正在从数据库中获取项目,在forEach 中完成todayList 并且......仅此而已。你永远不会在任何地方返回这个ArrayList,尤其是它没有设置为某个适配器,它附加到ListView。看起来您已经剥离了很多代码,发布了整个课程 - 我敢打赌您的问题与异步数据库读取有关,onDataChange 的调用晚于绘图适配器/ListView,在此方法结束时您可能应该调用 @987654328 @

编辑:发布整个课程后,现在一切都清楚了:RemoteViewsFactory 正在根据传递给此类的数据生成视图,与适配器类似的工作。这不是从网络获取数据的时刻,因为这是异步操作,而创建 RemoteViewsFactory 是获取现有项目视图的一种同步方式。您应该在 extends AppWidgetProvider 类中获取您的数据(在 onUpdate() 方法中),可能需要启动一些 Service 来获取异步数据并在存储整个数组刷新小部件 GUI 之后

【讨论】:

  • 在下面的方法中我返回了今天的列表,好吧我编辑它
  • 我怎么能打电话给notifyDataSetChanged()?我不知道该怎么做。可以举个例子吗?
  • notifyDataSetChanged 很遗憾在这里不起作用,应用程序小部件有自己的运行时和生命周期,RemoteViewsFactory 是一个正在绘制数据的类,当它创建时下载数据为时已晚.查看我的编辑
  • 哦,好吧,所以我要做的就是在数据完全检索到列表后重绘数据。但是你能解释一下如何在AppWidgetProvider 中的onUpdate 方法中获取吗?因此它在不同的班级。我编辑并添加我的AppWidgetProvider
  • AppWidgetProvider 扩展了BroadcastReceiver,因此您可以通过向其发送广播来唤醒它,就像使用ACTION_TOAST 一样。引入新的动作,例如ACTION_NEW_DATA,将您的数据库获取代码放在onUpdate 中,并在onDataChange 的末尾发送new Intent,并带有此操作和整个数组。在onReceive 内部检测到这个动作并调用onUpdate 从额外的传递数组。在HERE 的答案中(尤其是第 1 步)你有一些样本
猜你喜欢
  • 1970-01-01
  • 2014-05-14
  • 1970-01-01
  • 2021-02-27
  • 1970-01-01
  • 2021-08-23
  • 2021-09-20
  • 2021-06-26
  • 1970-01-01
相关资源
最近更新 更多