JanBo
JanBo

Reputation: 2943

Widget problems on android 4.0.3

I have tried maybe around 7,8 tutorials and read at least 30,40 answers here but in vain...i cant get any widget working on my phone.

Every widget implementation doesnt update the text on my widgets nor it does register widgets on click.

for example this tutorial: http://blog.doityourselfandroid.com/2011/05/24/developing-android-home-screenwidgets/ you can download the code, it runs fine on my friends phone ( android 2.3) but on my phone i can see the receivers firing in Log Cat but nothing updates?

Here is my current simple code:

1.manifest

<receiver android:name=".TestWidgetProvider">
        <meta-data android:name="android.appwidget.provider"
            android:resource="@xml/testwidgetprovider"
            />
        <intent-filter >
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
        </intent-filter>

    </receiver>
    <receiver android:name=".TestReceiver"/>
  1. TestWidgetProvider

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
    
    
    Log.d("CSV", "Called on onUpdate");
    
    AlarmManager am=(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Calendar cal=Calendar.getInstance();
    cal.add(Calendar.SECOND, 30);
    
    Intent intent=new Intent(context, TestReceiver.class);
    
    
    int N=appWidgetIds.length;
    for (int i=0; i<N; i++) {
    
        RemoteViews tt=new RemoteViews(context.getPackageName(), R.layout.testwidget);
    
        tt.setTextViewText(R.id.textView1,"UPDATED" +i);
    
        appWidgetManager.updateAppWidget(appWidgetIds[i], tt);
    
        Log.d("CSV", "Update widget, i = " +i + " widgetId=" + appWidgetIds[i] );
    
    }
    
    
    
    intent.putExtra("id", appWidgetIds);
    intent.putExtra("duz", appWidgetIds.length);
    
    PendingIntent p1=PendingIntent.getBroadcast(context, 1, intent, 0);
    am.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 10000, p1);
    
    super.onUpdate(context, appWidgetManager, appWidgetIds);
    

    }

  2. TestReceiver

    public class TestReceiver extends BroadcastReceiver {
    
    
    private static final String tag="TestReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
    // TODO Auto-generated method stub
    
    
    int[] ID;
    Bundle extras=intent.getExtras();
    ID=extras.getIntArray("id");
    int duz=intent.getIntExtra("duz", 0);
    
    Log.d("CSV", "update widget id=" +ID);
    
    
    double b=Math.random();
    int i=(int) ((b*10+1)%10);
    
    RemoteViews rv=new RemoteViews(context.getApplicationContext().getPackageName(), R.layout.testwidget);
    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context.getApplicationContext());
    
    
    for (int a=0; a<duz; i++) {
    
        rv.setTextViewText(R.id.textView1, "update random: " + a);
        appWidgetManager.updateAppWidget(ID[a], rv);
        Log.d("CSV", "Update widget, a = " +a + " widgetId=" + ID[a] );
    
    }
    
    
    /*
    ComponentName provider = new ComponentName(context, TestWidgetProvider.class);
    appWidgetManager.updateAppWidget ( provider, rv);
    */
    

    }

  3. widget xml

    <?xml version="1.0" encoding="utf-8"?>
       <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 
        android:minWidth="200dp"
    android:minHeight="120dp"
    android:updatePeriodMillis="0"
    android:initialLayout="@layout/testwidget"
    android:resizeMode="horizontal|vertical"
    >
    </appwidget-provider>
    

Please help i've been stuck for days know...

Edit 1. I've added a main activity as proposed by first answer, but no change.

Also the text doesnt update pragmatically the first time i set the widget on screen, like it cant find the widget, but the second time i put the widget on screen it changes its text according to the code in onEnable?

Edit 2: I have posted an answer that fixed my issue for now, and got the widget updating

Edit 3. I have marked Richard Le Mesurier's answer as the correct one since his demo code goes into great detail of managing widgets via services while doing network operations. It covers my issue as well as many other ones i was about to ask. I recommend that you study this demo if you are going to do some serious work with widgets.

Upvotes: 1

Views: 556

Answers (2)

Richard Le Mesurier
Richard Le Mesurier

Reputation: 29762

Answer 2 (update with link to working demo)

As promised to @JanBo, some more details on how I approached this problem (disclaimer - this is just my opinion, and I hope for constructive comments on how to improve).

JanBo had a problem with one update method working, and one failing. I suggested he combine them into a single method, that can be called in both cases.

I have a Proof-Of-Concept demo widget app on GitHub called StackFlairWidget. It displays a user's Stack Overflow "flair" image:

(This project is in progress - it may be easier to use the POC Complete commit to see code relevant to this problem. It has some bugs, but is simpler to understand than the head revision.)

It is a demo to allow multiple widgets to be configured differently. You could e.g. search the project for "appWidgetId" to show how I pass the widget ID around the various methods, enabling the user to configure the widgets correctly.

It shows the pattern of offloading the widget update code into a thread inside a service, so as not to strain your BroadcastReceiver - you will probably need to do something similar as your project grows.

As it is only a demo app, it contains many comments, some overly complex code (borrowed from production apps) but also some horrible hacks (I apologise).

Essentially, your update code is correct, as you state. Mine, fwiw, is in the FlairWidgetService class. It updates a given widget with an image:

public void updateWidget(int appWidgetId, Bitmap flair)
{
    try
    {
        // set remote views
        RemoteViews widgetUi = new RemoteViews(getPackageName(), R.layout.widget);
        widgetUi.setImageViewBitmap(R.id.ivFlair, flair);

        // open Settings on click
        Intent flairSettings = new Intent(this, SettingsActivity.class);
        flairSettings.putExtra(IntentExtra.Key.APP_WIDGET_ID, appWidgetId);
        PendingIntent pendingIntentIp =
                PendingIntent.getActivity(this, appWidgetId, flairSettings,
                        PendingIntent.FLAG_UPDATE_CURRENT);
        widgetUi.setOnClickPendingIntent(R.id.ivFlair, pendingIntentIp);

        /* UPDATE THE WIDGET INSTANCE */
        try
        {
            AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
            widgetManager.updateAppWidget(appWidgetId, widgetUi);
        }
        catch (Exception e)
        {
            Dbug.log("Failed to update widget");
        }
    }
    catch (Exception e)
    {
        Dbug.log("Failed to update widget");
    }
    finally
    {
        // clean up
        FlairWidgetService.this.stopSelf();
    }
}

This is not the only way, but I promised I would provide something... Good luck.


Answer 1 (did not help poster, as per Edit 1)

It looks like you are being hit by a security upgrade which I think happened in HoneyComb.

Basically, in newer versions of Android, you cannot have your widget working, without first launching an Activity.

So add an activity to the project, run it first, and I think your widgets will update.

A good example would be to use a Settings style activity, or perhaps and About box type of thing, to tell the user a bit about your widget. (I use settings in my widgets).


For more info:

Upvotes: 1

JanBo
JanBo

Reputation: 2943

It works if i use this code in my TestReceiver

    ComponentName thisAppWidget = new ComponentName(context.getPackageName(), TestWidgetProvider.class.getName());
     AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context.getApplicationContext());
     int ids[] = appWidgetManager.getAppWidgetIds(thisAppWidget);

     appWidgetManager.updateAppWidget(ids, tt);

and in onUpdate in AppWidgetProvider:

    ComponentName provider = new ComponentName(context, TestWidgetProvider.class);
    appWidgetManager.updateAppWidget ( provider, tt); //tt is RemoteViews tt=...

I am not sure why but this is the only combination that worked for my phone?

If someone know more about this please explain since i need to make a complex service combined with alarm manager that updates etc....

@Richard Le Mesurier thanks for the info for android 4.0 needing to have an activity for the widget, didnt find that anywhere.

Upvotes: 0

Related Questions