I'm trying to build a stackview widget, which should display differnt data when swiping through it. So far everything is working, but when I want to receive the index of the clicked card in the widget, I always get an extra or action of 'null'. I already have tried several workarounds, but none of them is working in my application. I also set up a complete new application for only making this work completely isolated. But here I get the exact same behaviour.
Several workarounds I tried to pass the index:
- misusing the intent action (like here Android 7 BroadcastReceiver onReceive intent.getExtras missing data)
- creating a bundle (putInt, putString) (while receiving using getBundleExtra) (like here Pendingintent getbroadcast lost parcelable data)
- putExtra(clickedCategory, test) (while receiving using getIntExtra(clickedCategory, 0))
What I observed is, that the getViewAt funtion is called several times with a position(p0) of "0" before it gets called by the right positions from the generated exampleData List... But I don't know if this causes the Nulls in the onReceive function, when an card is clicked.
Here is my coding:
Manifest.xml
<service android:name=".ExampleWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS">
</service>
WidgetLayout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<StackView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/stackview">
</StackView>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="#ffffff"
android:textStyle="bold"
android:text="empty"
android:textSize="20sp" />
</FrameLayout>
WidgetItemEntry
<?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">
<TextView
android:layout_width="200dp"
android:layout_height="200dp"
android:text="Icon"
android:id="@+id/newwidgetentry">
</TextView>
</LinearLayout>
AppWidgetProvider
package com.example.widgettest
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.widget.RemoteViews
import android.widget.Toast
/**
* Implementation of App Widget functionality.
*/
public const val clickedCategory: String = "com.example.myapplication.buttonpress.id"
public const val stackviewButton = "stackviewbutton"
class newwidget : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
) {
// There may be multiple widgets active, so update all of them
for (appWidgetId in appWidgetIds) {
/* val widgetText = context.getString(R.string.appwidget_text)
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.newwidget)
views.setTextViewText(R.id.newwidgetentry, widgetText)*/
val serviceIntent: Intent = Intent(context, ExampleWidgetService::class.java).apply{
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
}
val views = RemoteViews(
context.packageName,
R.layout.newwidget
).apply{
setRemoteAdapter(R.id.stackview, serviceIntent)
setEmptyView(R.id.stackview, R.id.empty_view)
}
val toastIntent = Intent(context, newwidget::class.java).run {
action= stackviewButton
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
data = Uri.parse(toUri(Intent.URI_INTENT_SCHEME))
PendingIntent.getBroadcast(context,
0,
this,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
}
views.setPendingIntentTemplate(R.id.stackview, toastIntent)
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views)
}
super.onUpdate(context, appWidgetManager, appWidgetIds)
}
override fun onEnabled(context: Context) {
// Enter relevant functionality for when the first widget is created
}
override fun onDisabled(context: Context) {
// Enter relevant functionality for when the last widget is disabled
}
override fun onReceive(context: Context?, intent: Intent?) {
var clickedCat2 = intent?.getBundleExtra("test")?.getInt(clickedCategory,-1)
/*val clickedCat2: Int? = intent?.getIntExtra(clickedCategory, -1)*/
Toast.makeText(context, "onreceive +$clickedCat2" , Toast.LENGTH_SHORT).show();
if (stackviewButton.equals(intent?.getAction())){
val clickedCat: Int? = intent?.getIntExtra(clickedCategory, 0)
Toast.makeText(context, "widgetbuttonpressed id + $clickedCat", Toast.LENGTH_SHORT).show();
}
super.onReceive(context, intent)
}
}
RemoteView Factory
package com.example.widgettest
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.RemoteViews
import android.widget.RemoteViewsService
import com.google.gson.Gson
private const val REMOTE_VIEW_COUNT: Int = 2
data class WidgetItem(
val id: String,
)
class ExampleWidgetService : RemoteViewsService() {
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
return ExampleWidgetService1(this.applicationContext, intent)
}
}
class ExampleWidgetService1(private val context: Context, intent: Intent) :
RemoteViewsService.RemoteViewsFactory {
private lateinit var exampleData: List<WidgetItem>
override fun onCreate() {
exampleData = List(REMOTE_VIEW_COUNT) { index -> WidgetItem("$index!") }
val test = 123
}
override fun onDataSetChanged() {
}
override fun onDestroy() {
}
override fun getCount(): Int {
return exampleData.size
}
override fun getItemId(p0: Int): Long {
return p0.toLong()
}
override fun getViewAt(p0: Int): RemoteViews {
return RemoteViews(context!!.packageName, R.layout.newwidgetentry).apply {
setTextViewText(R.id.newwidgetentry, exampleData[p0].id)
val fillIntent = Intent().apply {
Bundle().also { extras ->
extras.putInt(clickedCategory, p0)
putExtra("test",extras)
}
}
/*val fillIntent = Intent().apply {
putExtra(clickedCategory, p0)
}*/
setOnClickFillInIntent(R.id.newwidgetentry, fillIntent)
}
}
override fun getLoadingView(): RemoteViews? {
return null
}
override fun getViewTypeCount(): Int {
return 1
}
override fun hasStableIds(): Boolean {
return true
}
}
I really appreciate everykind of help!!! Thank you already in advance!!
setPendingIntentTemplate
– RubsetPendingIntentTemplate
intent obtained fromPendingIntent.getXXX
and you are passing your own new intentIntent().run {}
– Rub.run { }
return last statment ? if so then this language is pretty stupid ... as you can read from code if you have() -> void
or() -> somevalue
– Rub//action= stackviewButton
and you should not provide action in intent passed tosetOnClickFillInIntent
– RubputExtras(extras)
notputExtra("test",extras)
... if you useputExtra("test",extras)
then you should take bundle extra called "test" and thenclickedCategory
from this bundle likeintent?.getBundleExtra("test")?.getInt(clickedCategory, 0)
– Rubval fillInIntent = Intent().apply { putExtra(clickedCategory, p0) }
with yourval clickedCat: Int? = intent?.getIntExtra(clickedCategory, 0)
– RubclickedCategory
has the same value in both classes? – Rub