1

I'm working on app which test state on server every 15 min and push notification , i used Alarm Manager , broadcast receiver & Intent Service . every thing worked fine and i get this state from server perfectly when app is running or in background , until i removed it from recent apps, every thing stops and can't get that state from server. I searched ... and get nothing , but my friend tell me that I must register my broadcast receiver in on create of class extend from application.

I don't know how to do this .. so I need help please

Main Activity Class

public class MainActivity extends AppCompatActivity {

    static TextView TvText;
    Button Btn11, Btn22;
    AlarmManager alarm;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);

        TvText = (TextView) findViewById(R.id.tv_Text);
        Btn11 = (Button) findViewById(R.id.btn_11);
        Btn22 = (Button) findViewById(R.id.btn_22);
        Btn22.setEnabled(false);
    }

    public void Btn11OC(View view) {
        scheduleAlarm();
        Btn11.setEnabled(false);
        Btn22.setEnabled(true);
    }

    public void Btn22OC(View view) {
        if (alarm!= null) {
            cancelAlarm();
        } 
        Btn11.setEnabled(true);
        Btn22.setEnabled(false);
    }

    // Setup a recurring alarm every half hour
    public void scheduleAlarm() {
        // Construct an intent that will execute the AlarmReceiver
        Intent intent = new Intent(getApplicationContext(), broadtest.class);
        intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
        // Create a PendingIntent to be triggered when the alarm goes off
        final PendingIntent pIntent = PendingIntent.getBroadcast(this, broadtest.REQUEST_CODE,
            intent, PendingIntent.FLAG_UPDATE_CURRENT);
        // Setup periodic alarm every 5 seconds
         alarm.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(),
             900000L, pIntent);
    }

    public void cancelAlarm() {
        Intent intent = new Intent(getApplicationContext(),      broadtest.class);
        intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
        final PendingIntent pIntent = PendingIntent.getBroadcast(this, broadtest.REQUEST_CODE,
            intent, PendingIntent.FLAG_UPDATE_CURRENT);
        alarm.cancel(pIntent);
    }
}  

Broad Cast Receiver

public class broadtest extends WakefulBroadcastReceiver {
    public static final int REQUEST_CODE = 12345;

    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent(context, MyService.class);
        context.startService(i);
    }
}

AppController Class

public class AppController extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

    }
}

MyService class

public class MyService extends IntentService {
    static int NOTIFICATION_ID = 0;

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

    @Override
    protected void onHandleIntent(Intent intent) {
        String url = "http://test.com/testts.php";
        // Tag used to cancel the request
        String  tag_string_req = "string_req";

        StringRequest strReq = new StringRequest(Request.Method.GET,
            url, new Response.Listener<String>() {

            @Override
            public void onResponse(String response) {
                Log.d("Volley Log", response);
                Toast.makeText(MyService.this, response, Toast.LENGTH_SHORT).show();
                if (response.equals("0")){
                    sendNotification("Titel Test 1111", "Body Test 1111");
                }else if (response.equals("1")){
                    sendNotification("Titel Test 2222", "Body Test 2222");
                }else {
                    sendNotification("Titel Test 3333", "Body Test 3333");
                }
            }
        }, new Response.ErrorListener() {

            @Override
            public void onErrorResponse(VolleyError error) {
                Toast.makeText(MyService.this, error.toString(), Toast.LENGTH_SHORT).show();
                VolleyLog.d("Volley Log", "Error: " + error.getMessage());
            }
        });
        // Adding request to request queue
        int socketTimeout = 30000;//30 seconds - change to what you want
        RetryPolicy policy = new DefaultRetryPolicy(socketTimeout,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
        strReq.setRetryPolicy(policy);
        AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
        // Setup periodic alarm every 5 seconds
    }

    private void sendNotification(String title, String messageBody) {
        long[] pattern = {500,500,500,500,500,500,500,500,500};
        Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(title)
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(alarmSound)
            .setLights(Color.BLUE, 500, 500)
            .setVibrate(pattern);

        NotificationManager notificationManager =
           (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        if (NOTIFICATION_ID > 1073741824) {
            NOTIFICATION_ID = 0;
        }
        notificationManager.notify(NOTIFICATION_ID++, notificationBuilder.build());
    }
} 

Manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.gih.testmass">

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<application
    android:name=".AppController"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <receiver
        android:name=".broadtest"
        android:process=":remote">
    </receiver>

    <service
        android:name=".MyService"
        android:exported="false">
    </service>
</application>

2 Answers2

1

You need to start the service as a foreground service. When you clear app from recents it kills the service

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

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);

        builder.setSmallIcon(R.drawable.ic_notification)
                .setLargeIcon(BitmapFactory.decodeResource(getApplicationContext().getResources(),
                        R.mipmap.ic_launcher))
                .setContentTitle("WhatsApp Reminder Service.")
                .setContentText("Touch to configure.");

        Intent startIntent = new Intent(getApplicationContext(), MainActivity.class);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 965778, startIntent, 0);

        builder.setContentIntent(pendingIntent);

        startForeground(965778, builder.build());

        return START_REDELIVER_INTENT;
}

It is necessary to build a notification when you use foreground service. Hope it helps.

I see you have used IntentService see answer to this question Using startForeground() with an Intent Service

Suraj
  • 184
  • 1
  • 14
0

To run a process on a device when users are not particularly interacting with your application.

The steps will involve:

1.Updating your android manifest xml

2.Setting up broadcast receivers to listen to relevant events

3.Set up a background service for context when your application isn’t running

Android menifest.xml

<?xml version="1.0" encoding="utf-8"?>

<uses-permission ... />

 <application
    android:name=".MyApplication"
    ... >

    <receiver android:name=".receivers.PeriodicTaskReceiver">
       <intent-filter>
           <action android:name="com.example.app.PERIODIC_TASK_HEART_BEAT" />
       </intent-filter>
   </receiver>

   <service android:name=".services.BackgroundService" />

    ...
</application>

Now for the Broadcast receiver

    public class PeriodicTaskReceiver extends BroadcastReceiver {

    private static final String TAG = "PeriodicTaskReceiver";
    private static final String INTENT_ACTION = "com.example.app.PERIODIC_TASK_HEART_BEAT";

    @Override
    public void onReceive(Context context, Intent intent) {
        if (!Strings.isNullOrEmpty(intent.getAction())) {
            MyApplication myApplication = (MyApplication) context.getApplicationContext();
            SharedPreferences sharedPreferences = myApplication.getSharedPreferences();

            if (intent.getAction().equals("android.intent.action.BATTERY_LOW")) {
                sharedPreferences.edit().putBoolean(Constants.BACKGROUND_SERVICE_BATTERY_CONTROL, false).apply();
                stopPeriodicTaskHeartBeat(context);
            } else if (intent.getAction().equals("android.intent.action.BATTERY_OKAY")) {
                sharedPreferences.edit().putBoolean(Constants.BACKGROUND_SERVICE_BATTERY_CONTROL, true).apply();
                restartPeriodicTaskHeartBeat(context, myApplication);
            } else if (intent.getAction().equals(INTENT_ACTION)) {
                doPeriodicTask(context, myApplication);
            }
        }
    }

    private void doPeriodicTask(Context context, MyApplication myApplication) {
        // Periodic task(s) go here ...
    }

    public void restartPeriodicTaskHeartBeat(Context context, MyApplication myApplication) {
        SharedPreferences sharedPreferences = myApplication.getSharedPreferences();
        boolean isBatteryOk = sharedPreferences.getBoolean(Constants.BACKGROUND_SERVICE_BATTERY_CONTROL, true);
        Intent alarmIntent = new Intent(context, PeriodicTaskReceiver.class);
        boolean isAlarmUp = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntent.FLAG_NO_CREATE) != null;

        if (isBatteryOk && !isAlarmUp) {
            AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
            alarmIntent.setAction(INTENT_ACTION);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
            alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);
       }
    }

    public void stopPeriodicTaskHeartBeat(Context context) {
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent alarmIntent = new Intent(context, PeriodicTaskReceiver.class);
        alarmIntent.setAction(INTENT_ACTION);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
        alarmManager.cancel(pendingIntent);
    }
}

here com.example.app.PERIODIC_TASK_HEART_BEAT is application’s own broadcast, created and sent from our restartPeriodicTaskHeartBeat method.

your Alarmmanager should have this line

alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pendingIntent);

Now for your background service class:

public class BackgroundService extends Service {

    private static final String TAG = "BackgroundService";

    PeriodicTaskReceiver mPeriodicTaskReceiver = new PeriodicTaskReceiver();

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        MyApplication myApplication = (MyApplication) getApplicationContext();
        SharedPreferences sharedPreferences = myApplication.getSharedPreferences();
        IntentFilter batteryStatusIntentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent batteryStatusIntent = registerReceiver(null, batteryStatusIntentFilter);

        if (batteryStatusIntent != null) {
            int level = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
            int scale = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
            float batteryPercentage = level / (float) scale;
            float lowBatteryPercentageLevel = 0.14f;

            try {
                int lowBatteryLevel = Resources.getSystem().getInteger(Resources.getSystem().getIdentifier("config_lowBatteryWarningLevel", "integer", "android"));
                lowBatteryPercentageLevel = lowBatteryLevel / (float) scale;
            } catch (Resources.NotFoundException e) {
               Log.e(TAG, "Missing low battery threshold resource");
            }

            sharedPreferences.edit().putBoolean(Constants.BACKGROUND_SERVICE_BATTERY_CONTROL, batteryPercentage >= lowBatteryPercentageLevel).apply();
        } else {
            sharedPreferences.edit().putBoolean(Constants.BACKGROUND_SERVICE_BATTERY_CONTROL, true).apply();
        }

        mPeriodicTaskReceiver.restartPeriodicTaskHeartBeat(BackgroundService.this);
        return START_STICKY;
    }
     @Override
       public void onDestroy() {
          super.onDestroy();
          startSelf();
       }
}

Here the Backgroundservice tries to find the device’s low battery threshold and set our battery control flag appropriately before it attempts to restart the Broadcast receiver.

And START_STICKY will try to re-create your service after it is killed and call onStartCommand() again with a null intent.

Finally for your Application class start the Background service:

 public class MyApplication extends Application {
    private static final String TAG = "MyApplication";

    @Override
    public void onCreate() {
        super.onCreate();
        // Initialize the singletons so their instances
        // are bound to the application process.
         ...
         Intent startServiceIntent = new Intent(context, BackgroundService.class);
         startService(startServiceIntent);
    }
}

For detail implementation see this:https://technology.jana.com/2014/10/28/periodic-background-tasks-in-android/ enter image description here

be sure to make you service like this in your Mainifest

<service
        android:name=".service.youservice"
        android:exported="true"
        android:process=":ServiceProcess" />

then your service will run on other process named ServiceProcess

if you want make your service never die :

  1. onStartCommand() return START_STICKY

  2. onDestroy() -> call startself

if nothing works use startForeground() service..

Community
  • 1
  • 1
rafsanahmad007
  • 23,683
  • 6
  • 47
  • 62
  • thank you , i understand your code Except The code of background service , what does she do? – Ahmed Shaheen Dec 20 '16 at 18:25
  • i do every thing you said but still after i remove app from recent i didn't receive any thing from server – Ahmed Shaheen Dec 21 '16 at 10:22
  • @AhmedShaheen did u start your service like this: onCreate() of activity startService(new Intent(getBaseContext(), BackServices.class)); Also run service in another process...it works in my case – rafsanahmad007 Dec 21 '16 at 10:59
  • check the Updated BackgroundService,class – rafsanahmad007 Dec 21 '16 at 10:59
  • sorry can't log to internet till now ... there is some lines from code of broadcast receiver android studio can't understand , is it any library must be added .. android can't understand " Constants.BACKGROUND_SERVICE_BATTERY_CONTROL" .. – Ahmed Shaheen Dec 24 '16 at 08:59
  • just define a class public class Constants{ public static final String BACKGROUND_SERVICE_BATTERY_CONTROL= "battery";} – rafsanahmad007 Dec 24 '16 at 09:06
  • this class work , but android still can't understand this line "!Strings.isNullOrEmpty(intent.getAction())" .. 'Strings' didn't declared . – Ahmed Shaheen Dec 24 '16 at 09:40
  • also " myApplication.getSharedPreferences()" need string between its bracts ... after all thank you very much as you help me – Ahmed Shaheen Dec 24 '16 at 09:48
  • public static final String MyPREFERENCES = "MyPrefs"; in getSharedPreferences(MyPREFERENCES ) ... – rafsanahmad007 Dec 24 '16 at 09:54