sendBroadcast()是在Android中保持WakefulBroadcastReceiver活着的最佳方法吗?

时间:2017-10-02 15:00:24

标签: java android

我尝试在Android应用程序中执行一些后台计算任务。

我的主要课程:

public class CalculationService extends IntentService {

    public CalculationService() {
        super("Calculation Service");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        int nb1 = intent.getIntExtra(NUMBER_1,0);
        int nb2 = intent.getIntExtra(NUMBER_2,0);
        doAddition(nb1,nb2);
        CalculationReceiver.completeWakefulIntent(intent);
    }

    public void doAddition(int number1, int number2){
        int result = number1+number2;
        System.out.println("Result : " + result);
    }
}

我的服务:

public class CalculationReceiver extends WakefulBroadcastReceiver {

    public static final String NUMBER_1 = "NUMBER_1";
    public static final String NUMBER_2 = "NUMBER_2";

    @Override
    public void onReceive(Context context, Intent intent) {
        Intent service = new Intent(context, CalculationService.class);

        int receiverNumber1 = intent.getIntExtra(NUMBER_1,0);
        int receiverNumber2 = intent.getIntExtra(NUMBER_2,0);

        service.putExtra(NUMBER_1,receiverNumber1);
        service.putExtra(NUMBER_2,receiverNumber2);

        startWakefulService(context, service);
    }

    public void doAddition (Context context, int number1, int number2){
        Intent intent = new Intent(context, CalculationReceiver.class);

        intent.putExtra(NUMBER_1,number1);
        intent.putExtra(NUMBER_2,number2);

        context.sendBroadcast(intent);
    }
}

我的接收者:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testservices">
    <uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
    <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">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".ReductionService"
            android:enabled="true" />
        <receiver android:name=".ReductionReceiver"/>

        <service android:name=".CalculationService"
            android:enabled="true" />
        <receiver android:name=".CalculationReceiver"/>
    </application>
</manifest>

我的宣言:

context.sendBroadcast (intent);

应用程序的计算比这些添加更复杂,可能需要几分钟(平均15分钟)才能完成。

根据Google文档(https://developer.android.com/training/scheduling/wakelock.html),我决定实施此架构,以确保计算结束。

这个想法是用户开始计算,然后等待应用程序给出结果。与此同时,他可以启动其他应用程序或锁定他的手机,计算一定不能停止。

这种方法似乎有效。

让我困扰的是接收者对服务的要求:

{{1}}

是否有更多&#34;清洁&#34;启动服务的方式?

让我印象深刻的是它看起来并不是很干净#34;特别是相同参数(number1和number2)的几次通过

由于

2 个答案:

答案 0 :(得分:1)

  

根据Google文档(https://developer.android.com/training/scheduling/wakelock.html),我决定实施此架构,以确保计算结束。

这不是文档使用WakefulBroadcastReceiver显示的方式。另外,WakefulBroadcastReceiver在支持库的版本26.0.0中已弃用。

  

这个想法是用户开始计算,然后等待应用程序给出结果。

我对此的解释是,用户通过您的活动的UI请求开始计算。这意味着此时屏幕已打开,您在前台有活动。

  

是否有更“干净”的方式来启动服务?

致电startService()

步骤1:删除您对已弃用的WakefulBroadcastReceiver

的使用

步骤2:让您的活动致电startService()以启动服务

第3步:让您的服务通过WakeLock系统服务获取部分PowerManager,服务的onCreate()方法

第4步:在服务的WakeLock方法中发布onDestroy()服务

步骤#5:将服务修改为前台服务,使用合适的startForeground()onCreate()中调用Notification,以允许用户控制服务的行为

请注意:

  • 如果您跳过步骤#5,您的服务将在Android 8.0 +上大约1分钟后停止运行。

  • 如果设备进入打盹模式,这仍然无法在Android 6.0+上运行。这不应该发生大约1个小时,但你需要确保你的计算在那时完成。

  • 考虑将计算工作卸载到服务器,而不是长时间烧毁用户的CPU(通过计算工作加上唤醒锁)

答案 1 :(得分:1)

按照这种方式,我按照@CommonsWare

的建议解决了这个问题

主要活动:

public class MainActivity extends AppCompatActivity {

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

        Button button = (Button) findViewById(R.id.button);

        final Context mContext = this;

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Intent service = new Intent(mContext, CalculationService.class);

                service.putExtra(NUMBER_1,2);
                service.putExtra(NUMBER_2,2);

                startService(service);
            }
        });
    }
}

计算服务:

public class CalculationService extends IntentService {

    public static final String NUMBER_1 = "NUMBER_1";
    public static final String NUMBER_2 = "NUMBER_2";

    private static final int FOREGROUND_ID = 42;

    PowerManager.WakeLock wakeLock;

    public CalculationService() {
        super("Calculation Service");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        int nb1 = intent.getIntExtra(NUMBER_1,0);
        int nb2 = intent.getIntExtra(NUMBER_2,0);
        doAddition(nb1,nb2);
    }

    public void doAddition(int number1, int number2){
        int result = number1+number2;
        System.out.println("Result : " + result);
    }

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

        PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                "CalculationServiceWakelockTag");
        wakeLock.acquire();

        Intent notificationIntent = new Intent(this, MainActivity.class);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, 0);

        Notification notification = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Calculation App")
                .setContentText("Calculation in progress")
                .setContentIntent(pendingIntent).build();

        startForeground(FOREGROUND_ID, notification);
    }

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

        wakeLock.release();
    }
}

这很有效:)

但我可以打电话吗

startForegroundService(service)

而不是

startService(service);
是不是?为什么?