NFC framework introduce(一)

本文介绍了Android NFC框架,包括NFC的简介、总体框架、初始化流程和NDEF数据读写流程。NFC是一种短距离无线技术,适用于点对点数据交换。框架采用c/s架构,客户端API位于android.nfc.tech和android.nfc包,服务端为NfcService。NFC数据分为NFC basics和Advanced NFC,涉及NDEF消息的读写。初始化流程包括服务端和客户端的初始化。NDEF数据读写流程涵盖小数据量和大数据量的处理,其中小数据量数据通过NdefMessage直接传送,大数据量数据则结合蓝牙进行传输。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  NFC framework introduce

 

1 NFC 简介

对于NFC,是googleandroid4.0上推出来的,简单介绍下近场通讯(NFC)是一系列短距离无线技术,一般需要4cm或者更短去初始化连接。近场通讯(NFC)允许你在NFC tagAndroid设备或者两个Android设备间共享小负载数据。优酷上有其应用的视频:http://v.youku.com/v_show/id_XMjM3ODE5ODMy.html

http://v.youku.com/v_show/id_XMzM1MTUyMzI4.html

2 总体框架

   对于NFC框架的设计,同样是android的标准的c/s架构,其框架图如下:



n        客户端:android提供了两个API包给apk,分别是android.nfc.techandroid.nfc,实现了NFC的应用接口,代码路径frameworks/base/core/java/android/nfc/techframeworks/base/core/java/android/nfc

n        服务端:packages/apps/Nfc是一个类似电话本的应用,这个程序在启动后自动运行,并一直运行,作为NFC的服务进程存在,是NFC的核心。

在这个程序代码中,有个JNI库,供NfcService调用,代码路径是packages/apps/Nfc/jni/

n        库文件:代码路径是external/libnfc-nxp,C编写的库文件,有两个库,分别是libnfc.solibnfc_ndef.solibnfc.so是一个主要的库,实现了NFC stack的大部分功能,主要提供NFC的服务进程调用。libnfc_ndef是一个很小的库,主要是实现NDEF消息的解析,供framework调用

2.1 总体类图关系



2.2 数据分类

NFC按照发展,分为两种,NFC basicsAdvanced NFC。从字面上理解,第一种是最先设计的,第二种是在原来基础上扩展的。

2.2.1 NFC basics

是一种点对点(P2P)数据交换的功能,传送的数据格式是NDEF,是Nfc Data Exchange Format的缩写,这个数据格式用于设备之间点对点数据的交换,例如网页地址、联系人、邮件、图片等。对于除图片以外的数据,数据量比较小,直接封装在类NdefMessage中,通过NFCNdefMessage类型数据发送到另一台设备,而对于图片这样数据量比较大的数据,需要构建一个标准的NdefMessage数据,发送给另外一台设备,等有回应之后,再通过蓝牙传送数据。

NdefMessage类是用于数据的封装,其包含有一个或多个NdefRecord类,NdefRecord才是存储数据的实体,将联系人、邮件、网页地址等转换才byte类型的数据存储在NdefRecord当中,并且包含了数据类型。举个例子吧:

NdefRecord uriRecord = newNdefRecord(

   NdefRecord.TNF_ABSOLUTE_URI ,

   "http://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")),

new byte[0], new byte[0]);

newNdefMessage(uriRecord);

 

以上是用NdefMessage对一个NdefRecord数据进行分装。

为了更好理解数据的传送方式,需要更细的分为三种:

n        在一个Apk中,用NdefMessage封装Apk的数据,在设置NdefRecord的数据类型,然后发送给其他设备。在接收设备的同样的APKAndroidManifest文件中设置接收数据的类型,这样通过Intent消息就能找到对应的Activity启动。

n        直接将当前运行(home程序外)Apk的包名封装到NdefMessage中,发送给其他设备。接收设备收到NdefMessage数据,转换才成包名,根据包名构造Intent,启动指定的Activity。如果包名不存在,那么会启动google play去下载安装该Apk

n        图片为数据量比较大的数据。需要封装一个标准的NdefMessage数据发送给其他设备,当有回应的时候,在将图片数据通过蓝牙发送给其他设备。

 

按照上面的分析,还可以将数据传送,分为小数据量的传送和大数据量的传送。小数据量是指联系人、邮件、网页地址、包名等,而大数据量是指图片等,需要通过蓝牙传送的。那么为什么NFC的功能还要蓝牙传送呢?原因是NFC的设计本来就是为了传送小的数据量,同我们通过NFC启动蓝牙传图片,更方便的不需要手动进行蓝牙的匹配,只需要将手机贴在一起就可以完成了蓝牙的匹配动作。

2.2.2 Advanced NFC

对于该类型的NFC,也是在点对点数据交换功能上的一个扩充,我们日常接触的有公交卡、饭卡,手机设备可以通过NFC功能读取该卡内的数据,也有支持NFC设备往这类卡里面写数据。所以,我们将这些卡类称为Tag

   需要直接通过Byte格式进行数据封装,对TAG数据进行读写。市面上有很多的卡,估计没个城市用的公交卡都不一样,就是使用的标准不一样,所以在 android.nfc.tech包下支持了多种technologies,如下图:

   NFC <wbr>framework <wbr>introduce(一)


   tag设备与手机足够近的时候,手机设备首先收到了Tag信息,里面包含了当前Tag设备所支持的technology,然后将Tag信息发送到指定的Activity中。在Activity中,将读取Tag里面的数据,构造相应的technology,然后再以该technology的标准,对tag设备进行读写。

3初始化流程

3.1 时序图


3.2 代码分析

    初始化分两部分,第一是服务端的初始化,并将服务添加到ServiceManager中,第二是初始化NFC适配器NfcAdapter

3.2.1 Server端初始化

NFC的服务端代码在packages/apps/Nfc中,并且还包含了JNI代码,前面也介绍过,NFC的服务端是一个应用程序,跟随系统启动并一直存在的一个服务进程。

NfcService继承于Application,当程序启动的时候,调用onCreate()方法,代码如下:

public void onCreate(){

       super.onCreate();

       mNfcTagService = newTagService();

       mNfcAdapter = new NfcAdapterService();

       mExtrasService = new NfcAdapterExtrasService();

       ……

       mDeviceHost = new NativeNfcManager(this, this);

       mNfcDispatcher = new NfcDispatcher(this,handoverManager);

       mP2pLinkManager = new P2pLinkManager(mContext,handoverManager);

       ……

       ServiceManager.addService(SERVICE_NAME,mNfcAdapter);//mNfcAdapter添加到系统服务列表中。

       …….

       new EnableDisableTask().execute(TASK_BOOT);  // doblocking boot tasks

   }

TagServiceNfcService的内部类,并继承于INfcTag.stub,因此客户端可以通过Binder通信获取到TagService的实例mNfcTagService。其主要的功能是完成tag的读写。

NfcAdapterService也是NfcService的内部类,并继承于INfcAdapter.stub,同样客户端可以通过Binder通信获取到NfcAdapterService的实例mNfcAdapterNfcAdapterService也是暴露给客户端的主要接口,主要完成对NFC的使能初始化,扫面读写tag,派发tag消息等。

NativeNfcManager类就像其名字一样,主要负责native JNI的管理。

NfcDispatcher主要负责tag消息处理,并派发Intent消息,启动Activity

3.2.2 NfcAdapter客户端初始化

ContextImpl类中,有一个静态模块,在这里创建了NfcManager的实例,并注册到服务中,代码如下:

Static{

registerService(NFC_SERVICE, newServiceFetcher() {

               public Object createService(ContextImpl ctx) {

                   return newNfcManager(ctx);

               }});

}

   NfcManager的构造函数中,调用了NfcAdapter.getNfcAdapter(context),创建NFC Adapter

public static synchronizedNfcAdapter getNfcAdapter(Context context) {

       ……

           sService =getServiceInterface();//获取NFC服务接口

       ……

           try {

               sTagService= sService.getNfcTagInterface();//获取NFC tag服务接口

           } catch (RemoteException e) {

           }

       ……

       NfcAdapter adapter = sNfcAdapters.get(context);

       if (adapter == null) {

           adapter =newNfcAdapter(context);

           sNfcAdapters.put(context, adapter);

       }

       return adapter;

}

private static INfcAdaptergetServiceInterface() {//获取NFC服务接口

       IBinder b = ServiceManager.getService("nfc");

       if (b == null) {

           return null;

       }

       return INfcAdapter.Stub.asInterface(b);

}

我们看看getServiceInterface()方法,在3.2.1我们也看到了,调用ServiceManager.addService()NfcAdapterService的实例添加到系统的服务列表中,这里我们调用了ServiceManager.getService(“nfc”)获取到了服务端的NfcAdapterService对象的实例。

NfcAdapterService类中提供了getNfcTagInterface接口,用于获取远程服务端的TagService对象的实例。

如果一切正常,那么将创建NfcAdapter的实例,在其构造函数中,创建了NfcActivityManager的实例。

4 启动NFC流程

4.1 时序图

4.2 代码分析

如果android设备有N

<think>好的,我现在要帮用户了解PyCharm中的“Introduce Field”功能怎么用。首先,我得回忆下自己使用PyCharm的经验,或者查下相关资料,确保信息准确。用户可能是个开发者,在使用PyCharm时遇到了需要将局部变量提升为类字段的情况,所以需要这个重构功能的具体步骤和用途。 首先,“Introduce Field”属于重构操作的种,通常用于将局部变量转换为类的字段,这样该变量就可以在类的其他方法或块中使用。这个功能在代码重构时非常有用,尤其是当发现某个变量在多个地方被使用时,提升为字段可以减少重复代码,提高代码的可维护性。 接下来,我需要分步骤说明如何使用这个功能。首先,用户需要选中变量,然后通过快捷键或者右键菜单找到“Refactor”选项,再选择“Introduce Field”。这里可能需要说明不同操作系统下的快捷键,比如Windows/Linux是Ctrl+Alt+F,而macOS是Cmd+Alt+F。同时,用户可能需要调整初始化位置,比如构造函数或者当前方法,PyCharm会提供选项让用户选择。 另外,用户可能关心这个功能的应用场景,比如在多个方法中使用同个变量时,或者需要延长变量的生命周期。这时候,举例说明会有帮助,比如用户在个方法中创建了个变量,后来发现另个方法也需要使用它,这时候就可以使用“Introduce Field”来提升作用域。 还有可能需要提到些注意事项,比如如果变量已经被初始化,PyCharm会自动处理初始化位置,或者在提升过程中可能需要调整访问修饰符。这些细节能帮助用户避免常见错误,确保操作顺利进行。 最后,用户可能还想知道相关的其他重构功能,比如“Introduce Variable”或“Extract Method”,所以生成相关问题的时候可以包括这些,帮助他们进步学习。同时,确保回答中引用正确的格式,比如引用标识,但根据用户提供的引用内容,可能没有直接相关的,所以需要检查是否需要添加,但看起来用户提供的引用是关于React环境变量和Jest测试库的,可能与PyCharm功能无关,所以可能不需要引用。不过需要确认用户给的引用是否有相关内容,但看起来没有,所以可能不需要添加引用标识。 总结步骤:说明功能用途,详细步骤,应用场景,注意事项,相关其他功能的问题。</think>### PyCharm中"Introduce Field"功能的使用方法 在PyCharm中,**Introduce Field**(引入字段)是种代码重构功能,用于将局部变量提升为类的字段(成员变量),使其在整个类中可见和可用。以下是具体操作步骤和典型场景: --- #### 步骤详解 1. **选中目标变量** 在编辑器中,将光标定位到要转换的局部变量名上(例如`count = 0`)。 2. **触发重构菜单** - **快捷键**: - Windows/Linux: `Ctrl+Alt+F` - macOS: `Cmd+Alt+F` - **右键菜单**:右键点击变量 → 选择`Refactor` → `Introduce Field`。 3. **配置字段属性** 在弹出的对话框中可以设置: - **字段名称**(默认与原变量名相同) - **初始化位置**(构造函数、当前方法或静态初始化块) - **可见性修饰符**(`public`/`protected`/`private`) - 是否声明为`final`或`static`(根据需求选择)[^1]。 4. **确认并应用** PyCharm会自动将变量提升为字段,并调整代码结构。例如: ```python class Example: def __init__(self): self.count = 0 # 提升后的字段 def method(self): print(self.count) ``` --- #### 典型应用场景 1. **变量跨方法复用** 当发现某个局部变量需要在多个方法中使用时,提升为字段可避免重复定义。例如,在多个方法中共享配置参数。 2. **延长变量生命周期** 若局部变量需要在方法调用后保留状态(如计数器),提升为字段可确保其值持久化[^2]。 3. **减少参数传递** 避免在方法间频繁传递某个变量,直接通过字段访问。 --- #### 注意事项 - **初始化位置选择**:若选择在构造函数中初始化,PyCharm会自动在`__init__`方法中添加字段;若选择当前方法,则字段会在首次使用时初始化。 - **代码冲突检查**:若字段名与现有字段冲突,PyCharm会提示修改名称。 - **类型推断**:PyCharm会根据变量值自动推断字段类型(需开启类型提示)。 ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值