1

I want to create a clock widget with a second watch hand. And yes, I already read that widgets aren't designed to be refreshed that fast.

The widget should become an egg timer which is only animated when the user actively starts it so it is probably not that bad for battery life and performance at all because I only use this high refresh rate when the user actively uses it...

Currently I start a service which posts a delayed runnable every 1000 milliseconds.

Handler mTimeRecordLongTouchedHandler = new Handler();
Runnable mTimeRecordLongTouched = new Runnable() {
    public void run() {

        remoteViews.setTextViewText(R.id.tv_widget_watch, _fmtTime.print(new DateTime()));
        Bitmap bmpSource = _bmpSource.copy(Bitmap.Config.ARGB_8888, true);

        Canvas canvas = new Canvas(bmpSource);


        DateTime dtNow = new DateTime();
        int iSeconds = dtNow.getSecondOfMinute();

        float radius = _bmpSource.getWidth() / 2;
        float mX = _bmpSource.getWidth() / 2;
        float mY = _bmpSource.getWidth() / 2;

        float pX = mX + radius * FloatMath.cos(iSeconds * 6);
        float pY = mY + radius * FloatMath.sin(iSeconds * 6);

        canvas.drawLine(mX, mY, pX, pY, paint3);

        remoteViews.setImageViewBitmap(R.id.iv_tower, bmpSource);

        manager.updateAppWidget(thiswidget, remoteViews);
        iCounter++;

        // if (bmpLast != null) {
        // bmpLast.recycle();
        // }
        // bmpLast = bmpSource;

        mTimeRecordLongTouchedHandler.postDelayed(mTimeRecordLongTouched, 1000);
    }
};

After a few seconds I get: “android.os.TransactionTooLargeException”. For this exception I don’t have a stack trace but I guess it is because I don’t recycle my newly created bitmap. The exception after this is: “system server dead?” and here I have a stacktrace:

03-07 11:26:28.374: E/AndroidRuntime(13422): FATAL EXCEPTION: main
03-07 11:26:28.374: E/AndroidRuntime(13422): java.lang.RuntimeException: system server dead?
03-07 11:26:28.374: E/AndroidRuntime(13422):    at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:554)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at com.mxp.time.service.WidgetService$1.run(WidgetService.java:90)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at android.os.Handler.handleCallback(Handler.java:730)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at android.os.Handler.dispatchMessage(Handler.java:92)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at android.os.Looper.loop(Looper.java:137)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at android.app.ActivityThread.main(ActivityThread.java:5493)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at java.lang.reflect.Method.invokeNative(Native Method)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at java.lang.reflect.Method.invoke(Method.java:525)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at dalvik.system.NativeStart.main(Native Method)
03-07 11:26:28.374: E/AndroidRuntime(13422): Caused by: android.os.TransactionTooLargeException
03-07 11:26:28.374: E/AndroidRuntime(13422):    at android.os.BinderProxy.transact(Native Method)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.updateAppWidgetProvider(IAppWidgetService.java:736)
03-07 11:26:28.374: E/AndroidRuntime(13422):    at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:551)
03-07 11:26:28.374: E/AndroidRuntime(13422):    ... 10 more

I thought that I can solve this easily with just recycling my bitmap

if (bmpLast != null) {
            bmpLast.recycle();
        }
        bmpLast = bmpSource;

but this just leads me to the next problem:

03-07 11:28:22.964: E/AndroidRuntime(14559): FATAL EXCEPTION: main
03-07 11:28:22.964: E/AndroidRuntime(14559): java.lang.IllegalStateException: Can't parcel a recycled bitmap
03-07 11:28:22.964: E/AndroidRuntime(14559):    at android.graphics.Bitmap.checkRecycled(Bitmap.java:273)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at android.graphics.Bitmap.writeToParcel(Bitmap.java:1332)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at android.widget.RemoteViews$BitmapCache.writeBitmapsToParcel(RemoteViews.java:988)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at android.widget.RemoteViews.writeToParcel(RemoteViews.java:2573)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.updateAppWidgetProvider(IAppWidgetService.java:730)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at android.appwidget.AppWidgetManager.updateAppWidget(AppWidgetManager.java:551)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at com.mxp.time.service.WidgetService$1.run(WidgetService.java:90)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at android.os.Handler.handleCallback(Handler.java:730)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at android.os.Handler.dispatchMessage(Handler.java:92)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at android.os.Looper.loop(Looper.java:137)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at android.app.ActivityThread.main(ActivityThread.java:5493)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at java.lang.reflect.Method.invokeNative(Native Method)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at java.lang.reflect.Method.invoke(Method.java:525)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
03-07 11:28:22.964: E/AndroidRuntime(14559):    at dalvik.system.NativeStart.main(Native Method)

I already cache my last bitmap and only recycle it when the new one is forwarded to the widget. Why do I get this exception?

Who wants to parcel my last Bitmap? Keeps the widget a reference to all Bitmaps I pass in???

Cheers, Stefan

stefan
  • 1,336
  • 3
  • 21
  • 46

2 Answers2

1

you should recycle bitmap like this

if (bmpLast != null) {
        bmpLast.recycle();
        bmpLast=null;//you must do it
    }

Other then this there is another issue you should use alarmmanager to update widget ,it will cumsume less battery compared to Runnable() ;

Shakeeb Ayaz
  • 6,200
  • 6
  • 45
  • 64
  • Actually I use a service. This Runnable is just started in my service “onStart()”. I don't see any benefits from using AlarmManager. Actually I see some drawbacks: 1.) I need to register a receiver 2.) I need an extra permission – stefan Mar 07 '14 at 11:19
  • no need to register extra receiver Appwidget provide contain onReceive method like onupdate. U can set ararmmanager in onupdate which will call onReceive in same class. – Shakeeb Ayaz Mar 07 '14 at 11:23
  • did u checked by adding bmpLast=null; in your code – Shakeeb Ayaz Mar 07 '14 at 11:24
  • check out http://stackoverflow.com/questions/20651197/onupdate-intilized-variable-are-null-in-onreceive-of-widget-class how i used onReceive of appwidgetprovidre class – Shakeeb Ayaz Mar 07 '14 at 11:26
  • The only reason why I use bmpLast is because I tried to get around this exception: Can't parcel a recycled bitmap. If I set bmpLast explicitly to null this piece of code would become useless (what it actually already is because I still get this exception). – stefan Mar 07 '14 at 11:30
  • keep hunting for ur answer..I am sure u'll find ans to ur problem keep it up – Shakeeb Ayaz Mar 07 '14 at 11:33
  • I use my onReceive of my AppWidgetProvider only to catch my Button clicks... You seem to be the expert on this topic... Is this the correct way to do? – stefan Mar 07 '14 at 11:42
  • what u r doing is correct.I am not an expert but I have worked on widget. – Shakeeb Ayaz Mar 07 '14 at 11:52
  • 1
    This is my first widget so you are more an expert than me :) – stefan Mar 07 '14 at 11:54
1

Part of your problem is probably that you hang on to your RemoteViews object and keep adding 'actions' to it. RemoteViews doesn't do any smart de-duplication of actions, it just appends them to a list, so you're effectively retaining references to every Bitmap you push into it.

Karsten
  • 310
  • 1
  • 6