NFC开发系列 - 第二篇:NFC企业级架构设计与最佳实践
在掌握了NFC开发的基础知识和实战技能后,本篇将带你深入企业级NFC应用的架构设计,学习如何构建一个健壮、可维护、可扩展的NFC系统。
架构设计核心要点
- 三层架构:UI层、业务逻辑层、数据访问层分离
- 协议兼容:工厂模式 + 策略模式支持多协议
- 应用保活:前台服务 + JobScheduler双重保活
- 异常处理:统一异常处理器,友好的错误提示
- 设计原则:单一职责、依赖倒置、开闭原则
企业级应用检查清单
- 三层架构分离明确
- 异常处理机制完善
- 日志记录规范统一
- 保活机制稳定可靠
- 代码可测试性高
- 协议扩展性强
- 性能优化到位
- 用户体验友好
下篇预告
下一篇《无界面NFC后台服务方案》将深入探讨:
- Tag对象跨进程传递的技术挑战
- 多种技术方案的深度对比
- 1px透明Activity的最佳实践
- 防抖Toast工具类的实现
参考资料:
一、企业级NFC架构设计
1.1 三层架构模式
在企业级NFC开发中,良好的架构设计是项目成功的关键。我们采用经典的三层架构模式,实现关注点分离和职责解耦。
架构层次图
markdown
┌─────────────────────────────────────────────┐
│ UI Layer(表示层) │
│ ┌────────────────┐ ┌──────────────────┐ │
│ │ Activity │ │ Service │ │
│ │ │ │ │ │
│ │ - 用户交互 │ │ - 后台服务 │ │
│ │ - 界面展示 │ │ - 保活机制 │ │
│ │ - 事件处理 │ │ - 广播接收 │ │
│ └────────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Business Layer(业务逻辑层) │
│ NfcBusinessManager │
│ │
│ ┌────────────────┐ ┌──────────────────┐ │
│ │ 协议识别 │ │ 数据处理 │ │
│ │ 解析调度 │ │ 异步执行 │ │
│ │ 状态管理 │ │ 结果回调 │ │
│ └────────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ Data Layer(数据访问层) │
│ NfcUtils │
│ │
│ ┌────────────────┐ ┌──────────────────┐ │
│ │ 协议解析 │ │ 异常处理 │ │
│ │ 数据存储 │ │ 工具方法 │ │
│ │ 硬件操作 │ │ 格式转换 │ │
│ └────────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────┘
架构设计原则
- 单一职责原则(SRP):每个类只负责一个功能领域
- 依赖倒置原则(DIP):依赖抽象接口而非具体实现
- 开闭原则(OCP):对扩展开放,对修改封闭
- 接口隔离原则(ISP):接口粒度细化,避免臃肿
- 异步处理原则:避免阻塞UI线程,提升用户体验
1.2 核心类设计
1.2.1 业务管理层 - NfcBusinessManager
业务管理层负责协调NFC相关的所有业务逻辑,是UI层和数据层之间的桥梁。
java
/**
* NFC业务管理器 - 负责协调NFC相关的所有业务逻辑
*
* 设计原则:
* 1. 单一职责:只负责业务逻辑调度,不涉及具体实现
* 2. 依赖倒置:依赖抽象接口(NfcUiCallback)而非具体UI实现
* 3. 异步处理:避免阻塞UI线程
* 4. 单例模式:全局唯一实例,避免资源浪费
*/
public class NfcBusinessManager {
private static final String TAG = "NfcBusinessManager";
private static volatile NfcBusinessManager instance;
private Context context;
private Handler mainHandler;
private NfcUiCallback uiCallback;
private ExecutorService executorService;
private NfcBusinessManager(Context context) {
this.context = context.getApplicationContext();
this.mainHandler = new Handler(Looper.getMainLooper());
this.executorService = Executors.newSingleThreadExecutor();
}
/**
* 双重检查锁单例模式(线程安全)
*/
public static NfcBusinessManager getInstance(Context context) {
if (instance == null) {
synchronized (NfcBusinessManager.class) {
if (instance == null) {
instance = new NfcBusinessManager(context);
}
}
}
return instance;
}
/**
* 设置UI回调接口(依赖倒置)
*/
public void setUiCallback(NfcUiCallback callback) {
this.uiCallback = callback;
}
/**
* 处理NFC标签 - 业务入口
*
* 流程:
* 1. 参数校验
* 2. UI状态通知(显示加载)
* 3. 异步处理NFC数据
* 4. 结果回调(成功/失败)
*/
public void processNfcTag(Tag tag) {
if (tag == null) {
notifyError("标签对象为空");
return;
}
Log.d(TAG, "开始处理NFC标签,UID: " + NfcUtils.bytesToHex(tag.getId()));
// 显示加载状态
notifyLoading();
// 异步处理,避免阻塞UI线程
executorService.execute(() -> {
try {
// 业务处理流程
String result = parseNfcData(tag);
if (result != null && !result.isEmpty()) {
// 保存数据到系统
saveNfcData(result);
notifySuccess("数据读取成功: " + result);
} else {
notifyError("数据解析失败:返回结果为空");
}
} catch (Exception e) {
Log.e(TAG, "处理NFC标签时发生异常", e);
notifyError("处理异常:" + getErrorMessage(e));
}
});
}
/**
* 同步处理NFC标签(用于后台服务)
*/
public String processNfcTagSync(Tag tag) throws Exception {
if (tag == null) {
throw new IllegalArgumentException("标签对象为空");
}
Log.d(TAG, "同步处理NFC标签,UID: " + NfcUtils.bytesToHex(tag.getId()));
// 业务处理流程
String result = parseNfcData(tag);
if (result != null && !result.isEmpty()) {
// 保存数据到系统
saveNfcData(result);
return result;
} else {
throw new NfcParseException("数据解析失败:返回结果为空");
}
}
/**
* NFC数据解析 - 调用数据层
*/
private String parseNfcData(Tag tag) {
return NfcUtils.parseNfcData(tag);
}
/**
* 保存NFC数据到系统
*/
private void saveNfcData(String data) {
NfcUtils.saveToSystem(context, data);
}
/**
* 错误信息处理 - 调用异常处理器
*/
private String getErrorMessage(Exception e) {
return NfcExceptionHandler.getErrorMessage(e);
}
// ==================== UI通知方法 ====================
private void notifyLoading() {
if (uiCallback != null) {
mainHandler.post(() -> uiCallback.showLoading());
}
}
private void notifySuccess(String message) {
if (uiCallback != null) {
mainHandler.post(() -> uiCallback.showSuccess(message));
}
}
private void notifyError(String message) {
if (uiCallback != null) {
mainHandler.post(() -> uiCallback.showError(message));
}
}
/**
* 释放资源
*/
public void release() {
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdown();
}
uiCallback = null;
}
}
1.2.2 UI回调接口
java
/**
* NFC业务层与UI层的通信接口
*/
public interface NfcUiCallback {
/**
* 显示加载状态
*/
void showLoading();
/**
* 显示成功消息
*/
void showSuccess(String message);
/**
* 显示错误消息
*/
void showError(String message);
}
1.2.3 数据处理层 - NfcUtils
数据处理层负责底层NFC操作和协议解析,所有方法都是静态的(无状态设计)。
java
/**
* NFC数据处理工具类 - 负责底层NFC操作和协议解析
*
* 设计原则:
* 1. 无状态:所有方法都是静态的,避免状态管理
* 2. 协议兼容:支持多种协议版本的自动识别
* 3. 异常安全:完善的异常处理机制
*/
public class NfcUtils {
private static final String TAG = "NfcUtils";
// 协议版本常量
private static final String PROTOCOL_NEW = "NEW";
private static final String PROTOCOL_OLD = "OLD";
private static final String PROTOCOL_NDEF = "NDEF";
/**
* NFC数据解析入口 - 根据协议自动识别解析方式
*
* 流程:
* 1. 协议自动识别
* 2. 根据协议选择解析器(工厂模式)
* 3. 执行解析
*/
public static String parseNfcData(Tag tag) {
try {
// 1. 协议自动识别
String protocol = detectProtocol(tag);
Log.d(TAG, "检测到协议类型: " + protocol);
// 2. 根据协议选择解析器(工厂模式)
NfcDataParser parser = NfcParserFactory.getParser(protocol);
// 3. 执行解析
return parser.parse(tag);
} catch (Exception e) {
Log.e(TAG, "NFC数据解析失败", e);
throw new NfcParseException("数据解析失败", e);
}
}
/**
* 协议自动识别
*
* 识别逻辑:
* 1. 读取协议标识块
* 2. 判断标识符
* 3. 返回协议类型
*/
private static String detectProtocol(Tag tag) {
// 优先检查NDEF格式
if (isNdefFormat(tag)) {
return PROTOCOL_NDEF;
}
// 检查MIFARE Classic卡
if (MifareClassic.get(tag) != null) {
// 根据厂商协议实现具体识别逻辑
byte[] protocolBytes = readProtocolIdentifier(tag);
if (isNewProtocol(protocolBytes)) {
return PROTOCOL_NEW;
} else if (isOldProtocol(protocolBytes)) {
return PROTOCOL_OLD;
}
}
throw new UnsupportedOperationException("不支持的协议类型");
}
/**
* 保存数据到系统
*
* 使用Settings.System存储,方便跨进程访问
*/
public static void saveToSystem(Context context, String data) {
try {
// 创建JSON格式数据
JSONObject jsonData = new JSONObject();
jsonData.put("data", data);
jsonData.put("timestamp", System.currentTimeMillis());
jsonData.put("source", "NFC");
// 保存到系统设置
boolean success = Settings.System.putString(
context.getContentResolver(),
"NFC_SCAN_RESULT",
jsonData.toString()
);
if (success) {
Log.d(TAG, "数据保存成功: " + jsonData);
} else {
Log.w(TAG, "数据保存失败");
}
} catch (Exception e) {
Log.e(TAG, "保存数据时发生异常", e);
throw new NfcSaveException("数据保存失败", e);
}
}
/**
* 字节数组转十六进制字符串
*/
public static String bytesToHex(byte[] bytes) {
if (bytes == null) return null;
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}
// ==================== 协议检测的辅助方法(伪代码) ====================
private static byte[] readProtocolIdentifier(Tag tag) {
// 根据具体协议实现
// 这里是伪代码,实际项目需要根据厂商协议文档实现
return new byte[16];
}
private static boolean isNewProtocol(byte[] data) {
// 根据具体协议实现
// 示例:检查特定字节位置的标识符
return false;
}
private static boolean isOldProtocol(byte[] data) {
// 根据具体协议实现
return false;
}
private static boolean isNdefFormat(Tag tag) {
return Ndef.get(tag) != null;
}
}
1.3 协议兼容性处理(工厂模式)
为了支持多种NFC协议的兼容性,我们使用工厂模式 + 策略模式进行协议解析器的管理。
1.3.1 解析器接口定义
java
/**
* NFC数据解析器接口(策略模式)
*/
public interface NfcDataParser {
/**
* 解析NFC数据
* @param tag NFC标签对象
* @return 解析后的数据
*/
String parse(Tag tag);
/**
* 检查是否支持该标签
* @param tag NFC标签对象
* @return 是否支持
*/
boolean isSupported(Tag tag);
/**
* 获取协议名称
* @return 协议名称
*/
String getProtocolName();
}
1.3.2 具体协议解析器实现(示例)
java
/**
* 新协议解析器 - 示例实现(伪代码)
*
* 注意:具体实现需要根据厂商协议文档定制
*/
public class NewProtocolParser implements NfcDataParser {
private static final String TAG = "NewProtocolParser";
@Override
public String parse(Tag tag) {
Log.d(TAG, "使用新协议解析数据");
try {
// 1. 读取协议标识块
byte[] protocolBlock = readProtocolBlock(tag);
// 2. 解析FLAG字段(标识数据分布)
Map<Byte, Integer> flagMap = parseFlags(protocolBlock);
// 3. 读取数据长度信息
byte[] lengthBlock = readLengthBlock(tag);
// 4. 根据FLAG读取对应数据
String result = readDataByFlags(tag, flagMap, lengthBlock);
return result;
} catch (Exception e) {
Log.e(TAG, "新协议解析失败", e);
throw new NfcParseException("新协议解析失败", e);
}
}
@Override
public boolean isSupported(Tag tag) {
// 根据具体协议实现识别逻辑
return detectNewProtocol(tag);
}
@Override
public String getProtocolName() {
return "NEW_PROTOCOL";
}
// ==================== 协议解析的辅助方法(伪代码) ====================
private byte[] readProtocolBlock(Tag tag) {
// 读取协议标识块的具体实现
// 需要根据厂商协议文档实现
return new byte[16];
}
private Map<Byte, Integer> parseFlags(byte[] flagBlock) {
// 解析FLAG字段的具体实现
return new HashMap<>();
}
private byte[] readLengthBlock(Tag tag) {
// 读取数据长度块的具体实现
return new byte[16];
}
private String readDataByFlags(Tag tag, Map<Byte, Integer> flagMap, byte[] lengthBlock) {
// 根据FLAG读取数据的具体实现
return "解析结果";
}
private boolean detectNewProtocol(Tag tag) {
// 新协议识别逻辑
return false;
}
}
/**
* NDEF协议解析器(标准实现)
*/
public class NdefParser implements NfcDataParser {
private static final String TAG = "NdefParser";
@Override
public String parse(Tag tag) {
Log.d(TAG, "使用NDEF协议解析数据");
return NdefReader.readNdefTag(tag);
}
@Override
public boolean isSupported(Tag tag) {
return Ndef.get(tag) != null;
}
@Override
public String getProtocolName() {
return "NDEF";
}
}
1.3.3 解析器工厂
java
/**
* NFC解析器工厂 - 根据协议类型选择合适的解析器
*/
public class NfcParserFactory {
private static final String TAG = "NfcParserFactory";
// 解析器列表(可动态扩展)
private static final List<NfcDataParser> PARSERS = Arrays.asList(
new NdefParser(),
new NewProtocolParser(),
new OldProtocolParser()
);
/**
* 根据协议名称获取解析器
*/
public static NfcDataParser getParser(String protocol) {
for (NfcDataParser parser : PARSERS) {
if (parser.getProtocolName().equals(protocol)) {
Log.d(TAG, "选择解析器: " + protocol);
return parser;
}
}
throw new UnsupportedOperationException("不支持的协议类型: " + protocol);
}
/**
* 自动选择解析器(根据Tag对象)
*/
public static NfcDataParser getParser(Tag tag) {
for (NfcDataParser parser : PARSERS) {
if (parser.isSupported(tag)) {
Log.d(TAG, "自动选择解析器: " + parser.getProtocolName());
return parser;
}
}
throw new UnsupportedOperationException("找不到支持的解析器");
}
/**
* 获取所有支持的协议
*/
public static List<String> getSupportedProtocols() {
List<String> protocols = new ArrayList<>();
for (NfcDataParser parser : PARSERS) {
protocols.add(parser.getProtocolName());
}
return protocols;
}
}
二、应用保活架构
在企业级NFC应用中,保持应用长期运行是一个重要需求。我们采用多重保活策略确保NFC服务的高可用性。
2.1 开机自启机制
2.1.1 BootReceiver实现
java
/**
* 开机自启接收器 - 确保应用开机后自动启动NFC服务
*
* 功能:
* 1. 监听开机完成广播
* 2. 延迟启动NFC前台服务(避免系统资源竞争)
* 3. 错误处理和日志记录
*/
public class BootReceiver extends BroadcastReceiver {
private static final String TAG = "BootReceiver";
private static final int DELAY_START_MS = 3000; // 延迟3秒启动
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
Log.d(TAG, "收到开机完成广播,准备启动NFC服务");
// 延迟启动,避免系统资源竞争
new Handler(Looper.getMainLooper()).postDelayed(() -> {
startNfcService(context);
}, DELAY_START_MS);
}
}
/**
* 启动NFC前台服务
*/
private void startNfcService(Context context) {
try {
Intent serviceIntent = new Intent(context, NfcService.class);
// Android 8.0+ 需要使用startForegroundService
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent);
} else {
context.startService(serviceIntent);
}
Log.d(TAG, "NFC前台服务启动成功");
} catch (Exception e) {
Log.e(TAG, "启动NFC前台服务失败", e);
}
}
}
2.1.2 Manifest配置
xml
<!-- 开机自启接收器 -->
<receiver
android:name=".receiver.BootReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
2.2 前台服务保活
2.2.1 NfcService实现
java
/**
* NFC前台服务 - 保持NFC功能在后台长期运行
*
* 功能:
* 1. 前台服务保活,避免被系统杀死
* 2. 维持NFC硬件连接
* 3. 处理后台NFC事件
* 4. 服务被杀后自动重启
*/
public class NfcService extends Service {
private static final String TAG = "NfcService";
private static final int NOTIFY_ID = 1001;
private static final String CHANNEL_ID = "nfc_service_channel";
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "NFC服务创建");
// 初始化前台通知
initForegroundNotification();
// 初始化NFC业务管理器
NfcBusinessManager.getInstance(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "NFC服务启动,保持后台运行");
// START_STICKY:服务被系统杀死后自动重启
// START_NOT_STICKY:服务被杀死后不会重启
// START_REDELIVER_INTENT:服务被杀死后重启并重新传递Intent
return START_STICKY;
}
/**
* 初始化前台通知
*/
private void initForegroundNotification() {
// 创建通知渠道(Android 8.0+)
createNotificationChannel();
// 创建通知Intent(点击通知跳转到主Activity)
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this,
0,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
// 创建前台通知
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("NFC服务运行中")
.setContentText("正在监控NFC标签,请保持应用运行")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_LOW) // 低优先级,不打扰用户
.setOngoing(true) // 持久通知,不可滑动删除
.setShowWhen(false) // 不显示时间
.build();
// 启动前台服务
startForeground(NOTIFY_ID, notification);
Log.d(TAG, "前台通知已创建,服务提升为前台服务");
}
/**
* 创建通知渠道(Android 8.0+)
*/
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
"NFC服务",
NotificationManager.IMPORTANCE_LOW // 低重要性,不发出声音
);
channel.setDescription("NFC后台服务通知");
channel.setShowBadge(false); // 不显示角标
NotificationManager manager = getSystemService(NotificationManager.class);
if (manager != null) {
manager.createNotificationChannel(channel);
Log.d(TAG, "通知渠道已创建");
}
}
}
@Override
public IBinder onBind(Intent intent) {
return null; // 不提供绑定服务
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "NFC服务销毁");
// 释放业务管理器资源
NfcBusinessManager.getInstance(this).release();
}
/**
* 服务被系统杀死后的重启处理
*/
@Override
public void onTaskRemoved(Intent rootIntent) {
Log.d(TAG, "任务被移除,准备重启服务");
// 重启服务
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getApplicationContext().startForegroundService(restartServiceIntent);
} else {
getApplicationContext().startService(restartServiceIntent);
}
super.onTaskRemoved(rootIntent);
}
}
2.2.2 Manifest配置
xml
<!-- NFC前台服务 -->
<service
android:name=".service.NfcService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="connectedDevice" />
2.3 双重保活策略
2.3.1 保活管理器
java
/**
* 应用保活管理器 - 提供多种保活策略
*
* 保活策略:
* 1. 前台服务保活(主要策略)
* 2. JobScheduler定时保活(辅助策略)
* 3. WorkManager保活(可选)
*/
public class AppKeepAliveManager {
private static final String TAG = "KeepAliveManager";
private Context context;
public AppKeepAliveManager(Context context) {
this.context = context.getApplicationContext();
}
/**
* 启动所有保活机制
*/
public void startKeepAlive() {
Log.d(TAG, "启动应用保活机制");
// 1. 前台服务保活(主要策略)
startForegroundService();
// 2. JobScheduler定时保活(Android 5.0+)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
scheduleJobService();
}
}
/**
* 启动前台服务
*/
private void startForegroundService() {
Intent serviceIntent = new Intent(context, NfcService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent);
} else {
context.startService(serviceIntent);
}
Log.d(TAG, "前台服务已启动");
}
/**
* JobScheduler保活(Android 5.0+)
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void scheduleJobService() {
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
if (jobScheduler == null) {
Log.w(TAG, "JobScheduler不可用");
return;
}
JobInfo jobInfo = new JobInfo.Builder(
1001,
new ComponentName(context, KeepAliveJobService.class)
)
.setPeriodic(15 * 60 * 1000) // 15分钟执行一次
.setRequiresCharging(false) // 不需要充电
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) // 任何网络类型
.setPersisted(true) // 重启后保留
.build();
int result = jobScheduler.schedule(jobInfo);
if (result == JobScheduler.RESULT_SUCCESS) {
Log.d(TAG, "JobScheduler调度成功");
} else {
Log.w(TAG, "JobScheduler调度失败");
}
}
}
2.3.2 KeepAliveJobService实现
java
/**
* 保活Job服务(Android 5.0+)
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class KeepAliveJobService extends JobService {
private static final String TAG = "KeepAliveJobService";
@Override
public boolean onStartJob(JobParameters params) {
Log.d(TAG, "KeepAliveJobService执行");
// 检查NFC服务是否运行,如果未运行则启动
if (!isNfcServiceRunning()) {
startNfcService();
}
// false表示任务已完成,不需要重新调度
// true表示任务正在后台执行,需要调用jobFinished()
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
Log.d(TAG, "KeepAliveJobService停止");
// true表示需要重新调度
return true;
}
private boolean isNfcServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
if (manager == null) return false;
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (NfcService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
private void startNfcService() {
Intent serviceIntent = new Intent(this, NfcService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent);
} else {
startService(serviceIntent);
}
Log.d(TAG, "NFC服务已重新启动");
}
}
三、异常处理机制
3.1 统一异常处理器
java
/**
* NFC异常处理器 - 统一处理各种NFC相关异常
*
* 功能:
* 1. 将技术异常转换为用户友好的错误信息
* 2. 异常日志记录
* 3. 异常上报(可选)
*/
public class NfcExceptionHandler {
private static final String TAG = "NfcExceptionHandler";
/**
* 获取用户友好的错误信息
*/
public static String getErrorMessage(Exception e) {
if (e == null) {
return "未知错误";
}
// 根据异常类型返回对应的错误信息
if (e instanceof IOException) {
return handleIOException((IOException) e);
} else if (e instanceof TagLostException) {
return "卡片已离开感应区,请重新放置";
} else if (e instanceof FormatException) {
return "卡片数据格式异常,请检查卡片是否损坏";
} else if (e instanceof NfcParseException) {
return "数据解析失败,请确认卡片格式";
} else if (e instanceof NfcSaveException) {
return "数据保存失败,请重试";
} else if (e instanceof SecurityException) {
return "权限不足,请检查NFC权限设置";
} else {
return "操作失败:" + e.getMessage();
}
}
/**
* 处理IO异常
*/
private static String handleIOException(IOException e) {
String message = e.getMessage();
if (message != null) {
if (message.contains("connect") || message.contains("transceive")) {
return "连接失败,请确认卡片已正确放置";
} else if (message.contains("authentication")) {
return "卡片认证失败,请检查密钥设置";
} else if (message.contains("timeout")) {
return "操作超时,请重试";
}
}
return "IO操作失败:" + message;
}
/**
* 记录异常信息
*/
public static void logException(String operation, Exception e) {
Log.e(TAG, "NFC操作异常 - " + operation, e);
// 可以在这里添加异常上报逻辑
// CrashReport.recordException(operation, e);
}
/**
* 处理异常并返回结果(函数式接口)
*/
public static <T> T handleException(String operation, ExceptionSupplier<T> supplier) {
try {
return supplier.get();
} catch (Exception e) {
logException(operation, e);
throw new NfcOperationException(getErrorMessage(e), e);
}
}
@FunctionalInterface
public interface ExceptionSupplier<T> {
T get() throws Exception;
}
}
3.2 自定义异常类
java
/**
* NFC解析异常
*/
public class NfcParseException extends RuntimeException {
public NfcParseException(String message) {
super(message);
}
public NfcParseException(String message, Throwable cause) {
super(message, cause);
}
}
/**
* NFC保存异常
*/
public class NfcSaveException extends RuntimeException {
public NfcSaveException(String message) {
super(message);
}
public NfcSaveException(String message, Throwable cause) {
super(message, cause);
}
}
/**
* NFC操作异常
*/
public class NfcOperationException extends RuntimeException {
public NfcOperationException(String message) {
super(message);
}
public NfcOperationException(String message, Throwable cause) {
super(message, cause);
}
}
四、架构分离最佳实践
4.1 设计原则总结
1. 接口抽象原则
通过接口抽象实现层与层之间的解耦,便于扩展和维护。
java
// ✅ 正确:依赖抽象接口
public class NfcBusinessManager {
private NfcUiCallback uiCallback; // 依赖接口
}
// ❌ 错误:依赖具体实现
public class NfcBusinessManager {
private MainActivity activity; // 依赖具体Activity
}
2. 单一职责原则
每个类只负责一个功能领域,保持代码的简洁和可维护性。
java
// ✅ 正确:职责单一
public class NfcBusinessManager {
// 只负责业务逻辑调度
}
public class NfcUtils {
// 只负责底层NFC操作
}
// ❌ 错误:职责混乱
public class NfcManager {
// 既有业务逻辑,又有UI操作,还有硬件操作
}
3. 开闭原则
对扩展开放,对修改封闭。新的协议可以通过实现接口轻松添加。
java
// ✅ 正确:添加新协议只需实现接口
public class CustomProtocolParser implements NfcDataParser {
@Override
public String parse(Tag tag) {
// 自定义协议解析逻辑
}
}
// 注册到工厂
PARSERS.add(new CustomProtocolParser());
4. 依赖注入
使用依赖注入降低组件间的耦合度。
java
// ✅ 正确:通过构造器注入依赖
public class NfcActivity extends BaseNfcActivity implements NfcUiCallback {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 注入回调接口
NfcBusinessManager.getInstance(this).setUiCallback(this);
}
}
4.2 代码组织结构
推荐的项目包结构:
bash
com.example.nfcapp
├── ui # UI层
│ ├── activity
│ │ ├── MainActivity
│ │ ├── NdefActivity
│ │ └── MifareActivity
│ └── callback
│ └── NfcUiCallback
├── business # 业务逻辑层
│ ├── NfcBusinessManager
│ └── AppKeepAliveManager
├── data # 数据访问层
│ ├── NfcUtils
│ ├── NdefReader
│ ├── MifareClassicReader
│ └── parser
│ ├── NfcDataParser
│ ├── NfcParserFactory
│ ├── NewProtocolParser
│ ├── OldProtocolParser
│ └── NdefParser
├── service # 服务层
│ ├── NfcService
│ └── KeepAliveJobService
├── receiver # 广播接收器
│ └── BootReceiver
├── exception # 异常处理
│ ├── NfcExceptionHandler
│ ├── NfcParseException
│ ├── NfcSaveException
│ └── NfcOperationException
└── util # 工具类
├── NfcChecker
└── NfcForegroundManager
五、性能优化建议
5.1 内存优化
java
// ✅ 使用单例模式避免重复创建
public static NfcBusinessManager getInstance(Context context) {
if (instance == null) {
synchronized (NfcBusinessManager.class) {
if (instance == null) {
instance = new NfcBusinessManager(context);
}
}
}
return instance;
}
// ✅ 及时释放资源
@Override
protected void onDestroy() {
super.onDestroy();
NfcBusinessManager.getInstance(this).release();
}
5.2 线程优化
java
// ✅ 使用线程池管理线程
private ExecutorService executorService = Executors.newSingleThreadExecutor();
// ❌ 避免每次都创建新线程
new Thread(() -> {
// NFC操作
}).start();
5.3 日志优化
java
// ✅ 使用日志级别控制
if (BuildConfig.DEBUG) {
Log.d(TAG, "详细的调试信息");
}
// ✅ 避免在生产环境输出敏感信息
Log.d(TAG, "UID: " + maskSensitiveData(uid));