简体   繁体   中英

Background service not starting android

I'm trying to use a background service so that I can check for new content on the app every 30 minutes and notify the user with a notification if there is any new content. The problem is that that service does not seem that it is starting at all. I'm not entirely sure what I have wrong.

I've followed this article to implement a notification service and this question as well - Trying to start a service on boot on Android .

AndroidManifest.xml

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

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

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

    <receiver android:name="com.____.BootReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
    <service android:name="com.____.NotificationService"/>
</application>

The BootReceiver should start the Service

public class BootReceiver extends BroadcastReceiver {

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

The service NotificationService right now is set to display a simple notification

public class NotificationService extends Service {

    private WakeLock mWakeLock;

    /**
     * Simply return null, since our Service will not be communicating with
     * any other components. It just does its work silently.
     */
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * This is where we initialize. We call this when onStart/onStartCommand is
     * called by the system. We won't do anything with the intent here, and you
     * probably won't, either.
     */
    private void handleIntent(Intent intent) {
        // obtain the wake lock
        PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My App");
        mWakeLock.acquire();

        // check the global background data setting
        ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
        if (cm.getActiveNetworkInfo() == null) {
            stopSelf();
            return;
        }

        // do the actual work, in a separate thread
        new PollTask().execute();
    }

    private class PollTask extends AsyncTask<Void, Void, Void> {
        /**
         * This is where YOU do YOUR work. There's nothing for me to write here
         * you have to fill this in. Make your HTTP request(s) or whatever it is
         * you have to do to get your updates in here, because this is run in a
         * separate thread
         */
        @SuppressLint("NewApi") @Override
        protected Void doInBackground(Void... params) {
            // do stuff!

            // get last added date time of offer
            // every 60 minutes check for new offers

            Notification notification = new Notification.Builder(getApplicationContext())
                .setContentText("New Content Available")
                .setSmallIcon(R.drawable.ic_launcher)
                .setWhen(0)
                .build();

            return null;
        }

        /**
         * In here you should interpret whatever you fetched in doInBackground
         * and push any notifications you need to the status bar, using the
         * NotificationManager. I will not cover this here, go check the docs on
         * NotificationManager.
         *
         * What you HAVE to do is call stopSelf() after you've pushed your
         * notification(s). This will:
         * 1) Kill the service so it doesn't waste precious resources
         * 2) Call onDestroy() which will release the wake lock, so the device
         *    can go to sleep again and save precious battery.
         */
        @Override
        protected void onPostExecute(Void result) {
            // handle your data
            stopSelf();
        }
    }

    /**
     * This is deprecated, but you have to implement it if you're planning on
     * supporting devices with an API level lower than 5 (Android 2.0).
     */
    @Override
    public void onStart(Intent intent, int startId) {
        handleIntent(intent);
    }

    /**
     * This is called on 2.0+ (API level 5 or higher). Returning
     * START_NOT_STICKY tells the system to not restart the service if it is
     * killed because of poor resource (memory/cpu) conditions.
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        handleIntent(intent);
        return START_NOT_STICKY;
    }

    /**
     * In onDestroy() we release our wake lock. This ensures that whenever the
     * Service stops (killed for resources, stopSelf() called, etc.), the wake
     * lock will be released.
     */
    public void onDestroy() {
        super.onDestroy();
        mWakeLock.release();
    }
}

Debugging the app with breakpoints in both BootRecevier and NotificationService are never triggered. Maybe I'm misunderstanding the way Background Services work.

UPDATE

I found this article about why the BroadcastRecevier is not being called. One of the mentioned points is PendingIntent requestCode missing

I've updated the BootRecevier as follows to test out the service...called every 1 minute:

@Override
public void onReceive(Context context, Intent intent) {
    int minutes = 1;
    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    Intent i = new Intent(context, NotificationService.class);
    PendingIntent pi = PendingIntent.getService(context, 54321, i, 0);
    am.cancel(pi);

    if (minutes > 0) {
        am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
            SystemClock.elapsedRealtime() + minutes*60*1000,
            minutes*60*1000, pi);
    }
}

Changing 0 to a 'unique' requestCode 54321 somehow started triggering the service. The issue is that the service does not carry on working when the app is closed...not sure if that's a completely different thing altogether.

UPDATE 2

I've updated the doInBackground method in the NotificationService , using this example to display notifications:

@SuppressLint("NewApi") @Override
protected Void doInBackground(Void... params) {

    Context mContext = getApplicationContext();

    // invoke default notification service
    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext);

    mBuilder.setContentTitle("[Notification Title]");
    mBuilder.setContentText("[Notification Text]");
    mBuilder.setTicker(mContext.getString(R.string.app_name));
    mBuilder.setSmallIcon(R.drawable.ic_launcher);

    Intent resultIntent = new Intent(mContext, MainActivity.class);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext);
    stackBuilder.addParentStack(MainActivity.class);

    stackBuilder.addNextIntent(resultIntent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_ONE_SHOT);

    mBuilder.setContentIntent(resultPendingIntent);

    NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(1, mBuilder.build());

    return null;
}

I've tested it on an emulator and the Background Service works even when the app is closed. However, testing the app on an actual device did not display any notifications.

You need to declare the permission to receive the intent in your manifest.

AndroidManifest.xml

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

http://developer.android.com/reference/android/Manifest.permission.html#RECEIVE_BOOT_COMPLETED

You will only receive notifications of the device booting after the user has started your application at least once.

I happened to have the same issue recently, and I am using a 5.1.1 android smartphone. The way I solved this issue was using the ic_launcher in mipmap to replace the ic_launcher in drawable when called setSmallIcon().

However, for the exact reason, I guess it has something to do with the difference between mipmap and drawable.

Ref: mipmap vs drawable folders

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM