2016年10月

设计模式--观察者模式

聪明的人不一定有智慧,智慧的人一定是聪明的。自以为小聪明是非常可怕的,勿以恶小而为之,勿以善小而不为。
最近在看一个蓝牙打印机的小例子,里面提到了观察者设计模式,这里复习一下。

说明

观察者模式主要用于1:N对象的通知.
当一个对象状态发生变化时,通知其他一系列对象,令他们做出响应.生活中这样的例子有很多,比如手机厂商发布了一个新版本,所有订阅这个消息的手机都能得到新版本的提示.下面就来实现一下观察者模式.

- 阅读剩余部分 -

设计模式重新学习

设计模式重新学习

这两天看吴军老师的硅谷来信中一片文章又想到了一些。在从孙子兵法和战争论说起中,谈到了孙武的孙子兵法和克劳塞维兹的战争论两本书,讲了战争中的战略和战争中可操作性的观点,其中孙子兵法不教人具体的作战方法,而战争论学过之后可能军事素养就会提高很多。后面还提到中国人思维方式和西方人的区别,中国人讲求悟性,什么事情不会讲的很清楚(人与人的交往中,也是这样,有什么往往不会主动提出来,让你自己去悟(╯▽╰));西方文做事讲求可操作性,喜欢寻求一些方法,所以看到工业化时代就是可操作性的产物,各种生产线提高生产效率。
想到了设计模式方面的内容记录在下

- 阅读剩余部分 -

Android NFC开发教程(下)

1.Mifare S50 卡片介绍

Mifare s50工作频率为13.56MHz,数据传输速度在106kbit/s。容量共1k字节,分为16个扇区,每个扇区分为4块,每块16个字节。用户可以自定义每一个存储器块的访问条件,数据可以保持10年,读写10万次。智能的反冲突功能允许统一工作区内有不止一张卡同时工作。反冲突算法每次只能选择一张卡,确保对选中的卡正确操作而且同一区域内的其他卡不会破坏数据。
Mifare保密级别很高,需要经过3轮确认。a)读写装置(rwd)指定要访问的区并选择秘钥A或密钥B,b)卡从区尾读出密钥和访问条件,然后卡发送一个随机数到读写装置(第一轮),c)读写装置用密钥和附加输入计算响应,然后,将响应和读写装置的随机询问一起发送到卡中(第二轮),d)卡用自己的询问和读写装置的响应相比较确认RWD的响应。然后卡计算询问的响应并发送出去(第三轮),e)rwd用自己的询问和卡的响应相比确认卡的响应。

上图是存储方式。厂商段存储在第一个扇区的第一个数据段,包含了IC厂商的数据。不能随便写。所有的区包含3个块(每块16个字节)保存数据(扇区0两个可以保存数据)。在执行任何存储器操作前都需要先验证秘钥,确认之后可以可以执行读、写、减、增、恢复、传送操作。每个块都有一个块尾,包括密钥A和密钥B和访问这个扇区中四个块的条件(保存在第6-9个字节)。访问位可以指出数据段的类型,如果不需要密钥B,那么块3的最后六个字节也可以当做数据字节。总结就是块3分成3部分,密钥A(0-5)、访问控制(6-9)、密钥B(10-15)。

基础的知识知道上面这一些,下面主要进入如何读写。

2.Android MifareClassic介绍

MifareClassic类是android提供的操作Mifare卡的主要类。具体的API函数在MifareClassic
KEY_DEFAULT:获取默认的密钥
authenticateSectorWithKeyA(int sectorIndex,byte[] key):用密钥A验证,返回boolean。拿到新的卡片一般可以直接调用authenticateSectorWithKeyA(5,mifareClassic.KEY_DEFAULT)可以验证第五个扇区,返回true。
blockToSector(int blockIndex):返回块所属的扇区
connect():连接,在操作卡片之前需要先进行连接,对应的就是close,一般放在try catch finally中。
get(Tag tag):静态方法,返回一个MifareClassic实例,mifarClassic = MifareClassic.get(tagFromIntent);
readBlock(int blockIndex):读块的内容,返回byte[]
writeBlock(int blockIndex,byte[] data):写。

3. 主要看代码

声明几个用到的变量

    //当前mifare卡
    private MifareClassic mifarClassic;
    //NFC适配器
    private NfcAdapter mNfcAdapter;
    //Tag标签
    private Tag tagFromIntent;

onCreate方法中获取当前的NfcAdapter

    mNfcAdapter = NfcAdapter.getDefaultAdapter(this);

onNewIntent中对保存当前卡片和tag

    tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    //得到当前卡片
    mifarClassic = MifareClassic.get(tagFromIntent);

基础工作完成,看方法,(读就是先读出来,然后变为String),这里主要看个人的需求,不同的需求代码可能不同。但基本的逻辑是:

  1. String类型的数据变为byte[]

    byte[] dataBytes = data.getBytes();
  1. 调用connect方法连接,调用authenticateSectorWithKeyA验证,调用writeBlock方法写入数据,最后调用close方法断开连接。

这里一个块中16个字节,只能存5个汉字,可以将Byte[]分别存入几个块中,读的时候都出来,然后再拼到一块就可以了。

4. 参考的网址

  1. Mifare 1k S50的简单探讨与研究

  2. Intel的文章,值得一看

  3. 官方MifareClassic

  4. 也可以看一看

  5. 有一本,网上找到PDF版本,写的很详细。

  6. 从网上也可以找到一些Demo,可以拿来运行。

Android NFC开发教程(上)

最近做了一个android平台关于NFC的小项目,在此记录一下。

1. 什么是NFC和RFID

NFC(Near Filed Communication)翻译过来就是近场通信。结合了非接触式感应以及无线连接技术,作用于13.56MHZ频带,传输距离大约10cm左右。
RFID(radio Frequency Identification)翻译过来是射频识别或无线射频识别常被成为感应式电子镜片或近接卡、感应卡、非接触卡、电子标签等等。RFID是一种通信技术,可以通过无线电信号识别特定目标并读写相关数据,而无需识别系统与特定目标之间建立机械或光学接触。常用的频段分为如下四种,低频(30-300KHz)高频(3-30MHz)超高频(300MHz-3GHz)微波(2.45GHz以上),RFID的有点包括体积小、成本低廉、不易被仿制、可存储大量数据、快速非接触式读取方式、减少人工手动错误确保品质降低成本等等。一套完整的RFID系统由Reader/transceiver(读取器)Transponder/RF Tag(感应器/射频标签)Antenna/coil(天线)3部分组成。工作原理是Reader发射特定频率的无线电波能量给Transponder,用以驱动Transponder电路将内部的ID Code送出,此时,reader便会接收此ID Code。Transponder的特殊性在于免用电池、免接触、免刷卡,且晶体密码为世界唯一、无法复制、安全性高,寿命长。
NFCRFID技术的比较
NFC是基于RFID理论提出的,可以与现在的智能卡系统兼容。相同点是:两者都是通过频谱中无线频率的电磁感应耦合方式传递信息;两者都工作在13.56MHz频带。不同点是:NFC将非接触读卡器、非接触卡和点对点功能整合进一块单芯片,而RFID必须由阅读器和标签组成。目前的NFC手机内置NFC芯片,组成RFID模块的一部分,可以当做RFID无源标签使用,支付费用;RFID只能实现新的读取及判定,而NFC技术强调的是信息交互;NFC传输范围比RFID小,相比之下,NFC具有距离近、带宽高、能耗低等特点;NFC是一种近距离的通信方式,更加安全。

NFC根据应用的不同采用三种不同的工作模式:读写模式、P2P模式、卡模拟模式。

NFC标准规范:ISO14443MifareNFCIP-1等。ISO1443是非接触IC卡标准,该标准有JTC旗下SC17的WG8开发。这里主要使用了Mifare卡,mifare卡是恩智浦半导体(NXP)拥有的商标之一,Mifare卡已成为全球大多数非接触式智能卡的技术选择,并且是自动收费领域最成功的平台。Mifare卡是Philips Electronics(NXP的前身)所拥有的13.56MHz非接触性辨识技术。

NDEF概述:为了实现NFC标签、NFC设备以及NFC设备之间通信,NFC论坛定义了被称为NFC数据交互格式(NDEF)的通用数据格式。NDEF使NFC得各种功能更加容易的使用支持的标签类型进行数据传输,而不再关心具体是和那种标签通信。NDEF是轻量级的紧凑的二进制格式,可带有URL、vCard、和NFC定义的各种数据类型。NDEF交换的信息由一系列记录(Record)组成,每条记录包含一个有效载荷,记录信息可以是URL、MIME媒体和NFC自定义的数据类型。具体组成如下所示:

2. Android 中 NFC开发

与开发相关的类都在Android.nfc包中。
NfcManager:NfcAdapter的管理器,一般情况下通过调用静态方法getDefaultAdapter(context)来获取系统默认的NfcAdaper
NfcAdatpter:表示本设备的NFC适配器,可以定义Intent请求来将系统检测到的Tags提醒发送到你的Activity。在前台调度系统和标签调度系统时会用到
NdefMessageNdefRecord:android方面关于Ndef格式封装的类
Tag:表示一个被动的NFC目标,一般通过intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);来获得

Android.nfc.tech中放了一些不同类型的卡。比如nfcAIsoDepNdefFormatableMifareClassic等,这个在添加类型的时候会用到。

3. 动手去做

  1. 需要用到NFC权限,在Android manifest文件中添加

    <uses-permission android:name = "android.permission.NFC"/>
  1. NFC并不是所有SDK版本都支持,这个现在现在应该不需要设置了。一般android2.X应该也没了

    <uses-sdk android:minSdkVersion = "10"/>
  1. uses-feature 元素定义,这样只有有NFC的手机才能搜索到你的应用

    <uses-feature android:name = "android.hardware.nfc" android:required = "true"/>
  1. manifest文件中的改动就是这些。有两种获得nfc标签通知的方式:前台调度系统标签调度系统

4.1 前台调度系统
onCreate方法中:

    //region 前台调度系统
        pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags
                (Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        //Intent过滤器,在收到指定类型的通知时触发
        try {
            intentFileters = new IntentFilter[]{new IntentFilter(NfcAdapter
                    .ACTION_TECH_DISCOVERED, "*/*")};

        } catch (IntentFilter.MalformedMimeTypeException e) {
            e.printStackTrace();
        }
        //支持的卡片的类型,第一次没有成功就是因为卡片类型写的错误
        techListsArray = new String[][]{{NfcA.class.getName()}, {NdefFormatable.class.getName()},
                {MifareClassic.class.getName()}};
        //endregion

同时需要重写onPauseonResume方法,实现onNewIntent毁掉方法来处理扫描到的NFC标签的数据

@Override
    protected void onPause() {
        super.onPause();
        if (mNfcAdapter != null) {
            mNfcAdapter.disableForegroundDispatch(this);
        }
        if (sm != null) {
            sm.stopScan();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mNfcAdapter != null) {
            mNfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFileters, techListsArray);
        }    
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        //得到当前卡片
        mifarClassic = MifareClassic.get(tagFromIntent);
    }

4.2 标签调度系统

NFC标签调度系统是一种通过预先定义好的Tag或NDEF消息来启动应用程序的机制,扫描一个NFC tag时,如果Intent中注册了对应的应用程序,那么在处理该Tag消息时就会启动该应用。当存在多个可以处理Tag的应用时,就出弹出多个让用户选择。比如打开图片时,如果安装其他的图片软件就会让你选择。
标签调度系统定义了三种Intent对象,从高到低的优先级分别是`ACITON_NDEF_DESCOVERED`、`ACTION_TECH_DISCOVERED`、`ACTION_TAB_DISCOVERED`,调度系统看下图:

使用起来就是在Manifest文件中,activity节点下添加类似下面的内容

    <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />

                <data
                    android:host="*"
                    android:pathPrefix=""
                    android:scheme="http" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED" />
            </intent-filter>

            <meta-data
                android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />

            <intent-filter>
                <action android:name="android.nfc.action.TAG_DISCOVERED" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

还需要在XML文件夹下面添加一个nfc_tech_filter文件指定能接收的标签类型

    <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcF</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcV</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NdefFormatable</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.IsoDep</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.MifareClassic</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.MifareUltralight</tech>
    </tech-list>
</resources>

今天就先写到这里,明天更新读写数据一块。

学习总是要付出成本的

这是个最好的时代,互联网让学习的成本变得很低,你可以在网上找到你想学习的一切,不必再向以前一样去图书馆浩瀚的书本中去找,不好意思向人请教。现在所有的一切只需要轻轻一点,谷歌和百度都能告诉你想要的答案,不行了还可以在知乎、百度知道上问,总有那么几个人愿意给你回答问题。似乎学习不再那么重要,什么时候我们只要学会搜就可以了,真的是这样吗?
这两天给自己买了一点书,从淘宝买了一些图片、音频资料,想回归以前那样,静下心来去学习一点知识。以前有很多大师,他们读过了相当多的资料,对他专业的所有知识都了如指掌,他可以向给你讲历史一样把原理、中间的发展、为什么到了现在这样给你讲出来,顺便可能还能给你指点一下将来可能变得怎么样,现在少了。因为人们变得越来越懒,对结果变得越来越看重,过程便不是那么重要。什么时候我只要调用一个API函数就能获得我想要的结果,但并不知道中间的过程是怎么实现的,可能问题稍微变化一点,又要去灰头土脸的找API了。以前我也感觉我做过不少的东西,算是一个熟练工?但我自己清楚,很多基础性的原理没有找我牢固,很多时候我只是找问题的答案的本事比其他人强一点而已。
前几天看了吴军老师《硅谷来信》的一篇文章,讲了伪工作者的例子,讲的是有那么一些人,每天都很忙但就是没有产出。有的时候我也是伪工作者,每天都在写程序,但其实就是一些重复的工作。我应该做的是真正找到最重要的工作,并优先完成他们,并对所学习到的知识进行总结。一个人的成长总是和自己的输出成正比的,多多总结自己学到的知识,点滴积累汇成河流。

现在是一个持续学习的时代,可能一年的时间不学习就跟不上时代的发展,只有高质量的输入才有高质量的输出,在业余的时间我想让自己多多看看书,接触优秀的人,读优秀的文章,我想知道那些人都是怎么思考问题的。这个时代,最大的投资是为自己投资,我愿意为我自己的价值买单,不管它是一台单反、一台笔记本、或是简单的8.8元的优秀集锦,我都愿意为此去付出。希望我能在将来的某一天感恩自己现在的付出。

自勉