【问题标题】:Background service not starting android后台服务未启动android
【发布时间】:2014-10-07 21:08:32
【问题描述】:

我正在尝试使用后台服务,以便我可以每 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 缺失

我已按如下方式更新了 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 更改为“唯一”requestCode54321 以某种方式开始触发服务。问题是当应用程序关闭时服务无法继续工作......不确定这是否完全不同。

更新 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;
}

我已经在模拟器上对其进行了测试,即使应用程序关闭,后台服务也能正常工作。但是,在实际设备上测试该应用并没有显示任何通知。

【问题讨论】:

  • 您可以尝试手动启动服务,如果您希望它立即启动它。 (当操作系统杀死它时,我有一个粘性消息服务,需要一些时间才能重新启动,但如果我需要立即启动,我会运行此代码) context.startService(new Intent(context, YourService.class));

标签: android notifications background-service


【解决方案1】:

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

AndroidManifest.xml

&lt;uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /&gt;

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

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

【讨论】:

  • 是的,已经存在...我会更新我的问题以防万一
  • 你必须在&lt;application标签的inside声明服务。如果您不提供完整的代码,很难猜出您的问题:-)
【解决方案2】:

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

但是,确切的原因,我想这与 mipmap 和 drawable 之间的区别有关。

参考:mipmap vs drawable folders

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多