NFC开发系列 - 第二篇:NFC企业级架构设计与最佳实践

NFC开发系列 - 第二篇:NFC企业级架构设计与最佳实践

在掌握了NFC开发的基础知识和实战技能后,本篇将带你深入企业级NFC应用的架构设计,学习如何构建一个健壮、可维护、可扩展的NFC系统。

架构设计核心要点

  1. 三层架构:UI层、业务逻辑层、数据访问层分离
  2. 协议兼容:工厂模式 + 策略模式支持多协议
  3. 应用保活:前台服务 + JobScheduler双重保活
  4. 异常处理:统一异常处理器,友好的错误提示
  5. 设计原则:单一职责、依赖倒置、开闭原则

企业级应用检查清单

  • 三层架构分离明确
  • 异常处理机制完善
  • 日志记录规范统一
  • 保活机制稳定可靠
  • 代码可测试性高
  • 协议扩展性强
  • 性能优化到位
  • 用户体验友好

下篇预告

下一篇《无界面NFC后台服务方案》将深入探讨:

  • Tag对象跨进程传递的技术挑战
  • 多种技术方案的深度对比
  • 1px透明Activity的最佳实践
  • 防抖Toast工具类的实现

参考资料:


一、企业级NFC架构设计

1.1 三层架构模式

在企业级NFC开发中,良好的架构设计是项目成功的关键。我们采用经典的三层架构模式,实现关注点分离和职责解耦。

架构层次图
markdown 复制代码
┌─────────────────────────────────────────────┐
│              UI Layer(表示层)              │
│  ┌────────────────┐    ┌──────────────────┐ │
│  │   Activity     │    │     Service      │ │
│  │                │    │                  │ │
│  │ - 用户交互     │    │ - 后台服务       │ │
│  │ - 界面展示     │    │ - 保活机制       │ │
│  │ - 事件处理     │    │ - 广播接收       │ │
│  └────────────────┘    └──────────────────┘ │
└─────────────────────────────────────────────┘
                      ↓
┌─────────────────────────────────────────────┐
│         Business Layer(业务逻辑层)         │
│            NfcBusinessManager               │
│                                             │
│  ┌────────────────┐    ┌──────────────────┐ │
│  │   协议识别     │    │    数据处理      │ │
│  │   解析调度     │    │    异步执行      │ │
│  │   状态管理     │    │    结果回调      │ │
│  └────────────────┘    └──────────────────┘ │
└─────────────────────────────────────────────┘
                      ↓
┌─────────────────────────────────────────────┐
│          Data Layer(数据访问层)            │
│               NfcUtils                      │
│                                             │
│  ┌────────────────┐    ┌──────────────────┐ │
│  │   协议解析     │    │    异常处理      │ │
│  │   数据存储     │    │    工具方法      │ │
│  │   硬件操作     │    │    格式转换      │ │
│  └────────────────┘    └──────────────────┘ │
└─────────────────────────────────────────────┘
架构设计原则
  1. 单一职责原则(SRP):每个类只负责一个功能领域
  2. 依赖倒置原则(DIP):依赖抽象接口而非具体实现
  3. 开闭原则(OCP):对扩展开放,对修改封闭
  4. 接口隔离原则(ISP):接口粒度细化,避免臃肿
  5. 异步处理原则:避免阻塞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));

相关推荐
xiaolizi5674891 小时前
安卓远程安卓(通过frp与adb远程)完全免费
android·远程工作
阿杰100011 小时前
ADB(Android Debug Bridge)是 Android SDK 核心调试工具,通过电脑与 Android 设备(手机、平板、嵌入式设备等)建立通信,对设备进行控制、文件传输、命令等操作。
android·adb
梨落秋霜2 小时前
Python入门篇【文件处理】
android·java·python
源心锁2 小时前
丧心病狂!在浏览器全天候记录用户行为排障
前端·架构
遥不可及zzz4 小时前
Android 接入UMP
android
Tony Bai5 小时前
【分布式系统】03 复制(上):“权威中心”的秩序 —— 主从架构、一致性与权衡
大数据·数据库·分布式·架构
AIagenttest5 小时前
2026年智能招聘管理系统测评:从流程协同到算力执行的架构跨越
架构
Mr_sun.6 小时前
微服务框架课程
微服务·云原生·架构
Coder_Boy_6 小时前
基于SpringAI的在线考试系统设计总案-知识点管理模块详细设计
android·java·javascript
冬奇Lab7 小时前
【Kotlin系列03】控制流与函数:从if表达式到Lambda的进化之路
android·kotlin·编程语言