Search code examples
androidkotlinandroid-widgetandroid-launcher

Android widget that requires data fetching only shows loading


I am trying to add a widget in view by an android widget picker. A simple analog clock widget is displayed correctly but widget, where data have to fetch, is only showing loading without showing data as in the screenshot below.

Screenshot

My widget creation code is done from Hosting Android Widget.

My code is :

class MainActivity : AppCompatActivity() {

private lateinit var mAppWidgetManager: AppWidgetManager
lateinit var mAppWidgetHost: AppWidgetHost
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    mAppWidgetManager = AppWidgetManager.getInstance(this)
    mAppWidgetHost = AppWidgetHost(this, APPWIDGET_HOST_ID)
    add_widget.setOnClickListener {
        selectWidget()
    }
}

fun selectWidget() {
    val appWidgetId = mAppWidgetHost.allocateAppWidgetId()
    val pickIntent = Intent(AppWidgetManager.ACTION_APPWIDGET_PICK)
    pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    addEmptyData(pickIntent)
    startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET)
}

private fun addEmptyData(pickIntent: Intent) {
    val customInfo = arrayListOf<Parcelable>()
    pickIntent.putParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_INFO, customInfo)
    val customExtras = arrayListOf<Parcelable>()
    pickIntent.putParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS, customExtras)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (resultCode == RESULT_OK) {
        if (requestCode == REQUEST_PICK_APPWIDGET) {
            configureWidget(data)
        } else if (requestCode == REQUEST_CREATE_APPWIDGET) {
            createWidget(data)
        }
    } else if (resultCode == RESULT_CANCELED && data != null) {
        val appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
        if (appWidgetId != -1) {
            mAppWidgetHost.deleteAppWidgetId(appWidgetId)
        }
    }
}

private fun configureWidget(data: Intent?) {
    val extras = data?.extras ?: return
    val appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1)
    val appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId)
    if (appWidgetInfo.configure != null) {
        val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE)
        intent.component = appWidgetInfo.configure
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
        startActivityForResult(intent, REQUEST_CREATE_APPWIDGET)
    } else {
        createWidget(data)
    }
}


private fun createWidget(data: Intent?) {
    val extras = data?.extras ?: return;
    val appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
    val appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
    val hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
    remove_widget.setOnClickListener {
        removeWidget(hostView)
    }
    hostView.setAppWidget(appWidgetId, appWidgetInfo);
    widgetLayout.addView(hostView);
}

override fun onStart() {
    super.onStart()
    mAppWidgetHost.startListening()
}

override fun onStop() {
    super.onStop()
    mAppWidgetHost.stopListening()
}

private fun removeWidget(hostView: AppWidgetHostView) {
    mAppWidgetHost.deleteAppWidgetId(hostView.appWidgetId)
    widgetLayout.removeView(hostView);
}

companion object {
    const val REQUEST_PICK_APPWIDGET = 9
    const val REQUEST_REFRESH_APPWIDGET = 10
    const val APPWIDGET_HOST_ID = 442
    const val REQUEST_CREATE_APPWIDGET = 5
}
}

Here, remove_widget and add_widget are button and widgetLayout is linearlayout to add widget.

edit: The following error is shown in log after adding gmail widget.

2019-11-28 14:18:33.652 15363-15363/com.example.testapplication W/AppWidgetHostView: Error inflating RemoteViews : android.widget.RemoteViews$ActionException: android.widget.RemoteViews$ActionException: view: androidx.appcompat.widget.AppCompatImageView can't use method with RemoteViews: setImageResource(int)

note: from another launcher, widget is rendering as expected, not from my code though. Also, I changed my context with applicationContext. But, it produces same result.


Solution

  • If you are using androidX AppCompactActivity, then try to use normal activity and see if that works.

    import android.app.Activity;
    
    
    //other codes....
    
    public class MainActivity extends Activity {
    
        // other codes...
    
    }