金三银四那些事(三)
说说你对android中设计模式的认识:
单例模式
这里会考到手写一个单例模式:
public class Singleton {
private static volatile Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
上面有两层的非空判断,一般这里会问到,第一层是为了防止多次加锁的判断,因为同步锁是耗时的,所以只在首次为空的时候,只进行一次加锁,第二次纯粹是为了new对象的时候非空判断。
android中用到的单例模式举例:
Android-Universal-Image-Loader中的单例
private volatile static ImageLoader instance;
/** Returns singleton class instance */
public static ImageLoader getInstance() {
if (instance == null) {
synchronized (ImageLoader.class) {
if (instance == null) {
instance = new ImageLoader();
}
}
}
return instance;
}
builder模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
public class Person {
private String name;
private int age;
private double height;
private double weight;
//构造函数私有化
private Person(Builder builder) {
this.name=builder.name;
this.age=builder.age;
this.height=builder.height;
this.weight=builder.weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
static class Builder{
private String name;
private int age;
private double height;
private double weight;
public Builder name(String name){
this.name=name;
return this;
}
public Builder age(int age){
this.age=age;
return this;
}
public Builder height(double height){
this.height=height;
return this;
}
public Builder weight(double weight){
this.weight=weight;
return this;
}
//builder静态内部类里面定义一个方法来生成外部类的私有构造器
public Person build(){
return new Person(this);
}
}
}
调用部分:
Person.Builder builder=new Person.Builder();
Person person=builder
.name("张三")
.age(18)
.height(178.5)
.weight(67.4)
.build();
android源码部分builder设计模式举例:
AlertDialog.Builder
、GsonBuilder
总结:
- 定义一个静态内部类Builder,内部的成员变量和外部类一样
- Builder类通过一系列的方法用于成员变量的赋值,并返回当前对象本身(this)
- Builder类提供一个build方法或者create方法用于创建对应的外部类,该方法内部调用了外部类的一个私有构造函数,该构造函数的参数就是内部类Builder
- 外部类提供一个私有构造函数供内部类调用,在该构造函数中完成成员变量的赋值,取值为Builder对象中对应的值
观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都能得到通知并被自动更新
- 观察者,我们称它为Observer,有时候我们也称它为订阅者,即Subscriber
- 被观察者,我们称它为Observable,即可以被观察的东西,有时候还会称之为主题,即Subject
其实咱们在listview中刷新列表的时候,会用到adapter的notifyDataSetChanged方法,其实这里也是一个观察者模式,咱们去BaseAdapter
中去找找该方法:
private final DataSetObservable mDataSetObservable = new DataSetObservable();
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
接着看DataSetObservable
中notifyChanged方法:
public void notifyChanged() {
synchronized(mObservers) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
可以看到这里遍历了mObservers
集合,然后调用了onChanged方法。只能去父类找找mObservers
是个什么玩意。
从这里可以看出来实际是被观察者类,其中咋们要观察的对象是
DataSetObserver
,也就是我们的观察者。所以说这里的观察者一旦被触发了,会调用到自己的onChanged
方法。那是什么
registerDataSetObserver
的呢,接着看listview
的源码部分:image.png
那看看
AdapterDataSetObserver
该观察者中onChange
方法都做了些啥:
@Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
// Detect the case where a cursor that was previously invalidated has
// been repopulated with new data.
if (AdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
&& mOldItemCount == 0 && mItemCount > 0) {
AdapterView.this.onRestoreInstanceState(mInstanceState);
mInstanceState = null;
} else {
rememberSyncState();
}
checkFocus();
requestLayout(); //onChanged的主要目的就是重布局
}
其实从最后一行调用的方法可以看出来,onChange里面做的工作就是刷新listView中整体的布局。这会知道了调用adapter.notifyDataSetChanged方法就是刷新listview列表了吧。
总结下来观察者模式实际可以用一张图说明:
后面的原型模式
、策略模式
请点击这里
mvc和mvp的对比:
-
activity或fragment的职责不同
在mvc中activity充当controller层,但也脱不了view层的,但在mvp中activity完全是充当了view层的,只和view相关的代码。这也是为什么mvc过渡到mvp的好处,这里activity没有像在mvc中那么臃肿。 -
view层不同
在mvc中view层主要是一些layout资源文件,再就是一些自定义的view了。其实这里看得出来这里的view层发挥的功能很小,毕竟不像web开发那样。在mvp中view层指的是activity或fragment,这里缺陷是随着业务复杂,activity或fragment也会变得复杂。 -
控制层不同
mvc中controller层指的是activity或是fragment,但是大家也知道这里的activity或fragment又有view层的影子,毕竟activity又需要处理一些控件啥的。在mvp中controller层就是单一的p层了,简单地建立了view层和model层的桥梁。 -
关系链不同
在mvc中view层和model层直接联系的,比如我们的自定义view需要些数据展示页面的时候,就直接从model层去取的;也会出现model层获取到数据后,直接到view层刷新数据了,因此这里会出现直接交互的关系链。而在mvp中view和model层完全是通过p层来建立联系的,不再持有对方的引用,引用都在p层了。 -
交互方式不同
MVP中通讯交互基本都是通过接口的,MVC中的通讯交互很多时候都是实打实的调用对象的方法,简单粗暴! -
实现方式不同
MVC和MVP的Model几乎一样的,都是处理数据,只要不在Activity或者Fragment中请求数据,其他的所有控制都放在Activity或者Fragment中,这样写就基本是MVC的模式,这样写不麻烦,但是很容易把Activity写出上万行代码。用MVP的时候我们需要写很多View和Presenter接口来实现模块之间的通讯,会增加很多类。
画出mvp的umm图:
这里以登录模块为例:
mvp中登录uml图.png
说说mvvm的使用:
说说你对android中三级缓存的理解:
整个过程是先从内存缓存中找数据,如果内存缓存中没数据,到文件缓存中找,如果再没有去网络中找数据,网络中数据加载回来后,将数据保存到文件缓存中,再加载到内存中。
内存缓存:
主要用到android定义好的LruCache对象,此时需要传一个允许内存缓存的大小,一般遵循:
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 8;
这里会考到LruCache内存缓存的算法,这里的算法是最不经常使用的数据优先被移除,主要涉及到LinkedHashMap的数据结构问题。
文件缓存
这里存的时候,首先将url用MD5的encode过程,然后得到文件的name,然后通过定义的file_path目录得到File对象,得到file之后判断是不是已经存在该file的parentFile,如果不存在需要创建该file的parentFile。最后得到该file的输出流,最后使用bitmap.compress
保存到本地文件中。
服务端缓存
这个就没什么好说的了,使用HttpURLConnection
对象获取到bitmap的输入流,最后使用BitmapFactory.decodeStream
得到bitmap对象。
说说LinkedhashMap的数据结构:
里面是一个双向链表的数据结构,维护着一个双重链接列表的顺序。此链接列表定义了迭代顺序,该迭代顺序可以是插入顺序或者是访问顺序。该迭代顺序遵循的原则如下:
- 第一种和队列一样默认是按插入顺序排序,先进来的是最老的元素,放在队头,将来会被先移出去,最后进来的是新的元素。
- 第二种,基于访问排序,那么调用get方法后,会将每次访问的元素移至队尾,将来移除的时候移除的是队头,最先访问的元素最后才被移除,不断访问可以形成按访问顺序排序的链表。
java反射的机制:
HTTP网络的工作流程:
1.建立TCP连接
2.web浏览器向web服务器发送请求命令
3.web浏览器发送请求头信息
4.web服务器应答
5.web服务器发送应答头信息
6.web服务器向浏览器发送数据
7.web服务器关闭TCP连接
Http请求头都有哪些
image.pngTCP对比UDP来说都有哪些:
TCP的三次握手,四次挥手指的什么:
TCP的三次握手:
- 第一次握手:
建立连接,客户端A发送SYN=j包(这里表示新连接的一个标志位)到服务器B,并进入SYN_SEND状态,等待服务器B确认 - 第二次握手:
服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1,这里表示收到了来自A客户的应 答),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态 - 第三次握手:
客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手
TCP的四次挥手: - 客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
- 服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
- 服务器B关闭与客户端A的连接,发送一个FIN给客户端A。
- 客户端A发回ACK报文确认,并将确认序号设置为收到序号加1。