后台服务没有启动android

时间:2014-10-07 21:08:32

标签: android notifications background-service

我正在尝试使用后台服务,以便每30分钟检查一次应用程序上的新内容,并在有任何新内容时通知用户。问题是该服务似乎根本不是它的起点。我不完全确定我的错误。

我已按照此article来实施通知服务以及此问题 - 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>

BootReceiver 应启动服务

public class BootReceiver extends BroadcastReceiver {

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

现在,服务 NotificationService 设置为显示简单通知

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();
    }
}

永远不会触发在 BootRecevier NotificationService 中使用断点调试应用。也许我误解了后台服务的工作方式。

更新

我发现这个article关于为什么没有调用BroadcastRecevier。其中一个要点是 PendingIntent requestCode missing

我已按如下方式更新了BootRecevier以测试服务...每1分钟调用一次:

@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);
    }
}

将0更改为'unique'requestCode 54321以某种方式开始触发服务。问题是,当应用程序关闭时,该服务不会继续工作......不确定这是完全不同的事情。

更新2

我已更新 NotificationService 中的doInBackground方法,使用此example显示通知:

@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;
}

我在模拟器上测试了它,即使应用程序关闭,后台服务也能正常运行。但是,在实际设备上测试应用程序时不会显示任何通知。

2 个答案:

答案 0 :(得分:0)

您需要声明在清单中接收意图的权限。

的AndroidManifest.xml

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

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

在用户至少启动一次应用程序后,您才会收到设备启动的通知。

答案 1 :(得分:-1)

我最近遇到了同样的问题,我使用的是5.1.1安卓智能手机。我解决此问题的方法是在调用setSmallIcon()时使用ic_launcher in mipmap替换ic_launcher in drawable

然而,由于确切的原因,我猜它与mipmap和drawable之间的区别有关。

参考:mipmap vs drawable folders