views:

102

answers:

2

Hi everyone,

BACKGROUND INFO:

I need to update some data from the web, about every hour or so, even when my app is closed. The update of the data itself takes about 40 seconds to 1 minute. It is then saved as a Serializable to a file. This file is read when my app starts.

THIS IS THE APPROACH I TOOK FOR THE MOMENT (not using a Service)

use the AlarmManager and BroadcastReceiver like this :

private void set_REFRESH_DATA_Alarm(){
    mContext = Main.this;
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

    broadcast_intent = new Intent(mContext, RepeatingAlarmReceiver_REFRESH_DATA.class);
    pendingIntent = PendingIntent.getBroadcast(mContext, 0,  broadcast_intent, 0);

    // do a REFRESH every hour, starting for the first time in 30 minutes from now ...
    Calendar now = Calendar.getInstance();
    long triggerAtTime = now.getTimeInMillis()+ (1 * 30 * 60 * 1000);   // starts in 30 minutes
    long repeat_alarm_every = (1 * 60 * 60 * 1000);                 // repeat every 60 minutes/1 hour
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, triggerAtTime, repeat_alarm_every, pendingIntent);
}

My RepeatingAlarmReceiver_REFRESH_DATA.class takes care of updating the Data from the Web:

public class RepeatingAlarmReceiver_REFRESH_DATA extends BroadcastReceiver {

public static Context mContext;
ConnectivityManager mConnectivity;

@Override
public void onReceive(Context context, Intent intent) {

    mContext = context;

    // if Network connection is OK (Wifi or Mobile) then Load data ...
    mConnectivity = (ConnectivityManager)   context.getSystemService(Context.CONNECTIVITY_SERVICE); 

    Log.i("Hub", "mConnectivity.getNetworkInfo(0)="+mConnectivity.getNetworkInfo(0));
    Log.i("Hub", "mConnectivity.getNetworkInfo(1)="+mConnectivity.getNetworkInfo(1));

    if ((mConnectivity.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED)||( mConnectivity.getNetworkInfo(1).getState() == NetworkInfo.State.CONNECTED)) { 

        Log.i("Hub","Connectivity OK ...");
        Refresh_HIST_DATA();

    } else {
        // else Show Dialog "No network connection" ...
        Log.i("Hub", "No network connection for the moment... will try again later!");
    }
}

// =================================================================================
private void Refresh_HIST_DATA() {

    Log.i("Hub", "Refresh_HIST_DATA()... Starting ...");

etc...

In the Manifest I have :

<receiver android:name="com.cousinHub.myapp.RepeatingAlarmReceiver_REFRESH_DATA" android:process=":remote" />

PROBLEM :

The alarm gets fired on time and the update starts but then after about 10 seconds it stops (Timeout):

06-25 11:55:05.278: WARN/ActivityManager(76): Timeout of broadcast BroadcastRecord{44bb4348 null} - receiver=android.os.BinderProxy@44bcc670

06-25 11:55:05.278: WARN/ActivityManager(76): Receiver during timeout: ResolveInfo{44bb42c0 com.cousinHub.myapp.RepeatingAlarmReceiver_REFRESH_DATA p=0 o=0 m=0x0}

06-25 11:55:05.278: INFO/Process(76): Sending signal. PID: 819 SIG: 9

06-25 11:55:05.298: INFO/ActivityManager(76): Process com.cousinHub.myapp:remote (pid 819) has died.

ps: strangely enough, this "Timeout" does not happen after about 10 seconds on my HTC Hero (still on Android 1.5 - API Level 4) but well on my Nexus One (2.1-update1)

Questions :

  1. Why this timeout ? Any easy way to avoid this ?
  2. Did I set up my BroadcastReceiver correctly in the manifest ? Do I need to add something (to avoid this timeout) ?
  3. Should I absolutely go for a Service for this kind of "Refresh from Web" functionality ? (considering this article : http://www.androidguys.com/2009/09/09/diamonds-are-forever-services-are-not/) If YES (I should switch to a service): Any good snippets of code/tutorial for this ...

As allways, thanks for your help.

H.

+2  A: 

Why this timeout ?

You are running on the main application thread. You cannot run on the main application thread for more than a few seconds. Also, while doing this, you are harming the performance of the device (because you are running with foreground priority), such as causing frame-rate loss in games or videos.

Any easy way to avoid this ?

Don't do significant work (>100ms) on the main application thread. Have your BroadcastReceiver delegate to an IntentService, perhaps a WakefulIntentService.

Did I set up my BroadcastReceiver correctly in the manifest ?

Please please please please please get rid of the android:process=:remote. You do not need it, it is not helping you, and it is degrading performance of the device even further.

Should I absolutely go for a Service for this kind of "Refresh from Web" functionality ? (considering this article : http://www.androidguys.com/2009/09/09/diamonds-are-forever-services-are-not/) If YES (I should switch to a service): Any good snippets of code/tutorial for this ...

IMHO, yes. Then again, I wrote that blog post. For an example, see the WakefulIntentService project.

CommonsWare
and the WakefulIntentService will be able to "live" more than 30 secs and update all my data ? will it have access to the file that my app will then read ?
Hubert
"and the WakefulIntentService will be able to "live" more than 30 secs and update all my data ?" The [`IntentService`](http://developer.android.com/reference/android/app/IntentService.html) will live as long as your `onHandleIntent()` (or `doWakefulWork()` in `WakefulIntentService`) is doing its work. "will it have access to the file that my app will then read ?" As much as your `BroadcastReceiver` does today, presumably. Note that I am not you, and therefore did not write your code, so I have no idea what this "file that my app will then read" is.
CommonsWare
A last question if I may : How do I best access the app context (mContext => maybe "Context mContext = (Context) getApplicationContext();") within AppService.doWakefulWork ? The goal is to access my apps Preferences with "pref = PreferenceManager.getDefaultSharedPreferences(mContext);" and my files with "FileOutputStream fOut = mContext.openFileOutput(Globals.mFileName, Context.MODE_WORLD_READABLE);"
Hubert
YES IT WORKS with Context mContext = (Context) getApplicationContext();
Hubert
A: 

For information, I've tried with a new thread and it works when on Wifi (takes about 1'30" to update the data when phone is asleep, it doesn't get 'killed' !

//let's try with a new separate thread ?
        new Thread(new Runnable() {
            public void run() {
                Refresh_HIST_DATA();
            }
          }).start();

but NOT when on Mobile (GPRS), as it gets killed after about 10 secs!

It's half-a-solution for the moment and I will try CommonsWare's solution for a cleaner/more sustainable approach...

Let's see if the new thread solution works allways fine or was just luck (I've tested only during a couple hours) ...

If anyone else has another suggestion, please do post it.

Hubert
the new thread solution does not always work, so avoid ! Let's go for CommonsWare's solution then.
Hubert