ZAdapter3断头吸附效果

几种方案是选择

  • 外层一个显示的断头和内部的布局一样,但不是同一个 因为涉及到选择状态和 横向滚动 而导致的复杂性 放弃!

  • 自定义recyclerView布局,这样解决了是同一个的view的问题。但是因为getTop而导致 刷新监听的不兼容 放弃!

  • 既然想要用同一个View的话可以用李代桃僵的方式去实现,既用一个空view去代替RecyclerView的Itemview站位。然后吧itemView显示在断头上即可!

效果图

Rxjava2总结

Rxjava2基础认知

  • 形式正确的有限Observable
    调用观察者的onCompleted正好一次或者它的onError正好一次,而且此后不能再调用观察者的任何其它方法。如果onComplete 或者 onError 走任何一个 都会 主动解除订阅关系;

    • 如果解除订阅关系以后在发射 onError 则会 报错;而发射onComplete则不会。
    • 注意解除订阅关系 还是可以发射 onNext
  • Disposable类:

    • dispose():主动解除订阅
    • isDisposed():查询是否解除订阅 true 代表 已经解除订阅
  • CompositeDisposable类:可以快速解除所有添加的Disposable类
    每当我们得到一个Disposable时就调用CompositeDisposable.add()将它添加到容器中, 在退出的时候, 调用CompositeDisposable.clear() 即可快速解除.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
CompositeDisposable compositeDisposable=new CompositeDisposable();
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onComplete();或者 emitter.onError(new Throwable("O__O "));
}
}).subscribe(new Observer<Integer>() {

private Disposable mDisposable;
@Override
public void onSubscribe(Disposable d) {
<!-- 订阅 -->
mDisposable = d;
<!-- 添加到容器中 -->
compositeDisposable.add(d);
}

@Override
public void onNext(Integer value) {
<!-- 判断mDisposable.isDisposed() 如果解除了则不需要处理 -->
}

@Override
public void onError(Throwable e) {
}

@Override
public void onComplete() {
}
});
<!-- 解除所有订阅者 -->
compositeDisposable.clear();

Recycler下Adapter的HeaderFooter多个添加方式

Header Footer添加的问题

因为要撸库 所有参考了很多adapter库的代码 但是都发现一个问题 star前5的的Recycler Adapter库的Header Footer要么只能添加一次(在这里面添加删除view),要么添加之后删除会错位

为什么会错位呢?因为他们用List mHeaderViews的position 映射后当getType的值。
当删除一个headView的时候postion则会错位。如果做这样的以一个操作 删除头部然后添加另一个头部。布局不同。那么会发现视图根本不会改变还是原来的头部布局。因为getType的没变的缘故。
当然可以通过其他的方式 让position不错位。具体可看 ZAdapter3的1.0分支。但是还是有问题 滚动动画会出现奇怪的问题。所以弃用!

怎么改变这一现状能让添加头部和尾部如同listView一样呢。参考了ListView发现所有类型都是一个;而后我有想到 viewHold的机制其实就是复用。那我给头部和尾部都添加一个空的FrameLayout。然后在bindView是头尾的时候 removeAllViews,和addView(header/footer) 不就可以了吗?

这里我给出关键性代码:

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
 public static final int ITEM_VIEW_TYPE_HEADER_OR_FOOTER = -3;

//Limit one thousand
private List<ViewDelegates> mHeaderViews = new ArrayList<>();
private List<ViewDelegates> mFooterViews = new ArrayList<>();


@Override
public Holder onCreateViewHolder(final ViewGroup parent, int viewType) {
if (viewType == ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
QuickConfig.e("onCreateViewHolder header or footer :" + viewType);
return new Holder(setFullspan(LayoutInflater.from(context)
.inflate(R.layout.base_vp, mRecyclerView, false)));
}
...
}
/**
* @return layoutid
* 因为getItemViewType不同 导致 头部底部view不会被重用!
*/
@Override
public int getItemViewType(int position) {
...
if (position >= getHeaderViewsCount() && position < getHeaderViewsCount() + data.size()) {
QuickConfig.e("getItemViewType views:" + position);
int result = getItemViewType2(getDataPosition(position));
if (result == ITEM_VIEW_TYPE_HEADER_OR_FOOTER)
throw new IllegalStateException("layoutType is must not be" + ITEM_VIEW_TYPE_HEADER_OR_FOOTER);
return result;
} else {
QuickConfig.e("getItemViewType healder or footer:" + position);
return ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
}
}

@Override
public void onBindViewHolder(Holder holder, int position) {
if (isEmptyData())
return;
if (position >= mHeaderViews.size() && position < mHeaderViews.size() + data.size()) {
if (holder.wrapper != null)
holder.wrapper.getViewDelegates().fillData(
position, data.get(getDataPosition(position)),
holder.helper);
} else if (position < mHeaderViews.size()) {
QuickConfig.e("bind header position:" + position);
bindHFView((ViewGroup) holder.itemView, mHeaderViews.get(position).getItemView());
} else {
QuickConfig.e("bind footer position:" + position);
bindHFView((ViewGroup) holder.itemView, mFooterViews.get(position - getHeaderViewsCount() - data.size()).getItemView());
}
}

private void bindHFView(ViewGroup parent, View child) {
parent.removeAllViews();
ViewGroup vp = (ViewGroup) child.getParent();
if (vp != null)
vp.removeAllViews();
parent.addView(child);
}

Java8函数式编程读书总结

Lambda表达式

  • Lambda表达式的类型:函数接口是只有一个抽象方法的接口
  • @FunctionalInterface:是否仅仅一个抽象方法!不然编译错误,主要为了lambda提供方便;

    有些多抽象方法的接口不必使用此注解!

  • interface
    • default(注意有方法体!):符合多态 子类如果覆盖,既用自己的行为;

      事件原因:Java8中Collection接口增加stream方法,意味所有子类都需要增加。

    • static default:未构造即可使用,一般用于构造 例如Stream.rang()方法构造流;

继承与链式调用的结合

父类:返回值是泛型;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Helper<T extends Helper> {
protected T child;
public Helper() {
child = (T) this;
}
public T setText(@IdRes int viewId,String textStr) {
...
checkChild();
return child;
}
protected void checkChild() {
if (child == null)
throw new IllegalStateException("child must be set in child's Constructor!" +
"not method:initDefaultValueAnimator");
}
}

ZAdapter3的分析与撸库

分析时候的思路

  • adapter里面的viewhold可以被复用

    所以需要重写一个方法通过位置获取layoutStyle,addviewHolder顺便传递一个layoutStyle,也可不传为默认值;

  • layoutID要在viewhold的类方法中,而不是构造器中

    因为resID与viewHold本就是一个整体。方法构造中的话表示resID是可变的,并且看到这个viewhold类的时候布局文件看不到 容易蒙蔽

  • helper类与ButterKnife的取舍?

    helper比ButterKnife好,原因:可定制封装逻辑,不强转,可连写,可通过泛型+继承+装饰模式达到扩展的目的;

  • adapter 可扩展+链式调用 是用 泛型+继承 还是 同一个接口呢?

    泛型+继承 :在IDEA中是可以的。但是AS中出现了bug。我已经向google提意见了,估计不会吊我~

    所以退而求其次 选择同一个接口

  • 基础功能

    addViewHold(ViewHolder)//为default
    addViewHold(style,viewHolder)
    addHeaderHold(ViewHolder/resId)
    addFooterHold(ViewHolder/resId)
    addEmptyHold(ViewHolder/resId)
    notify系列
    notifyEx系列(这里的位置对应为数据集的位置。包括header/footer)
    relaeList(rv) 故事的开始。很多逻辑可以在这里完成

原型模式-下拉刷新的全局设置

目的

全局替换刷新头部

头部可拔插:需要应用策略模式(组合与接口的方式set get);
全局替换:就是原型模式

设置一个全局头部,那么每次使用的下拉刷新 都是全局头部的深拷贝对象。当然可以随意生成想要拷贝的特性;

Android-drawText()详解

  • 全局声明
    • canvas.drawText(string, baseLineX, baseLineY, paint)
    • baseLineY=基线的Y;
    • baseLineX=基线的X;
    • 本篇以textSize=100为例

API:canvas.drawText(String text,int start,int end,float x,float y, paint); //截取字符串 然后绘制

深入理解Java虚拟机总结---类初始化过程

类的初始化过程

非法向前引用

编译器手机的顺序是由语句在源文件中出现的顺序决定的,静态语句块中只能访问到定义在静态语句之前的变量,定义它之后的变量,可以赋值,但不能访问

1
2
3
4
5
6
7
public class Test{
static{
i=0;
system.out.print(i);//非法向前引用
}
static int i=1;
}

(类构造器方法):在jvm第一次加载class文件时调用,如果类或者接口没有静态语句块,也没有对变量的赋值,那么编译器可以不为这个类生成方法并且他被加锁了,既不能做耗时操作。

Tips:如果在此方法中耗时很长,就可能造成多个进程阻塞;

类加载的时机

  • 加载

    加载与连接阶段的验证动作是交叉进行的

  • 连接

    • 验证

      • 文件格式验证。是否符合Class文件格式的规范
      • 语义分析。父类,抽象类,接口等。
      • 字节码验证
      • 符号引用验证
    • 准备

      正式为类变量分配内存并设置类变量初始值的阶段

      1
      2
      3
      public static int value=123;
      //final的话 准备阶段既123;
      //非常量的 static 则准备阶段是0;<clinit>类构造方法执行才会变成123
    • 解析

      可选的,loadClass第二个参数来判定是否需要解释。这里的解释是根据勒种的符号引用查找相应的实体,在把符号引用替换成一个直接引用的过程。

  • 初始化

  • 使用

  • 卸载

类什么时候才被初始化

  • 只有这6中情况才会导致类的类的初始化

    • 创建类的实例,也就是new一个对象
    • 访问某个类或接口的静态变量,或者对该静态变量赋值
    • 调用类的静态方法
    • 反射(Class.forName(“com.lyj.load”))
    • 初始化一个类的子类(会首先初始化子类的父类)
    • JVM启动时标明的启动类,即文件名和类名相同的那个类
  • 所有引用类的方法都不会触发初始化,称为被动引用。

    类引用父类的静态字段,不会导致该类被初始化

  • 类的初始化步骤:

    • 如果这个类还没有被加载和链接,那先进行加载和链接
    • 假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口)
    • 加入类中存在初始化语句(如static变量和static块),那就依次执行这些初始化语句。

双亲委派模型

Java虚拟器角度仅仅有两种不同的类加载器:

一种启动类加载器(Bootstrap ClassLoader):C++语言实现是虚拟器自身的一部分;

另一种是所有其他的类加载器(java语言,JVM之外 继承ClassLoader)

更详细:

!

Bootstrap ClassLoader:负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class既核心API(ExtClassLoader和AppClassLoader也在此时被加载),由C++实现,不是ClassLoader子类

Extension ClassLoader:负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包

App ClassLoader:负责记载classpath中指定的jar包及目录中class.可以通过getSystemClassLoader()方法获得

Custom ClassLoader:属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader

加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。

为什么这么设计?

类加载器:任何一个类都需要加载它的类加载器和这个类一同确立其在java虚拟机唯一性。每个类加载器都有类名称空间。

两个类是否相同,是由同一个类加载器为前提下才有意义.相同是指equals、instanceof isAssignalbeFrom isIntance等;

例如类java.lang.Object,他存放在rt.jar中,无论哪个类加载器加载这个类,最终都是委派给魔性最顶端的启动类加载器进行加载。因此Object类在程序的各种类加载器环境中都是同一个类
相反如果没有使用,各个类加载自行加载的话。那么系统将出现多个不同的Object类,那么java类型体系中最基本的行为也无法保证;

以下是ClassLoader的源码,实现很简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
rotected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
//从父加载器加载
c = parent.loadClass(name, false);
} else {
//从bootstrap loader加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
  • 其他思考的问题

    • 类加载的逻辑应该在哪里写?

      jdk 1.2之后 已经不提倡用户覆盖loadClass方法了,而是应当在自己的类加载逻辑写到findClass()中。因为loadClass()方法如果加载失败就会调用自己的findClass()去加载。这样就能保证 写出来的类加载器是符合双亲委派模式的

    • 如果依赖特定的扩展包,需要继承特定的classLoader吗?

      下面的默认构造器, 要在父亲是AppClassLoader的基础上 加载自己的类。不然会破坏双亲的
      总结:新的ClassLoader需要旧的去委托。如果不这样就会导致在同一个类出现在不同的ClassLoader中。

      1
      2
      3
      4
       protected ClassLoader() {
      //getSystemClassLoader()其实就是AppClassLoader
      this(checkCreateClassLoader(), getSystemClassLoader());
      }
    • 如果类已经 加载过了,那么应该在哪里存储 下一次去验证是否加载过呢?

      可以通过该ClassLoader中 protect findLoadedClass(name)方法找到。

    • resolveClass 什么时候使用

  • 类加载过程总结

    • 得到类的原始字节数组byte[]。
    • findClass里通过defineClass(name, buf, 0, buf.length) 完成类加载。

举例分析流程

如果一个非ClassPath目录下的新的数据流类通过新的ClassLoader(NewClassLoader)去加载。

Parent:

NewClassLoader-AppClassLoader->ExtClassLoader

第一次初始化

loadClass:每次findLoadedClass都找不到

NewClassLoader-AppClassLoader->ExtClassLoader

findClass:(loadClass的逆序)

ExtClassLoader->AppClassLoader->NewClassLoader(最后在此define 生成类后loadClass一次)

第二次初始化

loadClass:第一个NewClassLoader中findLoadedClass就找到了

NB技巧:子类可以公开父类中的protected的方法;

1
2
3
public void findClass_(){
super.findClass();//protected
}

Demo Code

深入理解Java虚拟机总结

基础了解

  • Java 程序的执行过程:Java 源代码文件(.Java文件)-> Java Compiler(Java编译器)->Java 字节码文件(.class文件)->类加载器(Class Loader)->Runtime Data Area(运行时数据)-> Execution Engine(执行引擎)
  • 各种基本类型:boolean、byte、char、short、int、float、long、double;
  • 对象引用:reference类型 不等于对象本身,可能是对象的句柄也可能对象的引用指针
  • 局部变量默认没有初始值,不赋值是不可以使用的。和类变量(默认是有的)不一样;
  • 额外了解:插入式注解处理器:需要继承AbstractProcessor;

Mac下Hexo搭建博客攻略

Hexo是基于NodeJs的静态博客框架,简单、轻量,其生成的静态网页可以托管在GithubHeroku上。

  • 超快速度
  • 支持MarkDown
  • 一键部署
  • 丰富的插件

下面以我的博客为例,luhaoaimama1.github.io