Android手把手编写儿童手机远程监控App之前台服务

0 阅读4分钟

上节完成Activity内容。主要内容是Activity三种常用传参方式,分别是

  • 传递基本数据类型
  • 传递Bundle对象(适合传递大量数据)
  • 通过Serializable传递对象数据 服务(Service)是Android实现后台程序运行的解决方案,非常适合去执行不需要与用户交互而且要求长期运行的任务。程序的运行不依赖任何用户界面,即使程序被切换到后台,或者用户打开另一程序,服务仍然能够正常运行。服务分为两种
  • 后台服务,执行用户不会直接注意到的操作,如数据处理,日志清理等,资源不足可能会被系统终止
  • 前台服务,执行用户能注意到的操作,必须显示一个Notification,优先级高,系统不容易主动终止它 在这里插入图片描述

由于嘟宝使用MQTT一直保持后台连接在线,属后台静默程序。现今Android对于功耗设计,在锁屏之后,后台程序占用资源过多,会被暂停,这就要求嘟宝后台程序驻留线程对资源的暂用极低,且必须使用前台服务,持续激活状态。 在这里插入图片描述

创建后台服务

后台服务是应用程序在不直接与用户交互时执行的操作,它也是创建前台服务一部分。嘟宝工程目前含有MainActivity、HelloWorldActivity两个页面,Fish类,只保留MainActivity页面。

  • 删除其他不需要内容,创建后台服务
  • 重载onCreate、onStartCommand、onDestroy函数

创建MyService

右键app目录>new > Service>Service 在这里插入图片描述 在这里插入图片描述 点击Finish完成后台服务创建,其中,

  • 自定义类名:MyService类型
  • Exported服务是否被外界调用
  • Enbled服务是否打开
  • Srouce Language 开发语言
  • Target Source Set 创建后台服务代码存放位置,服务的用途归谁,如下图: 在这里插入图片描述 通过IDE创建后台服务,生成两部分内容
  • 一是创建类名MyService
  • 二是在AndroidManifest中声明后台服务 MyService源码
package com.zilong.dubao;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class MyService extends Service {
    public MyService() {
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

AndroidManifest文件代码

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.zilong.dubao">
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@drawable/fav"
        android:label="@string/app_name"
        android:roundIcon="@drawable/favround"
        android:supportsRtl="true"
        android:theme="@style/Theme.DuBao"
        tools:targetApi="31">
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"></service>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

重载onCreate、onStartCommand、onDestroy函数

  • 在MainActivity类中添加两个按钮
  • 介绍Toast用法
  • 在MyService类中,重载onCreate、onStartCommand、onDestroy Toast 是 Android 中一个非常常用的系统组件,用于在屏幕上以浮窗的形式显示简短的通知信息。它不会获取焦点,显示一小段时间后会自动消失,不会影响用户对当前应用的操作。 如下代码,单击按钮创建Toast 显示一小段文字
 Button startbtn=findViewById(R.id.startbtn);
        startbtn.setOnClickListener(v->{
            Toast.makeText(this,"hello,我是Toast",Toast.LENGTH_SHORT).show();
        });

效果如下: 在这里插入图片描述

  • onCreate首次创建后台服务时调用,且只被调用一次
  • onStartCommand多次创建后台服务,每次服务被创建都被调用
  • onDestroy后台服务被销毁时,调用 MainActivity代码
package com.zilong.dubao;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startbtn=findViewById(R.id.startbtn);
        startbtn.setOnClickListener(v->{
            Intent intent = new Intent(this, MyService.class);
            startService(intent);
        });
        Button stopbtn=findViewById(R.id.stopbtn);
        stopbtn.setOnClickListener(v->{
            Intent intent = new Intent(this, MyService.class);
            stopService(intent);
        });
    }

}

MyService代码

package com.zilong.dubao;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;

public class MyService extends Service {
    public MyService() {
    }


    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this,"后台服务onCreate",Toast.LENGTH_SHORT).show();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this,"后台服务onStartCommand",Toast.LENGTH_SHORT).show();
        return super.onStartCommand(intent, flags, startId);

    }

    @Override
    public void onDestroy() {

        Toast.makeText(this,"后台服务onDestroy",Toast.LENGTH_SHORT).show();

        super.onDestroy();
    }

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

运行效果如下: 在这里插入图片描述

创建前台服务

  • 根据创建后台服务的方法创建服务MyService
  • 在AndroidManifest添加权限前台服务权限
  • 在MyService启动后创建前台图标
  • 在MainActivity启动服务 MainActivity代码
package com.zilong.dubao;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startbtn=findViewById(R.id.startbtn);
        startbtn.setOnClickListener(v->{
            Intent intent = new Intent(this, MyService.class);
            startForegroundService(intent);

        });
        Button stopbtn=findViewById(R.id.stopbtn);
        stopbtn.setOnClickListener(v->{
            Intent intent = new Intent(this, MyService.class);
            stopService(intent);
        });
    }

}

MyService代码

package com.zilong.dubao;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.widget.Toast;

import androidx.core.app.NotificationCompat;

public class MyService extends Service {
    public MyService() {
    }


    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this,"后台服务onCreate",Toast.LENGTH_SHORT).show();
        createNotificationChannel();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this,"后台服务onStartCommand",Toast.LENGTH_SHORT).show();
        startForeground(10001, createNotification());
        return super.onStartCommand(intent, flags, startId);

    }

    @Override
    public void onDestroy() {

        Toast.makeText(this,"后台服务onDestroy",Toast.LENGTH_SHORT).show();

        super.onDestroy();
    }

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


    private void createNotificationChannel() {
        // Android 8.0+ 需要创建通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    "DUBAO",
                    "嘟宝安心守护孩子安全",
                    NotificationManager.IMPORTANCE_LOW
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }
    private Notification createNotification() {
        // 点击通知返回应用
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(
                this, 0, intent,
                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
        );

        return new NotificationCompat.Builder(this, "DUBAO")
                .setContentTitle("嘟宝")
                .setContentText("嘟宝安心守护孩子安全...")
                .setSmallIcon(android.R.drawable.ic_menu_info_details)
                .setContentIntent(pendingIntent)
                .setOngoing(true)  // 不可滑动删除
                .build();
    }
}

AndroidManifest代码

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.zilong.dubao">
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@drawable/fav"
        android:label="@string/app_name"
        android:roundIcon="@drawable/favround"
        android:supportsRtl="true"
        android:theme="@style/Theme.DuBao"
        tools:targetApi="31">
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true"></service>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

运行效果如下: 在这里插入图片描述 至此前台服务启动完成