4

I have created a widget for my app. All works fine and all the data shown in the widget is displaying correctly. But sometimes what happen whenever I run some other application like a camera and start shooting video for a couple of seconds and stop the video and close the camera then suddenly all the data that are displaying in my widget is lost and it shows nothing in the widget. I don't know whether the problem arises before when I run my app in Android 2.3.3 but as I updated my phone to Android 4.0 this problem shows.

The lost data appear again as the widget updated according to the time interval set by me. So my question is why this data loss occurs, is something I have to do in my code. Please help me to solve this out.

The code I have used

Widget_app_provider.xml file

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/widget_layout"
    android:minHeight="56dp"
    android:minWidth="56dp"
    android:updatePeriodMillis="2100000" />

WidgetLayout.xml file

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/appwidget_bg_clickable" >

    <ImageView
        android:id="@+id/backgroundImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:contentDescription="@string/tracking_status_faq_imageview_text"
        android:scaleType="fitXY" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center_horizontal|center_vertical" >

        <TextView
            android:id="@+id/txt_date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#5f5f5f"
            android:textSize="14dp" >
        </TextView>
    </LinearLayout>

</RelativeLayout>

Widget.java file

public class Widget extends AppWidgetProvider implements Utilities
    {
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) 
    {      
        // Read data from register before  updating the widget
        CycleManager.getSingletonObject().readHistoryDateFromFile(context);
        CycleManager.getSingletonObject().ComputeAverages();
        
        // To prevent any ANR timeouts, we perform the update in a service
        context.startService(new Intent(context, UpdateService.class));
    }

    public static class UpdateService extends Service 
    {
        @Override
        public void onStart(Intent intent, int startId) 
        {
            // Build the widget update for today
            RemoteViews updateViews = getValueFromCycleManager(this);

            // Push update for this widget to the home screen
            ComponentName thisWidget = new ComponentName(this, Widget.class);
            AppWidgetManager manager = AppWidgetManager.getInstance(this);
            manager.updateAppWidget(thisWidget, updateViews);
        }

        @Override
        public IBinder onBind(Intent arg0){
            // TODO Auto-generated method stub
            return null;
        }
        public RemoteViews getValueFromCycleManager(Context context) 
        {
            RemoteViews remoteViews = null;
            remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
                        
            Date currentDate = calInstance.getTime();
            
            // set No of days remaining for next cycle start to the widgets 
            Date dtStart = CycleManager.getSingletonObject().getStartDate();
            int iAvgCycleLength = CycleManager.getSingletonObject().getAvgCycleTime();
            
            calInstance.setTime(dtStart);
            calInstance.add(Calendar.DATE, iAvgCycleLength);            
            Date dtNextCycleDate = calInstance.getTime();   
            
            Long noOfDaysLeft = dtNextCycleDate.getTime()- currentDate.getTime();
            noOfDaysLeft = ((noOfDaysLeft / (1000 * 60 * 60)) + 1) / 24;
            
            remoteViews.setTextViewText(R.id.txt_date, Long.toString(noOfDaysLeft));        
        }
    }
}
iknow
  • 8,358
  • 12
  • 41
  • 68
AndroidDev
  • 4,521
  • 24
  • 78
  • 126
  • Even Singletons get removed from memory (everything in memory in fact) if the device shuts down your process because memory is low. Might be a reason but Idk – zapl Apr 27 '12 at 08:34
  • I am getting your point.Can u elaborate briefly. It will be helpful for me. – AndroidDev Apr 27 '12 at 09:17
  • If you rely on some kind of state saved in a `static` variable & your process is killed you start like you would do after a device reboot. So you have to design your widget in a way that it can always reconstruct it's state (it looks like you do that since you read from a file). I don't know exactly what your problem is and maybe it's just the service that gets killed (btw you should implement `onStartCommand` instead of `onStart` and return `START_REDELIVER_INTENT` from there) – zapl Apr 27 '12 at 10:03
  • and call stopSelf(startId) after you are done. Or use an [IntentService](http://stackoverflow.com/questions/5027147/intent-service-example-in-android) that does the tricky parts for you and should be well suited for your task. – zapl Apr 27 '12 at 10:07
  • Ok i will try and let u know.. – AndroidDev Apr 27 '12 at 10:20
  • @zapl i don't able to get how to change it in my code..can u please show me if u don't mind...it will be helpful for me. – AndroidDev Apr 27 '12 at 10:28

1 Answers1

1

Try implementing an IntentService which should handle being killed better. You need to do the work in onHandleIntent which is called with the intent you specify in context.startService(new Intent(context, UpdateService.class));.

public static class UpdateService extends IntentService 
{

    public UpdateService() 
    {
        super("UpdateService");
    }

    @Override
    protected void onHandleIntent(Intent intent)
    {
        // Build the widget update for today
        RemoteViews updateViews = getValueFromCycleManager(this);

        // Push update for this widget to the home screen
        ComponentName thisWidget = new ComponentName(this, Widget.class);
        AppWidgetManager manager = AppWidgetManager.getInstance(this);
        manager.updateAppWidget(thisWidget, updateViews);
    }

    public RemoteViews getValueFromCycleManager(Context context) 
    {
        RemoteViews remoteViews = null;
        remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

        Date currentDate = calInstance.getTime();

        // set No of days remaining for next cycle start to the widgets 
        Date dtStart = CycleManager.getSingletonObject().getStartDate();
        int iAvgCycleLength = CycleManager.getSingletonObject().getAvgCycleTime();

        calInstance.setTime(dtStart);
        calInstance.add(Calendar.DATE, iAvgCycleLength);            
        Date dtNextCycleDate = calInstance.getTime();   

        Long noOfDaysLeft = dtNextCycleDate.getTime()- currentDate.getTime();
        noOfDaysLeft = ((noOfDaysLeft / (1000 * 60 * 60)) + 1) / 24;

        remoteViews.setTextViewText(R.id.txt_date, Long.toString(noOfDaysLeft));        
    }
}
zapl
  • 63,179
  • 10
  • 123
  • 154
  • Ok..means there is no need of onStart method as i have used....on the UpdateService class – AndroidDev Apr 27 '12 at 10:40
  • yep `IntentService` is a specialized subclass where you should implement `onHandleIntent`. For a regular `Service` it would be `onStartCommand` and `onStart` is deprecated and should not be used at all. – zapl Apr 27 '12 at 10:44
  • Yeh the problem is solved but am little confused about what u have done. In my initial code the widget display things properly but only when i open some other app like camera and start shooting video and then close the camera then all the data display in my app widget get lost. The thing i don't understand is how the use of camera or some other heavy application cause loss in my app widget. Although there is no connection between them..and how ur code solve the issue – AndroidDev Apr 27 '12 at 10:49
  • @Anshuman Android needs more memory so it is closing apps that does not need so much memory. When heavy app closes service is started again. – Tomáš Hubálek Dec 13 '12 at 10:14