0

I am developing a widget which is running without any errors but the ImageView of my widget are not updating and also not giving any errors. Thus making me confused about what wrong i am doing. Here is the code:-

BroadcastReceiver _broadcastReceiver;
GetDrawableResources getDrawableResources = new GetDrawableResources();
private final SimpleDateFormat _sdfWatchTime = new SimpleDateFormat("HH:mm");

@Override
public void onEnabled(final Context context) {
    super.onEnabled(context);
    // TODO Auto-generated method stub
    System.out.println("Entering onstart");
    _broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context ctx, Intent intent) {
            System.out.println("Registering BroadCast");
            if (intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0) {

                System.out.println(_sdfWatchTime.format(new Date()));
                Bundle extras = intent.getExtras();
                if (extras != null) {
                    AppWidgetManager awm = AppWidgetManager
                            .getInstance(context);
                    ComponentName thisWidget = new ComponentName(
                            context.getPackageName(),
                            MainActivity.class.getName());
                    int[] appWidgetIds = awm.getAppWidgetIds(thisWidget);
                    onUpdate(context, awm, appWidgetIds);
                }

            }
        }
    };
    context.getApplicationContext().registerReceiver(_broadcastReceiver,
            new IntentFilter(Intent.ACTION_TIME_TICK));

}

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {
    // TODO Auto-generated method stub
    super.onUpdate(context, appWidgetManager, appWidgetIds);
    for (int awID : appWidgetIds) {
        updateAppWidget(context, appWidgetManager, awID);
    }

}

private void updateAppWidget(Context context,
        AppWidgetManager appWidgetManager, int awID2) {
    // TODO Auto-generated method stub
    // class to get drawable images that will be used to denote hours and
    // minutes

    int time[] = new int[new GetTime().getTime(context
            .getApplicationContext()).length];
    // class to get each digit of time separately eg 10:10, separating 1 0 1
    // 0 working correctly
    time = new GetTime().getTime(context.getApplicationContext());
    // changing views

    System.out.println("awID for " + awID2);
    RemoteViews views = new RemoteViews(context
            .getPackageName(), R.layout.activity_main);

    views.setImageViewResource(R.id.ivHour0,
            getDrawableResources.setTimeDrawable(time[0]));
    views.setImageViewResource(R.id.ivHour1,
            getDrawableResources.setTimeDrawable(time[1]));
    views.setImageViewResource(R.id.ivMinute0,
            getDrawableResources.setTimeDrawable(time[2]));
    views.setImageViewResource(R.id.ivMinute1,
            getDrawableResources.setTimeDrawable(time[3]));


    System.out.println("updating the views");

    appWidgetManager.updateAppWidget(awID2, views);

}

The output in my LogCat

06-28 19:46:00.076: I/System.out(680): Registering BroadCast
06-28 19:46:00.086: I/System.out(680): 19:46
06-28 19:46:00.096: I/System.out(680): awID for 14
06-28 19:46:00.096: I/System.out(680): updating the views
06-28 19:47:00.086: I/System.out(680): Registering BroadCast
06-28 19:47:00.086: I/System.out(680): 19:47
06-28 19:47:00.096: I/System.out(680): awID for 14
06-28 19:47:00.096: I/System.out(680): updating the views

Thus the appWidgetID is correct and the function is executing as it should but the Views are not updating. They are same as before.

Rohan Kandwal
  • 9,112
  • 8
  • 74
  • 107

1 Answers1

1

Your approach has a valid base, however you are creating and registering your broadcastReceiver in the onEnabled method which in turn belongs to the WidgetProvider class.

When the methods of the WidgetProvider (onEnabled, onUpdate) finish executing then the WidgetProvider class is destroyed by the system and so is your broadcastReceiver. As you can see no error here but no receiving as well.

In order to do what are you want you need a more "stable" application component to hold your broadcastReceiver, a component like that is a service. A service keeps running even when your application has stoped so it is a good component for those kind of jobs.

So to answer your question I suggest that you create a service which creates and register your broadcastReceiver then you start the service from onEnabled method of your widgetprovider class and you can stop the service when the user removes your widget(s) from his home screen.

A good place to start with my suggestion is here...

EDIT Here is the documentation of App Widgets from google that (about in the middle) states:

Note: Because AppWidgetProvider is an extension of BroadcastReceiver, your process is not guaranteed to keep running after the callback methods return (see BroadcastReceiver for information about the broadcast lifecycle). If your App Widget setup process can take several seconds (perhaps while performing web requests) and you require that your process continues, consider starting a Service in the onUpdate() method. From within the Service, you can perform your own updates to the App Widget without worrying about the AppWidgetProvider closing down due to an Application Not Responding (ANR) error. See the Wiktionary sample's AppWidgetProvider for an example of an App Widget running a Service.

I had similar problems with you in my appwidget which it turns out were caused by my appwidgetprovider's lifetime so I answered you based on that. However in your observations you are right your widget should update itself at least with the current time on the first update so looking more in to it I see that you are using a custom getDrawableResources class to get your resources (can you edit your question with its code?) and you are using getDrawableResources.setTimeDrawable(time[0])); in order to get the drawable, maybe you should change it to getDrawableResources.getTimeDrawable(time[0]))?

EDIT 2

Here is the code that illustrates my suggestion. First of all is the service in which we register a BatteryReceiver.

class FullWidgetBatteryChangedReceiver extends BroadcastReceiver {
//----- BroadcastReceiver Overrides -----
@Override
public void onReceive(Context cx, Intent intent) {
    Log.d("BatteryChangedReceiver", "onReceive");

    Commands.FullWidgetUpdate(cx, -1, 0); //<-- Update all widgets
}
//----- BroadcastReceiver Overrides END -----
}

public class myWidgetService extends Service {

//----- Private Members -----
private FullWidgetBatteryChangedReceiver    bcRCV;
//----- Private Members END -----



//----- Private Code -----    
private void RegisterBatteryChangedReceiver() {
    Log.d(TAG, "RegisterBatteryChangedReceiver");

    if (bcRCV == null) {
        Log.d(TAG, "BatteryChangedReceiver needs Registration and I am doing it...");

        bcRCV = new FullWidgetBatteryChangedReceiver();
        IntentFilter actions = new IntentFilter();
        actions.addAction(Intent.ACTION_BATTERY_CHANGED);
        registerReceiver(bcRCV, actions);
    } else {
        Log.d(TAG, "BatteryChangedReceiver does not needs Registration");
    }
}

private void UnRegisterBatteryChangedReceiver() {
    Log.d(TAG, "UnRegisterBatteryChangedReceiver");

    if (bcRCV != null) {
        Log.d(TAG, "Assuming that BatteryChangedReceiver is registered and I am unregister it...");

        unregisterReceiver(bcRCV);
        bcRCV = null;
    } else {
        Log.d(TAG, "Assuming that BatteryChangedReceiver is NOT registered");
    }
}    
//----- Private Code END -----



//----- Service Overrides -----
@Override
public void onCreate() {
    super.onCreate();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    RegisterBatteryChangedReceiver();

    return Service.START_STICKY; //<-- This is important!!!
}   

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onDestroy() {       
    UnRegisterBatteryChangedReceiver();

    super.onDestroy();
}   
//----- Service Overrides END -----

}

Then here is the myWidgetProvider in which the service manipulation is done:

public class myWidgetProvider extends AppWidgetProvider {


//----- AppWidgetProvider Overrides -----
@Override
public void onEnabled(Context context) {
    super.onEnabled(context);
}

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

    // If no specific widgets requested, collect list of all
    if (appWidgetIds == null) {
        appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, FullWidgetProvider.class));
    }

    // Εδώ κάνουμε update to Widget για κάθε id ξεχωριστά
    for (int widgetId : appWidgetIds) {
        Commands.FullWidgetUpdate(context, widgetId, 0); //<-- Update το widgetId
    }

    context.startService(new Intent(context, myWidgetService.class));
}

@Override
public void onDeleted(Context context, int[] appWidgetIds) {        
    super.onDeleted(context, appWidgetIds);
}

@Override
public void onDisabled(Context context) {
    super.onDisabled(context);

    context.stopService(new Intent(context, FullWidgetService.class));

    int[] appWidgetIds = AppWidgetManager.getInstance(context).getAppWidgetIds(new ComponentName(context, FullWidgetProvider.class));

    if (appWidgetIds.length != 0) {
        AppWidgetHost host = new AppWidgetHost(context, 0);

        for (int widgetId : appWidgetIds) {
            host.deleteAppWidgetId(widgetId);
        }   
    }
}
//----- AppWidgetProvider Overrides END -----       
}

Hope this helps...

ChD Computers
  • 3,135
  • 3
  • 23
  • 33
  • I didn't knew that these WidgetProvider class and broadcastReceiver is destroyed after execution. I am reading about the service and mark the answer correct if it solved my problem. Thanks – Rohan Kandwal Jun 28 '13 at 15:26
  • I want to clear something. You said that after execution onEnabled, onUpdate and broadcastReciever are destroyed but every minute my broadcastReciever then onUpdate and then finally updateAppWidget is called. Thus if updateAppWidget is called every minute then the views must be updated since updation is done in this method. Am I saying anything wrong? – Rohan Kandwal Jun 28 '13 at 15:47
  • `getDrawableResources` is a custom class that i made which is not extending or implementing anything. It is a simple class. It is returning the id of the image based on the time[0] send. eg- if time [0] is 8 then the code running in `getDrawableResources` is case 8: time = R.drawable.time_8; break; – Rohan Kandwal Jun 28 '13 at 17:31
  • Although i couldn't find the solution of the problem till now but by "create a service which creates and register your broadcastReceiver" you mean something like this? http://pastie.org/8092129 . Although this example uses activity but its working and i know how to implement it in widget. I just want to know that i did it correctly. – Rohan Kandwal Jun 28 '13 at 18:36
  • 1
    @RohanKandwal Yes something like this but take a look at my second edit in which I added some code illustrating this approach. Thank you. – ChD Computers Jun 28 '13 at 20:37
  • `Commands`? I can't seem to import it nor could find any documentation – Rohan Kandwal Jul 01 '13 at 04:28
  • IT'S WORKING FINALLY... Million thanks to you.. Just made a service and registered the BroadcastReciever through it. Your example helped a lot. Just tell me about `Commands.FullWidgetUpdate(context, widgetId, 0);` line since i didn't understood that part and i will mark your answer correctly. Once again thanks you a lot. – Rohan Kandwal Jul 01 '13 at 13:22
  • 1
    @RohanKandwal Commands is a custom static class that I made in order to keep things organized. You can replace this line with your updatewidget function. I am very sorry for the inconvenience but my code was for illustration purposes and not a full working one. BTW I am glad that you solved your problem. Thank you. – ChD Computers Jul 01 '13 at 15:53
  • I saw your answer on some other question and saw the same class so got confused. Well thanks for helping me out. – Rohan Kandwal Jul 01 '13 at 16:26