Android 四大组件基础(Activity/Service/BroadcastReceiver/ContentProvider)工控场景用法
四大组件是安卓应用开发的地基。手机开发可能只用 Activity 就够了,但工控场景下四个组件各司其职,缺一不可。今天咱们把每个组件在工控中的角色和实战代码都捋清楚。
一、四大组件概述与工控中的角色
Android 应用由四种核心组件构成,它们各司其职:
| Activity | 提供用户界面的组件 | 数据监控大屏、参数配置页面 |
| Service | 后台运行的无界面组件 | 串口数据采集、Modbus 轮询、看门狗守护 |
| BroadcastReceiver | 接收系统或应用广播 | 开机自启、网络状态监听、外设热插拔检测 |
| ContentProvider | 跨应用数据共享 | 多 APP 共享传感器数据、设备配置信息 |
在工控场景中,四大组件的使用优先级和手机开发完全不同:手机开发 Activity 占 80%,而工控开发中 Service 才是核心——你写的 APP 很多时候根本不需要界面。
二、Activity:工控界面的承载者
2.1 工控 Activity 的特点
工控设备的 Activity 和手机 APP 的 Activity 有本质区别:
- 全屏无标题栏:工控 APP 不需要 ActionBar,不需要导航栏,不需要花里胡哨的动画
- 固定横屏/竖屏:设备是横装还是竖装焊死在机柜里,不允许旋转
- 无返回键依赖:用户可能根本没有返回键,所有导航必须在界面内完成
- 防退出:按返回键不能退出 APP,必须通过特定流程(长按、密码)退出
2.2 工控 Activity 配置模板
在 AndroidManifest.xml 中:
<activity
android:name=".MainActivity"
android:screenOrientation="landscape"
android:theme="@style/Theme.AppCompat.NoActionBar"
android:configChanges="screenSize|orientation|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
关键配置说明:
- screenOrientation="landscape":锁定横屏,设备转不了
- HOME category:把 APP 设为桌面,开机直接进你的应用
- configChanges:自己处理配置变化,不让系统重建 Activity
2.3 防退出处理
@Override
public void onBackPressed() {
// 工控 APP 禁用返回键退出
// 可以是空实现,也可以做特定逻辑
showExitConfirmDialog(); // 弹出自定义退出确认
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
hideSystemUI(); // 隐藏虚拟按键和状态栏
}
}
private void hideSystemUI() {
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
);
}
这段代码把你的 Activity 变成真正的"全屏无干扰"模式——下拉通知栏都拉不出来。
三、Service:工控 APP 的灵魂
3.1 为什么 Service 是核心?
工控设备的大部分工作跟界面无关——串口一直在收传感器数据,Modbus 协议每 100ms 轮询一次 PLC,CAN 总线上车辆数据不断涌来。这些操作必须脱离 Activity 的生命周期,否则用户一切换界面数据就断了。
3.2 前台 Service:不被系统杀死的后台任务
从 Android 8.0 开始,后台 Service 会被系统限制甚至杀死。工控 APP 必须用前台 Service,带一个常驻通知:
public class SerialService extends Service {
private static final int NOTIFICATION_ID = 1;
private static final String CHANNEL_ID = "serial_channel";
@Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
startForeground(NOTIFICATION_ID, buildNotification());
// 初始化串口,开始数据采集
initSerialPort();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 返回 START_STICKY:被系统杀死后自动重启
return START_STICKY;
}
private void createNotificationChannel() {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID, "串口服务", NotificationManager.IMPORTANCE_LOW);
channel.setDescription("工控串口数据采集服务");
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
private Notification buildNotification() {
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("数据采集运行中")
.setContentText("串口服务正在运行")
.setSmallIcon(R.drawable.ic_serial)
.setOngoing(true) // 用户无法滑动删除
.build();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
在 AndroidManifest.xml 中声明:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<service
android:name=".SerialService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="dataSync" />
3.3 Service 的启动方式
// 方式一:startService,Service 独立运行,不依赖调用者
Intent intent = new Intent(this, SerialService.class);
startService(intent);
// 方式二:bindService,调用者和 Service 绑定,可以互相通信
Intent intent = new Intent(this, SerialService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
工控场景大多用 startService,让 Service 独立于 Activity 运行。
3.4 工控 Service 典型用途
| 串口数据采集 | Service 中开线程循环读取 /dev/ttyS* |
| Modbus TCP 轮询 | Service 中定时任务读写 PLC 寄存器 |
| MQTT 连接保活 | Service 维持长连接,断线自动重连 |
| 看门狗喂狗 | Service 定时写 /dev/watchdog 或 GPIO |
| GPS/RTK 定位 | Service 持续解析 NMEA 数据 |
四、BroadcastReceiver:系统的耳朵
BroadcastReceiver 是 Android 的事件监听机制。工控场景中,它主要用于"感知环境变化"。
4.1 开机自启广播
这是工控 APP 最常用的广播——设备通电后自动拉起你的服务:
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
// 启动串口采集服务
Intent serviceIntent = new Intent(context, SerialService.class);
context.startService(serviceIntent);
// 启动主界面
Intent activityIntent = new Intent(context, MainActivity.class);
activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(activityIntent);
}
}
}
在 Manifest 中声明:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<receiver
android:name=".BootReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
4.2 其他工控常用广播
| BOOT_COMPLETED | 系统启动完成 | 自启 Service 和 Activity |
| CONNECTIVITY_CHANGE | 网络状态变化 | 网络断了告警、切换备用网络 |
| BATTERY_LOW | 电量过低 | UPS 供电告警 |
| TIME_TICK | 每分钟触发 | 定时任务(不精确但省电) |
| PACKAGE_ADDED | 新 APP 安装 | 安全检测、自动配置 |
4.3 动态注册 vs 静态注册
// 动态注册(代码中注册,更灵活)
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkReceiver, filter);
// 记得在 onDestroy 中反注册
unregisterReceiver(networkReceiver);
工控设备一般用静态注册(在 Manifest 中声明),因为动态注册依赖组件生命周期,设备重启后不一定还在。
五、ContentProvider:工控多 APP 数据共享
ContentProvider 在日常手机开发中很少用——除了读系统通讯录。但在工控场景中,它是一个被低估的家伙。
5.1 工控场景的典型需求
假设你的工控设备上跑了三个 APP:
- 数据采集 APP:负责读写串口、采集传感器数据
- 本地监控 APP:负责显示实时数据和报警
- 远程上报 APP:负责把数据上传到云平台
这三个 APP 需要共享数据(传感器数值、设备状态、报警记录)。用文件互传?太原始。用 SQLite 数据库互相访问?Android 11+ 已经锁死了 /data/data/ 的跨应用访问。这时候 ContentProvider 就是正道。
5.2 实现一个简单的数据共享 ContentProvider
数据采集 APP 作为数据提供方:
public class SensorProvider extends ContentProvider {
public static final String AUTHORITY = "com.example.collector.provider";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/sensors");
@Override
public boolean onCreate() {
// 初始化数据库
dbHelper = new SensorDbHelper(getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
return db.query("sensor_data", projection, selection,
selectionArgs, null, null, sortOrder);
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
long id = db.insert("sensor_data", null, values);
getContext().getContentResolver().notifyChange(uri, null);
return ContentUris.withAppendedId(uri, id);
}
@Override
public String getType(Uri uri) {
return "vnd.android.cursor.dir/vnd.example.sensors";
}
// 工控场景一般不提供删除和更新接口
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
return 0;
}
}
监控 APP 作为数据消费方:
// 查询最新的传感器数据
Cursor cursor = getContentResolver().query(
Uri.parse("content://com.example.collector.provider/sensors"),
new String[]{"sensor_name", "value", "timestamp"},
null, null,
"timestamp DESC LIMIT 10"
);
while (cursor.moveToNext()) {
String name = cursor.getString(0);
float value = cursor.getFloat(1);
Log.d("Monitor", name + " = " + value);
}
cursor.close();
5.3 ContentProvider 在工控中的价值
| 安全可控 | 可以精确控制哪些 APP 能访问、能做什么操作 |
| 解耦架构 | 数据采集和数据展示分离,单 APP 崩溃不影响数据 |
| 内容观察者 | ContentObserver 实现数据变化实时通知 |
| 系统级支持 | Android 框架原生支持,不依赖第三方库 |
六、四大组件工控用途总结
| Activity | 数据监控大屏、参数配置 | 产线看板、设备参数设置页 | 中(无屏设备可不要) |
| Service | 后台常驻任务执行 | 串口采集、Modbus 轮询、看门狗 | 极高 |
| BroadcastReceiver | 系统事件感知 | 开机自启、网络断连告警 | 高 |
| ContentProvider | 多 APP 数据共享 | 采集/监控/上报三 APP 数据互通 | 中(单 APP 可不用) |
七、总结
四大组件在工控开发中的分量和手机开发完全不同。手机开发以 Activity 为中心,重在交互和体验;工控开发以 Service 为中心,重在稳定和自动化。
记住几个原则:
把这些组件吃透,你在工控安卓开发这条路上就算正式入门了。
网硕互联帮助中心





评论前必须登录!
注册