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中的按钮的时候便会执行这两个方法。

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

Android中Parcelable的使用

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

Parcelable与Serializable

Serializable是Java为我们提供的一个标准化的序列化接口。

Parcelable是Android为我们提供的序列化的接口。

 


 

对比:

1、Parcelable相对于Serializable的使用相对复杂一些。

2、Parcelable的效率相对Serializable也高很多。

3、Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable在外界有变化的情况下不能很好的保证数据的持续性。尽管Serializable效率低点,但此时还是建议使用Serializable。存储到设备或者网络传输上选择Serializable。

 


 

序列化与反序列化

序列化:将对象转换为可以传输的二进制流(二进制序列)的过程,这样我们就可以通过序列化,转化为可以在网络传输或者保存到本地的流(序列),从而进行传输数据 。

反序列化:从二进制流(序列)转化为对象的过程。

 

简单使用:

进行Android开发的时候,无法将对象的引用传给Activities或者Fragments,我们需要将这些对象放到一个Intent或者Bundle里面,然后再传递。简单看一下:

1、定义Book类,实现Parcelable接口。

 

writeToParcel:序列化过程

Creator与protected Book(Parcel in)配合实现反序列化,转换为对象。

 

注意:类中有多个String或者其它相同对象的话,那么writeToParcel中writeString的顺序是怎么样的,protected Book(Parcel in) {}中readString的顺序就得是怎么样的。

 

2、mainActivity中:

 

3、另一个Activity获取:

 

输出:

 


 

Book类里面有其它对象:

如果Book类里面有其他对象(比如实体类Data)的话,那么Data也需要实现Parcelable接口,用法与上面的Book类一样。

writeToParcel里面需要写上:dest.writeParcelable(data, 0);

protected Book(Parcel in) {}里面需要写上data = in.readParcelable(Data.class.getClassLoader());

 


参考:https://www.jianshu.com/p/df35baa91541

zipalign的使用

zipalign


 

是一个存档对齐工具,可为Android应用程序(.apk)文件提供重要的优化。目的是确保所有未压缩数据以相对于文件开头的特定对齐开始。具体来说,它会导致.apk中的所有未压缩数据(如图像或原始文件)在4字节边界上对齐。这允许直接访问所有部分,mmap()即使它们包含具有对齐限制的二进制数据。其好处是能够减少应用程序的RAM内存资源消耗。

在将.apk文件分发给最终用户之前,应始终使用此工具来对齐.apk文件。Android构建工具可以为您处理此问题。将Eclipse与ADT插件一起使用时,导出向导会在您使用私钥对其进行签名后自动为.apk设置zipalign。在使用Ant编译应用程序时使用的构建脚本也将对.apk进行zipalign,只要您提供了密钥库的路径和项目ant.properties文件中的密钥别名,以便构建工具可以首先对包进行签名。

警告:只有在使用您的私钥对.apk文件进行签名才能执行zipalign 。如果在签名之前执行zipalign,则签名过程将撤消对齐。此外,不要对对齐的包进行更改。对存档的更改(例如重命名或删除条目)可能会破坏已修改条目和所有后续条目的对齐。添加到“对齐”存档的任何文件都不会对齐。

通过更改zip本地文件头部分中“额外”字段的大小来进行调整。“额外”字段中的现有数据可以通过该过程改变。

有关如何在构建应用程序时使用zipalign的更多信息,请阅读签署您的应用程序

 


 

1、对infile.apk进行对齐并且保存为outfile.apk

      zipalign [-f] [-v] infile.apk outfile.apk

 

2、检查apk是否进行了对齐

zipalign c v  existing.apk

 


 

infile.apk表示需要存档对齐的apk
outfile.apk表示存档对齐后的apk
alignment:表示指定的对应字节数,是一个整数且必须指定为4。

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

原文:google开发文档:http://www.android-doc.com/tools/help/zipalign.html

shrinkResources去除无用资源原理

开启shrinkResources后,打包过程会新增task transformClassesWithShrinkResFor{variant},gradle1.5之后只需要注册一个tranform就会产生一个对应的task,查看源码发现对应的tranfrom在com.android.build.gradle.internal.transforms.ShrinkResourcesTransform,此类中调用com.android.build.gradle.tasks.ResourceUsageAnalyzer的analyze方法进行分析无用资源。

 

ResourceUsageAnalyzer:

该类的开头有这么一段话:

我翻译一下这段:

这个类负责搜索一颗gradle构建树(在合并资源,编译,压缩已经完成之后,最终的apk组装之前),这颗构建树确定了那些资源是未使用的,并将其删除。

它通过检查做到这一点:

  • 合并的清单,用于查找根资源引用(例如启动图标)
  • 合并的R类(查找分配给资源的实际整数常量)
  • 混淆映射文件(找到原始名称到混淆后短名称的一个映射)
  • 合并的资源(用于查找哪些资源引用其他资源,例如包括其他other drawables的drawable state lists,或包括其他布局的布局,或引用其他drawables的styles,或包括布局文件的菜单项等)
  • 缩小的输出类(在代码中查找实际可访问的资源引用)

所有的这些,构建了一个引用图,并基于根引用(例如来自清单与剩余代码),它计算出了在app中哪些资源是实际可达的,然后将任何无法访问的内容标记为删除。

如果文件R.type.name被引用(非最终资源引用,例如在库中),或者在代码中引用相应的int值,我们通过ASM查看输出的代码来检查这一点。有一个复杂的问题是代码可以通过Resources#getIdentifier(String,String,String),通过传递资源的名称去查查找资源,为了处理这种情况,我们使用ClassVisitor来查看是否有对特定Resources#getIdentifier方法的任何调用如果没有,很好,使用分析是完全准确的。如果我们找到一个,我们检查 所有在应用程序中的任何位置找到的字符串常量,并查看是否有看起来有关。例如,如果我们找到字符串“string / foo”或“my.pkg:string / foo”,我们将标记名为foo的字符串资源(如果有)作为可能使用的字符串资源。

 

 一:

 

 SdkConstants.FN_RESOURCE_CLASS = R.java

可以看出它找到的是R.java文件,然后调用parseResourceClass(file);方法,将R.java中的资源都标记为可达,加入表中。

 

recordMapping(mProguardMapping)

解析混淆文件,将现在的把映射存于表中

 

 

 

recordManifestUsages(mMergedManifest);

分析Manifest文件,将找到的引用标记为可达,例如:启动图标

 

AndResGuard的使用

AndResGuard是何物?

AndResGuard是一个帮助你缩小APK大小的工具,他的原理类似Java Proguard,但是只针对资源。他会将原本冗长的资源路径变短,例如将res/drawable/wechat变为r/d/a。一般用于给apk瘦身。

具体请看:

https://github.com/shwenzhang/AndResGuard/blob/master/README.zh-cn.md

我们解压缩apk后可以看到这个文件

resources.arsc

这个文件是编译后的二进制资源文件,里面是id-name-value的一个map,即id与资源名称的一个映射,如:

AndResGuard。它将资源的名称进行了混淆,所以可以用它对resources.arsc进行优化,只是具体优化效果与编码方式、id数量、平均减少命名长度有关。

例如:

表一:

 

表二:

表二是经过优化后的,我们一眼就可以知道表2肯定比表1存储的字符要小,所以整个文件的大小肯定也要小一些,因此就达到了瘦身的效果。

 

总的来说它可以将res/drawable/activity_advanced_setting_for_test变为r/d/a,达到混淆与减少体积的效果,也增加了反编译后阅读代码的难度,安全性高

 

那么怎么使用呢?

第一种方式:AS集成

1、在项目的build.gradle中添加依赖如下:

 

 

2、在app下建立gradle文件and_res_guard.gradle,里面的内容如下:

其中whiteList(白名单)中指定不需要进行混淆的资源路径规则,所有使用getIdentifier访问的资源都需要加入白名单,因为使用这种方式访问的资源,在代码中写死了id,比如:
int mipmapId = getResources().getIdentifier(“ic_launcher”, “mipmap”, getPackageName());,如果不加入白名单的话会报找不到资源的错误。
 
还有一些第三方SDK,因为有些SDK的代码中也用这种方式引用到对应的资源文件,如果对其进行混淆,会导致找不到对应资源文件,出现crash,所以不能对其资源文件进行混淆。像友盟这种喜欢用反射获取资源的SDK就是一个坑(友盟的SDK就是坑王)!对于app启动图标这样的icon可以不做混淆,推荐将其放入白名单里

可以在white_list.md查看更多sdk的白名单配置,也欢迎大家PR自己的白名单

 

compressFilePattern和compressFilePattern中的通配符支持? + *


白名单机制只作用于资源的specsName,不会keep住资源的路径。如果想keep住资源原有的物理路径,可以使用mappingFile。 例如我想keep住icon所有folder,可以在mappingFile指向的文件添加:

 

注意!

  1. 如果不是对APK size有极致的需求,请不要把resource.asrc添加进compressFilePattern. (#84 #233)
  2. 对于发布于Google Play的APP,建议不要使用7Zip压缩,因为这个会导致Google Play的优化Patch算法失效. (#233)

 

3、在app的build.gradle中引入:

编译一下便可以在gradle的task任务列表里看到混淆任务

使用:

双击对应的task可以编译debug包,release包。混淆后的apk生成在build/output/apk/AndResGuard_*目录中,默认会生成4种apk,我们选择签名、压缩、对齐后的apk即可,后缀名是*_signed_7zip_aligned.apk

 

第二种方式:指令集成

 1、下载AndResGuard过程:

https://github.com/shwenzhang/AndResGuard

 

 

2、解压,可以看到这个文件,进入这个文件

 

文件夹里面有这么一些东西:

 

文件作用:

jar包:用来执行命令的时候使用

build_apk.bat :windows执行脚本

build_apk.sh:linux执行脚本,由于我使用的是windows系统,所以就。

自定义PopupWindow

PopupWindow,一个弹出窗口控件,可以用来显示任意View,而且会浮动在当前activity的顶部

自定义PopupWindow。


1.extends PopupWindow

2.构造方法中可以进行一些属性设置


setContentView(View convertView); //设置popupWindow显示的View

getContentView(); //获取popupWindow显示的view

setWidth(mWith); //设置popupWindow的宽度

setHeight(mHeight); //设置popupWindow的高度

设置宽高,也可以在构造方法那里指定好宽高, 除了可以写具体的值,还可以用WRAP_CONTENT或MATCH_PARENT, popupWindow的width和height属性直接和第一层View相对应。

setAnimationStyle(R.style.PopupAnimation); //设置弹出动画

setFocusable(true);

设置焦点,PopupWindow弹出后,所有的触屏和物理按键都由PopupWindows 处理。其他任何事件的响应都必须发生在PopupWindow消失之后,(home 等系统层面的事件除外)。 比如这样一个PopupWindow出现的时候,按back键首先是让PopupWindow消失,第二次按才是退出 activity,准确的说是想退出activity你得首先让PopupWindow消失,因为不并是任何情况下按back PopupWindow都会消失,必须在PopupWindow设置了背景的情况下。

而setFocusable(false); //PopUpWindow只是一个浮现在当前界面上的view而已,不影响当前界面的任何操作,是一个没有存在感的东西

一般情况下setFocusable(true);

setTouchable(true); // 设置popupwindow可点击


要让点击PopupWindow之外的地方PopupWindow消失:

1.setOutsideTouchable(true);

2.调用setBackgroundDrawable(new BitmapDrawable()); 设置背景,为了不影响样式,这个背景是空的。

除此之外,还可以这样写,setBackgroundDrawable(new ColorDrawable(0x00000000));背景不空,但是完全透明

经过实际检验,只要设置了背景,不管有没有设置setOutsideTouchable(true);即使设置了setOutsideTouchable(false);一样能够实现点击PopupWindow之外的地方PopupWindow消失,有点奇葩,不过为了保险起见,还是加上setOutsideTouchable(true);比较好。


PopupWindow还有一个方法,也是用来设置点击PopupWindow外部使得PopupWindow消失的,不过仅仅是实现这个方法是不行的,一样要设置背景才起作用。可是当设置了背景的时候,下面这个方法不管有没有用都能够实现点击PopupWindow外部使得PopupWindow消失,也是够醉。


设置PopupWindow的弹出位置

popupWindow = new SelectPicPopupWindow(参数);

popupWindow.showAtLocation(findViewById(R.id.settings_layout),
Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 0);

 //在这里findViewById(R.id.settings_layout)是当前界面的id。


设置了PopupWindow的background,点击Back键或者点击弹窗的外部区域,弹窗就会dismiss.相反,如果不设置PopupWindow的background,那么点击back键和点击弹窗的外部区域,弹窗是不会消失的.

如果我想要一个效果,点击外部区域,弹窗不消失,但是点击事件会向下面的activity传递,比如下面是一个WebView,我想点击里面的链接等.

然后调用setPopupWindowTouchModal(popupWindow, false);就可以了。


不过还有要注意的是:

1.设置了setHeight();假如设置的高度小于屏幕的高,那么透明的那一部分是不属于PopupWindow的。

2.设置setContentView(View v);由于v里面的组件在布局文件里并没有占满整个屏幕,例如只是放在了底部,使得弹出PopupWindow上部分出现了透明,这个透明部分还是属于PopupWindow的,那么要想做到点击透明部分使得PopupWindow消失,又该怎么做呢?

这个也不难,答案如下:

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

自动显示隐藏布局的listView

借助View的OnTouchListener接口来监听listView的滑动,通过比较与上次坐标的大小,判断滑动方向,并通过滑动方向来判断是否需显示或者隐藏对应的布局,并且带有动画效果。

1.自动显示隐藏Toolbar

首先给listView增加一个HeaderView,避免第一个Item被Toolbar遮挡。

//R.dimen.abc_action_bar_default_height_material为系统ActionBar的高度

定义一个mTouchSlop变量,获取系统认为的最低滑动距离

属性动画

//上面为位移还有透明度属性动画

使用的时候theme要用NoActionBar的,不然会引起冲突。同时引入编译

2.当要隐藏和显示的组件不是toolbar,而是我们自定义的布局myView时,需要注意一些点,

(1) 布局要用相对布局,让我们自定义的布局悬浮在listView上方。

(2)避免第一个Item被myView遮挡,给listView增加一个HeaderView,此时需要测量myView的高度,要用下面这种方法,把任务post到UI线程中,不然执行会出错。

其他的与toolbar一样

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