1

我的目标是奥利奥。如您所知,奥利奥引入了对后台任务执行时间的限制。根据谷歌的说法,解决方法是将后台任务放在前台。这就是我想要做的,但是一旦前台服务运行,它会在一段时间后被销毁。首先手机会关闭它的屏幕,然后一旦我再次激活它,后台任务就会继续。有时会在未完成任务的情况下调用前台服务上的 onDestroy。

我的目标是让 enqueueWork 设置的所有任务都可以在没有调用 ondestroy 并且没有电话睡眠模式来中断它的情况下执行。

前台服务

public class ForeGroundService extends JobIntentService {

    static final int JOB_ID = 1000;
    static final int ONGOING_NOTIFICATION_ID = 33;

    static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, ForeGroundService.class, JOB_ID, work);
    }

    Notification.Builder notification;
    NotificationManager mNotificationManager;

    @RequiresApi(api = Build.VERSION_CODES.O)
    void einleitung(String Titel, String Text)
    {
        Intent notificationIntent = new Intent(this, ForeGroundService.class);
        PendingIntent pendingIntent =
                PendingIntent.getActivity(this, 0, notificationIntent, 0);


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

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(Titel,
                    Text,
                    NotificationManager.IMPORTANCE_HIGH);
            channel.setSound(null,null);
            mNotificationManager.createNotificationChannel(channel);
        }
        notification =
                new Notification.Builder(this,Titel)
                        .setContentTitle(Titel)
                        .setContentText(Text)
                        .setSmallIcon(R.drawable.kleinesicon)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                        .setContentIntent(pendingIntent)
                        .setTicker("setTicker");
        mNotificationManager.notify(ONGOING_NOTIFICATION_ID, notification.build());
        startForeground(ONGOING_NOTIFICATION_ID, notification.build());
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    void vordergrund(String Titel, String Text)
    {
        notification.setContentTitle(Titel);
        notification.setContentText(Text);
        mNotificationManager.notify(ONGOING_NOTIFICATION_ID, notification.build());
    }
    PowerManager.WakeLock wakeLock;
    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    protected void onHandleWork(Intent intent) {
        if (beginn) {
            einleitung("Test", "Test");
            beginn = false;
        }
        PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                "MyWakelockTag");
        wakeLock.acquire();
        //Do Work

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Intent local = new Intent();
        local.setAction("de.test.action");
        this.sendBroadcast(local);
        stopForeground(true);
        //toast("Fertig");
        if (wakeLock != null)
            wakeLock.release();
    }

    final Handler mHandler = new Handler();
}

主要活动

public class MainActivity extends AppCompatActivity {
    private int JI = 1000;
    private BroadcastReceiver updateUIReciver;

    @RequiresApi(api = Build.VERSION_CODES.O)
    void somefunction(someparameters)
    {
        Intent mServiceIntent = new Intent();
        mServiceIntent.putExtra...
        ForeGroundService.enqueueWork(getBaseContext(),ForeGroundService.class,JI,mServiceIntent);
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(updateUIReciver);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setTheme(R.style.AppTheme);
        super.onCreate(savedInstanceState);
        IntentFilter filter = new IntentFilter();
        filter.addAction("de.test.action");
        updateUIReciver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                ForeGroundService.shouldContinue = false;
            }
        };
        registerReceiver(updateUIReciver,filter);


        btnB.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            public void onClick(View v) {
                if (startcondition)
                {

                    Intent startIntent = new Intent(MainActivity.this, MyService.class);
                    startIntent.setAction(Constants.ACTION.START_ACTION);
                    startService(startIntent);


                    Intent serviceIntent = new Intent(MainActivity.this,ForeGroundService.class);
                    startForegroundService(serviceIntent);

                    somefunction(someparameters);
                }
                else
                {
                    Intent stopIntent = new Intent(MainActivity.this, MyService.class);
                    stopIntent.setAction(Constants.ACTION.STOP_ACTION);
                    startService(stopIntent);
                }
            }
        });
    }
}

编辑:我使它与sandhya sasane的解决方案一起使用

public int onStartCommand(Intent intent, int flags, int startId)
{
    if (beginn) {
        executorService = Executors.newFixedThreadPool(1);
        beginn = false;
    }
    final Intent i2 = intent;
    executorService.execute(new Runnable(){
        @Override
        public void run(){
            abarbeiten(i2);
        }
    });
    return START_STICKY;
}

重要的是 newFixedThreadPool(1) 中的 1;一次只运行一个线程

4

1 回答 1

2

我的目标是奥利奥。如您所知,奥利奥引入了对后台任务执行时间的限制。

是的,它确实。我能理解你,因为谷歌首先让事情变得非常奇怪和复杂......然后又变得复杂......然后再次......然后再次......现在像我和你这样的开发人员,以及你的问题和问题,表示结果/结果/证明。

解决方法是 - 根据谷歌...

请节省时间和你自己......谷歌文档最糟糕......我给他们的文档打了-10分(满分10分)。

将后台任务放在前台。

您对什么是前景概念有错误的认识..!! 仔细逐字阅读完整答案,您的问题将得到解决..!

这就是我试图做的,但是一旦前台服务运行,它会在一段时间后被销毁......

现在非常简单...您的概念和实现都是错误的...,因此尝试使用此处提供的新示例项目和指南以及从 4.0 到最新 android P 的示例工作和测试代码。

首先手机会关闭它的屏幕,然后一旦我再次激活它,后台任务就会继续。有时会在未完成任务的情况下调用前台服务上的 onDestroy。

无论如何,它与前台服务无关....忘记这一点。

我的目标是让 enqueueWork 设置的所有任务都可以在没有调用 ondestroy 并且没有电话睡眠模式来中断它的情况下执行。

也忘了这个吧……让我们先看看前台服务是什么以及它是如何创建的……


什么是前台服务

  • 保持活动状态的服务(这并不意味着......像永无止境的 do-while 循环一样持续运行)
  • 在下次启动/重新启动之前保持活动状态
  • 即使用户从最近删除应用程序,它仍然存在
  • 但它不会在下次启动后保持活动状态
  • 用户需要通过再次打开应用程序或通过 ON_BOOT_COMPLETE 的广播接收器或通过 AlarmManager 或通过 JobScedular 重新启动它

何时使用

根据我的观点,用户不喜欢显示消息的永久通知^这是在前台运行,可能很快会耗尽您的电池^,再次用户将无法将其滑开,只能强制停止或卸载应用程序来停止它。因此,根据我的实现观点,^开发人员必须使用它来实现运行时接收器,因为 post-oreo 设备不欢迎通过扩展Broadcastreceiver并将其意图条目放置在 manifest.xml 文件中实现的静态接收器......即使开发人员尝试要做到这一点,接收器将永远不会在后奥利奥设备上被调用......,是的,它将在奥利奥设备下被调用。所以只实现一个 ON_BOOT_COMPLETE 接收器,然后将所有内容都放在一个服务中。

如何实现前台服务

右键单击项目结构并创建一个名为 RunnerService 的服务,然后生成所有必需的方法。它不需要您手动输入所有代码.. 如上所述生成它。前台服务示例:

public class RunnerService extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "1";


public RunnerService() { }

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

    Log.d("RUNNER : ", "PROGRAMMED.... \n");

    Bitmap IconLg = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_foreground);

    mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
    mBuilder = new NotificationCompat.Builder(this, null);
    mBuilder.setContentTitle("App Name")
            .setContentText("Foreground service...")
            .setTicker("Foreground service...")
            .setSmallIcon(R.drawable.ic_menu_slideshow)
            .setLargeIcon(IconLg)
            .setPriority(Notification.PRIORITY_HIGH)
            .setVibrate(new long[] {100})
            .setVisibility(Notification.VISIBILITY_PUBLIC)
            .setOngoing(true)
            .setAutoCancel(false);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
        notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);

        // Configure the notification channel.
        notificationChannel.setDescription("Channel description");
        notificationChannel.enableLights(true);
        notificationChannel.setLightColor(Color.RED);
        notificationChannel.setVibrationPattern(new long[]{100});
        notificationChannel.enableVibration(true);
        notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
        mNotifyManager.createNotificationChannel(notificationChannel);

        mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
        startForeground(1, mBuilder.build());
    }
    else
    {
        mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
        mNotifyManager.notify(1, mBuilder.build());
    }



}

@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
    Log.d("RUNNER : ", "\n IT IS ACTIVE UNTIL NEXT BOOT....");
    return START_STICKY;
}

@Override
public void onDestroy()
{
    Log.d("RUNNER : ", "\n IT WILL BE AGAIN ACTIVE BY ANDROID OS AUTOMATICALLY, DO NOT WORRY AND DONT CODE TO START IT AGAIN !!....");
    super.onDestroy();
}


@Override
public IBinder onBind(Intent intent)
{
    // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("NOT_YET_IMPLEMENTED_BY_DEVELOPER");
}
}

如何开始

这取决于您在 oreo 下方或 post oreo 下定位的 android ......我更喜欢下面的所有内容:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
    this.startForegroundService(new Intent(this, RunnerService.class));
}
else
{
    this.startService(new Intent(this, RunnerService.class));
}

无论是从 MainActivity 或任何 ON_BOOT_RECEIVER,还是从您想要的任何地方,只需按照此处所述启动它...

如何测试在前台

通过从最近删除它...它将调用 onDestroy 但它永远不会被销毁,您将无法刷掉通知。这意味着成功。

如何快速测试

使用带有 MainActivity 的示例新项目,只需以上述方式调用服务。

接下来是什么..?

是的,你只能在这里问你接下来的任务......,我会不断更新和指导......我希望你把enqueueWork概念和你所有的概念放在一边,不要去想它......

让我们一步一步来,让我知道更新......

更新 2

您应该仅在模拟器上尝试...如果成功,请在实际设备上尝试...这里又是一个问题...

现在世界上有很多手机厂商,都是从谷歌那里拿来存货的安卓,因为它是开源的,并且修改它以禁用BOOT上的所有服务。它只保留谷歌、WhatsApp、FaceBook、Twitter 和主要市场领导者......好像他们不允许他们没有人会购买他们的设备......

例子 :

  1. Vivo = FunTouchOs
  2. Oppo = ColorOs
  3. 有一个巨大的清单......

不要检查这个 BOOT_COMPLETE ......,它不会工作,因为它们被修改了 android..

但我想在实际设备上测试它

然后在操作系统完全来自谷歌并拥有安卓操作系统的设备上对其进行测试。

那么对于从android修改的其他操作系统我该怎么办

有技巧......,但让我们一步一步来......我会让你知道,一旦你成功......!

更新:3

由于尚不清楚我做出一些假设并写下答案的要求是什么:

实现前台执行可以做的是:

  1. 按照我的描述实现前台服务
  2. 使用本地broadcastmanager广播您自己的事件。
  3. onCreate前台服务注册运行时接收器以接收该广播
  4. 在接收广播时调用context前台服务的用户定义类的方法。并从那里执行所有任务。
  5. 从前台服务的 onDestroy 注销接收器。

实现后台执行可以做的是:

如果您有重复的任务并且想要执行它,background即使应用程序已从最近删除... 那么:

  1. 使用使用 GooglePLAYServices 的 Firebase Job Dispatcher
  2. 如果您使用forever,那么即使系统重新启动,即使应用程序不在前台或后台或最近,该作业也会自动触发......

到目前为止,我认为没有任何需要,JobIntentService因此不需要它的静态enqueueWork方法;解决您的问题需要更多的解决方案和详细信息。

于 2018-08-18T09:37:58.583 回答