locked
Web Service doesn’t work when I try to update the android widget if the app is killed. RRS feed

  • Question

  • User396424 posted

    We are developing android widget for Xamarin.Forms application. The widget updates and gets data from the Web Service when the app is in Background, but stops working when the app is killed/closed. I have followed this article for developing this widget - https://stackoverflow.com/questions/53659897/xamarin-android-widget-with-timer-stops-when-app-killed

    I want to Update the widget when the user clicks on Refresh button. If I add hardcoded data for textboxes and click Refresh it updates the time but doesn’t work if I assign web service result data for the textboxes. I have added internet permission in AndroidManifest.xml. Is there a way I can get the data from web service even when the app is closed? Or Probably I am missing some permission?

    AppWidget.cs -

    public static class WidgetConsts { public const string DebugTag = "com.myapp.WIDGET"; public const string ActionWakeup = "com.myapp.WIDGETWAKEUP"; public const string ActionWidgetUpdate = "android.appwidget.action.APPWIDGETUPDATE"; public const string ActionWidgetDisabled = "android.appwidget.action.APPWIDGET_DISABLED"; }

    [BroadcastReceiver]
    [IntentFilter(new string[] { WidgetConsts.ActionWakeup })]
    public class AlarmReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            if (intent.Action.Equals(WidgetConsts.ActionWakeup))
            {
                Log.Debug(WidgetConsts.DebugTag, "Wakeup alarm called");
                if (AppWidget.widgetTimer == null)
                {
                    Log.Debug(WidgetConsts.DebugTag, "Widget updating does not run, enforcing update...");
                    AppWidget.UpdateAppWidget(context);
    
                }
                else
                {
                    Log.Debug(WidgetConsts.DebugTag, "Widget updating runs, no action needed");
                }
            }
        }
    }
    
    [BroadcastReceiver]
    [IntentFilter(new string[] { WidgetConsts.ActionWidgetUpdate})]
    [MetaData("android.appwidget.provider", Resource = "@xml/appwidget_provider")]
    public class AppWidget : AppWidgetProvider
    {
        public static System.Timers.Timer widgetTimer = null;
        public override void OnUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
        {
            RemoteViews views = BuildRemoteViews(context, appWidgetIds);
            (AppWidgetManager.GetInstance(Android.App.Application.Context)).UpdateAppWidget(new ComponentName(Android.App.Application.Context, Java.Lang.Class.FromType(typeof(AppWidget))), views);
           // appWidgetManager.UpdateAppWidget(appWidgetIds[0], views);
    
            // set timer for updating the widget views each 5 sec
            if (widgetTimer == null)
            {
                widgetTimer = new System.Timers.Timer();
                widgetTimer.Interval = 5000;
                widgetTimer.Elapsed += OnTimedEvent;
            }
            widgetTimer.Enabled = true;
    
            // set alarm to wake up the app when killed, each 60 sec
            // needs a fresh BroadcastReceiver because AppWidgetProvider.OnReceive is
            // not virtual and overriden method in this class would not be called
            AlarmManager am = (AlarmManager)context.GetSystemService(Context.AlarmService);
            Intent ai = new Intent(context, typeof(AlarmReceiver));
            ai.SetAction(WidgetConsts.ActionWakeup);
            PendingIntent pi = PendingIntent.GetBroadcast(context, 0, ai, PendingIntentFlags.UpdateCurrent);
            am.SetRepeating(AlarmType.ElapsedRealtime, 100, 1000 * 60, pi);
        }
    
        public override void OnEnabled(Context context)
        {
            AlarmManager am = (AlarmManager)context.GetSystemService(Context.AlarmService);
            Intent ai = new Intent(context, typeof(AlarmReceiver));
            ai.SetAction(WidgetConsts.ActionWakeup);
            PendingIntent pi = PendingIntent.GetBroadcast(context, 0, ai, PendingIntentFlags.UpdateCurrent);
            am.SetRepeating(AlarmType.ElapsedRealtime, 100, 1000 * 60, pi);
    
            base.OnEnabled(context);
        }
    
        public override void OnDisabled(Context context)
        {
            Log.Debug(WidgetConsts.DebugTag, "Disabling the widget");
            if (widgetTimer != null)
            {
                Log.Debug(WidgetConsts.DebugTag, "Stopping timer");
                widgetTimer.Enabled = false;
            }
            else
                Log.Debug(WidgetConsts.DebugTag, "Timer is null");
            base.OnDisabled(context);
        }
    
        private void OnTimedEvent(object sender, ElapsedEventArgs e)
        {
            Log.Debug(WidgetConsts.DebugTag, "Updating status...");
            new Handler(Looper.MainLooper).Post(() =>
            {
                //Run my code to periodically update the widget
                RemoteViews views = new RemoteViews(Android.App.Application.Context.PackageName, Resource.Layout.SnapVertWidget);
                AppWidgetManager manager = AppWidgetManager.GetInstance(Android.App.Application.Context);
                ComponentName thisWidget = new ComponentName(Android.App.Application.Context, Java.Lang.Class.FromType(typeof(AppWidget)));
                int[] appWidgetIds = manager.GetAppWidgetIds(thisWidget);
    
                (AppWidgetManager.GetInstance(Android.App.Application.Context)).UpdateAppWidget(new ComponentName(Android.App.Application.Context, Java.Lang.Class.FromType(typeof(AppWidget))), views);
    
               // manager.UpdateAppWidget(appWidgetIds[0], views);
            });
        }
    
        static public void UpdateAppWidget(Context context)
        {
            Intent intent = new Intent(context, typeof(AppWidget));
            intent.SetAction(WidgetConsts.ActionWidgetUpdate);
            int[] ids = AppWidgetManager.GetInstance(context).GetAppWidgetIds(new ComponentName(context, Java.Lang.Class.FromType(typeof(AppWidget))));
            intent.PutExtra(AppWidgetManager.ExtraAppwidgetIds, ids);
            context.SendBroadcast(intent);
        }
    
        public RemoteViews BuildRemoteViews(Context context, int[] appWidgetIds)
        {
    
            Excercise.Droid.Services.WeatherWidget weatherWidget = new Excercise.Droid.Services.WeatherWidget();
            var entry = weatherWidget.GetCurrentWeather();
    
            // Build an update that holds the updated widget contents
            var updateViews = new RemoteViews(context.PackageName, Resource.Layout.SnapVertWidget);
    
            updateViews.SetTextViewText(Resource.Id.txtvwUpdate, Convert.ToString(DateTime.Now)); updateViews.SetTextViewText(Resource.Id.txtvwCityName, entry.Result.CityName);
            updateViews.SetTextViewText(Resource.Id.txtvwTemp, entry.Result.TempValue);
    
    
            //SetTextViewText(widgetView);
            RegisterClicks(context, appWidgetIds, updateViews);
    
            return updateViews;
    
        }
        private void RegisterClicks(Context context, int[] appWidgetIds, RemoteViews widgetView)
        {
            Intent intentUpdate = new Intent(context, typeof(AppWidget));
            intentUpdate.SetAction(AppWidgetManager.ActionAppwidgetUpdate);
    
            //Update the current widget instance only, by creating an array that contains the widget’s unique ID// 
    
            int[] idArray = new int[] { appWidgetIds[0] };
            intentUpdate.PutExtra(AppWidgetManager.ExtraAppwidgetIds, idArray);
            PendingIntent pendingUpdate = PendingIntent.GetBroadcast(
              context, appWidgetIds[0], intentUpdate,
              PendingIntentFlags.UpdateCurrent);
            widgetView.SetOnClickPendingIntent(Resource.Id.btnRefresh, pendingUpdate);
    
            Intent launchAppIntent = new Intent(context, typeof(MainActivity));
            PendingIntent launchAppPendingIntent = PendingIntent.GetActivity(context, 0, launchAppIntent, PendingIntentFlags.UpdateCurrent);
            widgetView.SetOnClickPendingIntent(Resource.Id.pnlWeather, launchAppPendingIntent);
    
               }
    }
    
    Thursday, December 3, 2020 2:24 PM

All replies

  • User371688 posted

    Duplicated thread:https://forums.xamarin.com/discussion/186553/web-service-doesn-t-work-when-i-try-to-update-the-android-widget-if-the-app-is-killed

    Friday, December 4, 2020 7:15 AM