前台服务在Oreo(Android 8.1.0)上不起作用

时间:2019-05-31 09:03:30

标签: android android-8.0-oreo foreground-service

我正在制作一个包含两项活动的应用程序,其中一项是主要活动。应用启动时,它将创建一个前台服务,该服务注册一个用于USER_PRESENT意图的广播侦听器。广播侦听器获得广播后,将触发第二个活动。我的代码面临两个问题: 1)前台服务通知未到。但是,该服务运行。 2)当我的应用程序是手机上的活动应用程序时,广播侦听器可以正常工作。但是,如果我的应用程序在后台运行,则广播侦听器将无法正常工作。但是该服务正在运行,因为日志中有消息指出该服务已被终止/停止。

如何解决这两个问题?

我正在具有Android 8.1.0的Oppo CPH1859手机上运行该应用程序

Android.manifest +++++++++++++

<uses-sdk android:minSdkVersion="26" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <service
        android:name=".MyFGService"
        android:enabled="true"
        android:exported="true"></service>

    <activity
        android:name=".DisplayMessageActivity"
        android:parentActivityName=".MainActivity">

        <!-- The meta-data tag is required if you support API level 15 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".MainActivity" />
    </activity>
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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

+++++

在主要活动中

@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 Log.v("FIRST APP","Main activity started");
 myService = new Intent(MainActivity.this, MyFGService.class);
 startService(myService);
}

@Override
public void onDestroy() {
    stopService(myService);
    Log.v("FIRST APP","Main activity destroyed");
    super.onDestroy();
}

++++++++++++

在MyFGService中

public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "service (re)starting", Toast.LENGTH_SHORT).show();
    Log.v("FIRST APP", "Service (re)starting");
    // If we get killed, after returning from here, restart
    return START_STICKY;
}

private String createNotificationChannel() {
    // Create the NotificationChannel, but only on API 26+ because
    // the NotificationChannel class is new and not in the support library
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        CharSequence name = "TEST Name";
        String description = "TEST Description";
        int importance = NotificationManager.IMPORTANCE_DEFAULT;
        NotificationChannel channel = new NotificationChannel( "FirstAppNotifChannel", name, importance);
        channel.setDescription(description);
        // Register the channel with the system; you can't change the importance
        // or other notification behaviors after this
        NotificationManager notificationManager = getSystemService(NotificationManager.class);
        notificationManager.createNotificationChannel(channel);
        return channel.getId();
    }
    return null;
}

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

    Log.v("FIRST APP", "Service created");

    Intent notificationIntent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent =
            PendingIntent.getActivity(this, 0, notificationIntent, 0);
    String notificationChannelID = createNotificationChannel();
    Log.v("FIRST APP","notification channel ID =" + notificationChannelID);
    Notification myNotification = new Notification.Builder(this, notificationChannelID)
                    .setContentTitle("TEST Title")
                    .setContentText("TEST Content")
                    .setContentIntent(pendingIntent)
                    .build();

    startForeground(101, myNotification);

    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_USER_PRESENT);
    registerReceiver(mReciever, filter);
}


@Override
public void onDestroy() {
    Toast.makeText(this, "service destroyed", Toast.LENGTH_SHORT).show();
    Log.v("FIRST APP", "Service destroyed");
    unregisterReceiver(mReciever);
}

1 个答案:

答案 0 :(得分:0)

您需要使用ContextCompat.startForgroundService()来启动FG服务。

@Override 
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

    Log.v("FIRST APP","Main activity started");
    myService = new Intent(MainActivity.this, MyFGService.class);
    ContextCompat.startForegroundService(myService); 
  }

但是,要考虑的一件事是 Oreo 设置了后台和广播限制,这解释了为什么您的应用程序在后台时没有接收广播。除了启动前台服务之外,您别无选择。 Background Execution Limits

此外,前台服务未显示的原因是您需要创建通知频道。创建一个名为“ BaseApp”的类,该类扩展了Application,因为在启动应用程序时该类仅需要运行一次。 Create and Manage Notification Channels

private void createNotificationChannel() {  //This function creates a channel, call this channel in `onCreate()` method of your n
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    CharSequence name = getString(R.string.channel_name);
    String description = getString(R.string.channel_description);
    int importance = NotificationManager.IMPORTANCE_DEFAULT;
    NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
    channel.setDescription(description);
    // Register the channel with the system; you can't change the importance
    // or other notification behaviors after this
    NotificationManager notificationManager = getSystemService(NotificationManager.class);
    notificationManager.createNotificationChannel(channel);
  }
}

在您的onCreate()类的BaseApp方法中调用此方法。希望在此之后,您的前台服务能够正常工作。另外,请记住,如果您的应用定位到 Android Pie ,那么您需要在 Manifest 文件中添加前台权限。

科林样品

class BaseApp : Application() {

companion object {
    const val CHANNEL_1_ID = "foreground_service_channel"

}


override fun onCreate() {
    super.onCreate()

    createNotificationChannels()
}

private fun createNotificationChannels() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

        val channel1 = NotificationChannel(CHANNEL_1_ID, "CHANNEL 1", NotificationManager.IMPORTANCE_HIGH)
        channel1.description = "This channel is used to show notes in notfication"

        val manager = getSystemService(NotificationManager::class.java)
        manager.createNotificationChannel(channel1)

     }
   }
}

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