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));

相关推荐
短视频矩阵源码定制9 小时前
矩阵系统源码推荐:技术架构与功能完备性深度解析
java·人工智能·矩阵·架构
feibafeibafeiba10 小时前
Android 14 关于imageview设置动态padding值导致图标旋转的问题
android
tangweiguo0305198711 小时前
ProcessLifecycleOwner 完全指南:优雅监听应用前后台状态
android·kotlin
工藤学编程11 小时前
深入Rust:Tokio多线程调度架构的原理、实践与性能优化
性能优化·架构·rust
稚辉君.MCA_P8_Java11 小时前
RocketMQ 是什么?它的架构是怎么样的?和 Kafka 又有什么区别?
后端·架构·kafka·kubernetes·rocketmq
蛮三刀酱11 小时前
复杂度的代价远比你想象得大
java·架构
介一安全12 小时前
【Frida Android】基础篇15(完):Frida-Trace 基础应用——JNI 函数 Hook
android·网络安全·ida·逆向·frida
吞掉星星的鲸鱼12 小时前
android studio创建使用开发打包教程
android·ide·android studio
陈老师还在写代码12 小时前
android studio 签名打包教程
android·ide·android studio