Android设计模式—观察者模式

装载请标明出处:http://77blogs.com/?p=279

 

观察者模式

说白了,就是一个对发生改变,所有依赖于它的对象也发生改变,这是一对多的关系。

比如对象A,对象B,对象C。B与C依赖于A,那么A发生改变,B与C也将发生改变。此时A是被观察者,B与C是观察者。

 

观察者模式又被称作发布/订阅模式,主要是为了让观察者与被观察者之间进行解耦。

 

UML图:

 

 角色说明:

Subject(抽象主题):被观察者的一个抽象类,它会把所有观察者的引用保存在一个集合里。抽象主题提供一个接口,可以增加和删除观察者对象。

ConcreteSubject(具体主题):具体的被观察者。当具体被观察者的状态发生改变的时候,会给每一个注册过的观察者发送通知。

Observer(抽象观察者):所有具体观察者的一个抽象类,为所有的具体观察者定义了一个接口:得到主题的通知时候更新自己。

ConcrereObserver(具体观察者):抽象观察者的具体实现。

 

我们看一下具体的例子:

上课铃声响起时候,老师与学生们的不同反应。

1、定义一个抽象主题:

该抽象主题定义了一些通用的方法,即具体主题里面需要实现的。

 

2、创建一个具体主题(上课铃声):

 

3、创建抽象观察者:

定义了所有具体观察者需要实现的方法,听到铃声后的行为

 

4、创建具体观察者:

 

6、实现:

 

7、结果:

 

到这里我们便实现了观察者模式。

 

应用场景

  • 当一个对象的改变需要通知其它对象改变时,而且它不知道具体有多少个对象有待改变时。
  • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁
  • 跨系统的消息交换场景,如消息队列、事件总线的处理机制。

优点

  • 解除观察者与主题之间的耦合。让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
  • 易于扩展,对同一主题新增观察者时无需修改原有代码。

 缺点

  • 依赖关系并未完全解除,抽象主题仍然依赖抽象观察者。
  • 使用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。
  • 可能会引起多余的数据通知。

JDK内部也内置了Observable(抽象被观察者),Observer(抽象观察者)这两个类,我们也可以直接拿来用,具体可以去看看源码。

Android中有很多地方也用到了观察者模式:
  • 点击事件
  • listView的刷新
  • 广播等等

onTouchEvent中,跟随手指滑动的view出现抖动

在这次实践中,它抖动得不正常,太不正常,太抖。

其实是我代码上出现了问题,记录一下。

 

我是怎么设置滑动的呢?

通过改变view的margin。

 

然而我在onTouchEvent中怎么控制它滑动的大小呢?

我获取的是event.getY()。

 

而event.getY()获取的是相对距离,也就是说坐标是相对于我们手指下的那个view来说的,是相对坐标。

而这个view又跟随着手指的滑动,通过改变margin的方式,margin一旦改变,那么坐标也跟着改变,于是getY就出现了异常。

所以我们不应该用getY()。

 

而是要用getRawY()。这个方法是相对于屏幕来说的,是绝对坐标。

Android与JS互相调用

转载请标明出处:http://77blogs.com/?p=281

android开发中有经常需要用到android与H5的交互,有必要学一下。

 

如下图

点击各个按钮代表的意思已经很明显,我就不多说了

 

1、先看一下布局:

 

2、编写html页面,并且放在main下的assets资源文件夹下,没有的话请自己创建

 

3、主程序:

custonAndroid为自定义字段,需要与下面代码中的字段一样。
<input type=”button” value=”Js调用Java代码” onclick=”window.customAndroid.jsCallAndroid()”/>
webView.addJavascriptInterface有安全漏洞(H5可以调用android本地的所有方法),所以4.2以上还需要使用注解来表明那些方法是js可以调用的,接下来会讲。

 

H5中这两个方法的作用

如上html中代码,向id为showmsg的h3大小标题中写入字符串

同上,只是显示的现象变成了android传过去的字符串了。

js调用android:

@JavascriptInterface也就是我上面说的注解,4.2以上必须使用这个注解,否则js无法调用本地的方法。本地方法的名称需要与H5中定义的一样。
实践证明,js调用的方法并不是在主线程中,而是在线程名为JavaBridge的线程中。

当我们点击下面webview中的按钮的时候便会执行这两个方法。

Android CHM文件阅读器

CHM格式是1998年微软推出的基于HTML文件特性的帮助文件系统。以替代早先的winHelp帮助系统,它也是一种超文本标识语言。在Windows 98中把CHM类型文件称作“已编译的HTML帮助文件”。

CHM用了ITS文件压缩格式,使得文件体积大大减小。事实上CHM文件不仅可以包含HTML文件,它还可以将任何所需要的文件编译进文件中。

 

我们通常下载软件后,文件夹里都会有这样的一个帮助文件,可以直接用浏览器打开,Windows上我们也可以直接将其转换为txt文件格式

假如F盘中有个CHM文件,路径为:F:\CHM\chm文件\汇编语言教程.chm

我们在该目录下打开命令行,输入:

hh -decompile F:\CHM\chm文件\huibian 汇编语言教程.chm,那么便会将该chm文件转换为txt,然后保存在huibian文件夹中。里面有图片文件,html文件,目录文件等等。

 

而我们如果想要在Android手机上做chm文件格式阅读器,解析其目录结构,那么我们便需要知道chm文件的具体格式。

具体请看:https://www.cnblogs.com/tangZH/p/11176995.html

 

好了,不多说了,项目在github上:https://github.com/TZHANHONG/anchmreader

CHM格式

转载请标明出处:http://77blogs.com/?p=283

CHM格式为CHM头,CHM头节,内容三部分组成。

 

总体格式图:

 

初始化头包含了CHM的相关信息。格式如下:

0000:char [4]’ITSF’
0004:DWORD 3(版本号)
0008:DWORD 文件头总长度,包括标题节表和
以下数据。
000C:DWORD 1(未知)
0010:DWORD 时间戳。
被认为是一个大端的DWORD,它似乎包含
秒(MSB)和小数秒(第二个字节)。
第三个和第四个字节可能包含更多的小数
位。最后一个字节中的4个最低有效位是
不变。
0014:DWORD 语言代码:英文 0X0409,简体中文:0X0804
0018:GUID {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC}
0028:GUID {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC}

 

头节记录。它是2个条目,每个条目的长度为10个字节,具有以下格式:

0000:QWORD 头节的偏移量
0008:QWORD 头节的长度

这两个头节分别指向头节0和头节1,根据这两个头节的偏移量便可以读到两个头节。

 

内容节偏移。在版本2文件中,此数据不存在,因为内容部分紧跟在目录之后:

0000:QWORD 内容节的偏移量

 

头节0。此部分包含文件的总大小,而不是其他内容。

0000:DWORD 0X01FE(未知)
0004:DWORD 0(未知)
0008:QWORD 文件大小
0010:DWORD 0(未知)
0014:DWORD 0(未知)

 

头节1。.chm文件的核心部分:它包含的文件和信息的目录。

目录头:

0000:char [4]’ITSP’
0004:DWORD 版本号1
0008:DWORD 目录头的长度
000C:DWORD 0X0a(未知)
0010:DWORD 0X1000目录块大小
0014:DWORD 快速引用块密度,通常为2。
0018:DWORD 索引树的深度
1:没有索引,2:一层索引,以此类推。
001C:DWORD 根索引块的块号,如果没有则为-1
(尽管至少有一个文件有0,尽管没有
index chunk,可能是个bug。)
0020:DWORD 第一个PMGL(列表)块的块号
0024:DWORD 最后一个PMGL(列表)块的块号
0028:DWORD -1(未知)
002C:DWORD 目录块数(总计)
0030:DWORD Windows语言ID
0034:GUID {5D02926A-212E-11D0-9DF9-00A0C922E6EC}
0044:DWORD 0X54(这又是长度),同0X1000
0048:DWORD -1(未知)
004C:DWORD -1(未知)
0050:DWORD -1(未知)

目录头之后紧跟着目录块,有两种目录块:列表块和索引块,如果只有一个列表快,那么将没有索引块。

列表块:

0000:char [4]’PMGL’
0004:DWORD 结尾处的自由空间和/或quickref区域的长度目录块
0008:DWORD 始终为0。
000C:DWORD 读取时上一个列表块的块号
顺序目录(如果这是第一个列表块,则为-1)
0010:DWORD 读取时下一个列表块的块号
顺序目录(如果这是最后一个列表块,则为-1)
0014:目录列表条目(到quickref区域)排序方式根据文件名; 排序不区分大小写。

quickref区域是从块的末尾向后写入。对于文件中的每n个条目存在一个quickref条目,其中n被计算为1 +(1 << quickref density)。因此,对于密度= 2,n = 5。

其格式从后到前为:

Chunklen-0002:整个数据块中的项数
Chunklen-0004:从0项到n项之间的偏移量
Chunklen-0006:从0项到2n项之间的偏移量
……

目录列表条目的格式如下:

ENCINT:名字长度
UTF-8:编码的名称(UTF-8编码)
ENCINT:内容部分
ENCINT:偏移量
ENCINT:长度

偏移量是从文件解压缩之后的正文段开始计算的。长度也指解压后的长度。

目录中表示的文件有两种:用户数据和格式相关文件。与格式相关的文件具有以“::”开头的名称,用户数据文件的名称以“/”开头。

 

 

索引块:

0000:char [4]’PMGI’
0004:DWORD 目录块末尾的quickref / free(空余)区域的长度
0008:目录索引项

PMGI中的quickref区域与PMGL中的相同,当索引块的层次较高时,将不再存储数据块号而是存储下一层的索引号。

目录索引项的格式如下:

ENCINT:名字长度
UTF-8:名称(UTF-8编码)
ENCINT:以此名称开始的列表块的块号

 

内容:

在版本3中,内容通常紧跟在文件头之后,并且位于文件头表之后的DWORD指示的位置。在版本2中,内容紧跟在文件头之后。目录中的所有内容部分0位置都与该点相关。其他内容部分存储在内容部分0中。而且所有此文件夹中的正文部分的第0段都放在这个位置上。其他的正文段都在这个正文段里面。

 

名单列表文件

在内容部分0和目录中存在名为“:: DataSpace / NameList”的文件。此文件包含所有内容部分的名称。格式如下:

0000:WORD 文件长度,用文字表示
0002:WORD 文件中的条目数

每个条目:
0000:WORD 单词中的名称长度,不包括终止null
0002:WORD 。以0表示所有entry的结束。名称的编码类似于UFT-16。 段的名称目前为止只有两种,Uncompressed和MSCompressed,分别表示未压缩文件和Microsoft LZX压缩算法压缩的文件。
xxxx:WORD 0

Section_data:
对于段落编号不为0的段落,还有另一个文件:DataSpace / Storage / / Content,它存储段落的压缩信息。 因此,在解析非零段落时,需要两个步骤。 第一步是获取第,并获取段落名称。 第二步是使用段落名称查找相应的段落。

 

其余与格式相关的文件: ::DataSpace/Storage//ControlData

共0x20个字节,存储关于压缩的信息:

参考链接:

https://wenku.baidu.com/view/c2f81e21aaea998fcc220e22.html?pn=1

http://www.pythonclub.org/python-files/chm-format

从一个git仓库拷贝到另一个git仓库

利用git从一个仓库拷贝一个项目到另一个仓库,并且log也能够一起过去。

 

1、从原地址克隆一份裸版本库,比如原本托管于 GitHub。

git clone --bare http://github....(原始仓库地址)

 

2、进入克隆下来的目录

cd project.git(project即为你的项目名称)

 

3、以镜像推送的方式上传代码到新的仓库地址。

git push –mirror http://…(目标仓库地址)

Android Studio撤销与SVN或者Git的关联

为何会记录这一个问题,主要是在做项目的过程中出现了一个奇怪的现象,就是直接在文件目录下使用svn上传文件的话,可以看到该目录是与SVN相关联的,可是到了用Android Studio上传代码的时候却发现Android Studio是与Git相关联的。

最终发现可以使用以下方法解决:

在Android Studio上使用Project模式查看代码,在.idea文件夹,在该文件夹下找到vcs.xml。

打开发现如下:

我当时在<mapping directory=”” vcs=”svn” />下面还有很多代码,有一个句是 vcs=”Git”,问题就是出在这里,我把下面的都删了,只保留上面图片的代码就OK了,当然,如果想让Android Studio与SVN取消关联,那么只要将vcs = “svn”改为vcs=“”就OK了。

 

SVN拉取后撤销,恢复未拉取之前的状态

在做项目的时候,一不小心将服务器上的代码覆盖了本地的代码,本来可以使用log查看svn上的历史列表,然后选中某个选项,右键,点击revert to this vision来使代码恢复到任意一个版本。

可是关键是本地的代码还没有上传到svn上,也就是说我们要恢复的代码svn上还没有,那么怎么办呢?

1、右键选中你的项目,按照下图所示选中本地历史:

2、打开历史界面后便可以看到你本地的修改历史记录:

3、选中你想恢复到的某个记录,右键:

点击Revert就可以了