1.Glide
注意:因为android默认给每一个应用分配16M的内存,如果加载过多的图片的话,容易出现OOM
(1).glide的基本使用
//加载图片到ImageView,并指定缓存策略
RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(loadingResId) //设置“加载中”状态时显示的图片
.error(errorResId); //设置“加载失败”状态时显示的图片
Glide.with(context)
.load(url)
.apply(requestOptions)
.into(imageView);
//加载图片到ImageView,并指定占位图
RequestOptions requestOptions = new RequestOptions();
requestOptions.placeholder(loadingResId) //设置“加载中”状态时显示的图片
.error(errorResId); //设置“加载失败”状态时显示的图片
Glide.with(context)
.load(url)
.apply(requestOptions)
.into(imageView);
(2).glide的缓存策略
DiskCacheStrategy.NONE 不缓存文件
DiskCacheStrategy.SOURCE 只缓存原图
DiskCacheStrategy.RESULT 只缓存最终加载的图(默认的缓存策略)
DiskCacheStrategy.ALL 同时缓存原图和结果图
默认的磁盘缓存目录:data/data/包名/cache/image_manager_disk_cache
自定义外部缓存路径:
builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, "egatee", 100 * 1024 * 1024));
磁盘缓存目录:Android/data/包名/cache/egatee/
(3).glide源码分析
glide他是绑定生命周期,glide.get()根据传入的对象,和当前线程创建不同的RequestManager 实例,如果在UI线程中,context是Activity,则会创建一个能感知Activity生命周期的RequestManager,如果context是Fragment ,则会创建一个能感知Fragment生命周期的RequestManger,如果是在非UI线程中,则会创建一个applicationManager对象,能感知appltionm周期,在创建RequestManager的同时,也会创建一个RequestManagerFragment,在Request里面有onStart,onStop,onDestroy等生命周期方法,停止加载资源,释放缓存等。
glide从网络上加载图片:Glide在调用load方法加载图片的时候,检测如果资源存在,直接调用onResourceReady()方法直接加载图片,如果资源不存在,首先从网络下载图片,并开启二个线程池,用于缓存图片。
内存缓存和磁盘缓存,网络缓存
DiskCacheStrategy.NONE 啥也不缓存
DiskCacheStrategy.SOURCE 只缓存全尺寸图
DiskCacheStrategy.RESULT 只缓存最终降低分辨后用到的图片
和Picasso的对比:
1.Glide可以加载Gif,picasso不能,2.glide默认的解码格式是RGB_565(4bit) ,Picasso默认的解码格式是ARGB888(8bit)更清晰 3.pacasso的with方法只接受context作为参数,但是glide可以接受context,fragment,activity,这样,glide加载图片的时候,能够和组件的生命周期保持一致。
2.Retrofit2.0
(1).创建Retrofit对象
public class HttpRetrofit {
private static Retrofit mRetrofit;
public static Retrofit getService(){
if (mRetrofit == null) {
synchronized (HttpRetrofit.class) {
if (mRetrofit == null) {
mRetrofit = new Retrofit.Builder()
.baseUrl(ApiUrl.BASE_URL)
.client(WBHttpClient.getHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
}
}
return mRetrofit;
}
}
(2).retrofit各种网络请求的用法
/************************************GET网络请求方式******************************************************/
//作用:GET请求最简单的写法,无Path参数和Query参数 */
// @GET("article/list/latest?page=1") Call getLatestString();
//作用:GET请求,指定Path参数和Query参数
//@GET("article/list/{type}?") Call getInfoList(@Path("type") String type, @Query("page") int page);
//作用:GET请求提交数据
// @GET("MyWeb/RegServlet") Call getRegInfo(@QueryMap Map map);
//作用:GET请求,指定URL参数
//@GET Call getInfoList(@Url String urlString);
//访问网络,下载大文件。 * 默认情况下,Retrofit在处理结果前会将服务器端的Response全部读进内存
//@Streaming @GET Call getNetworkDataAsync(@Url String urlString);
/************************************POST网络请求方式******************************************************/
//作用:post网络请求,向服务器提交表单域数据
//@FormUrlEncoded @POST("MyWeb/RegServlet") Call postFormFields(@Field("username") String username, @Field("password") String password, @Field("age") String age);
// @FormUrlEncoded @POST("MyWeb/RegServlet") Call postFormFieldMap(@FieldMap Map map);
//作用:POST网络请求,上传单个文件,上传后的文件名称已经被指定
//@Multipart @POST("MyWeb/UploadServlet") Call postUploadFile(@Part("uploadfile\";filename=\"myuploadimg.png") RequestBody requestBody);
//作用:POST网络请求,上传多个文件,同时上传表单域数据
// @POST("MyWeb/UPloadServlet") Call postUploadFilesMultipartBody(@Body MultipartBody multipartBody);}
//和Rxjava一起连用
@GET(ApiUrl.GET_MARKET)
Observable>> getMarket(@QueryMap Map map);
mRetrofit.create(WebService.class).getMarket(map).
subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).
subscribe(new ObserverCallBack>>(new ApiCallBack>>() {
@Override
public void onSuccess(BaseResult> baseResult) {
}
@Override
public void onFailture(Throwable e,int errorCode) {
}
}));
(3).retrofit2.0原理
(3-1)通过构造者模式创建一个retrofit实例,配置baseUrl,OkHttpClient,CallAdapterFactory(Rxjava2CallAdapterFactory将代理返回的call对象转化为Observer),ConvertFactory(GsonConvertFactory将代理返回的请求的结果转化为特定的对象)
(3-2).通过retrofit对象的create(Class
(3-3).动态代理(代理类在运行前不存在,运行时由程序生成的代理方式叫动态代理)
参考文章:https://www.cnblogs.com/gonjan-blog/p/6685611.html
实现方式:创建一个实现了InvocationHandler 接口的类,然后实现其invoke方法,然后使用Proxy.newProxyInstance()方法创建代理对象,通过代理对象,调用接口中的方法,实际上是调用的InvocationHandler 中的invoke方法
/**
* 创建Person接口
* @author Gonjan
*/
public interface Person {
//上交班费
void giveMoney();
}
public class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void giveMoney() {
try {
//假设数钱花了一秒时间
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "上交班费50元");
}
}
public class StuInvocationHandler implements InvocationHandler {
//invocationHandler持有的被代理对象
T target;
public StuInvocationHandler(T target) {
this.target = target;
}
/**
* proxy:代表动态代理对象
* method:代表正在执行的方法
* args:代表调用目标方法时传入的实参
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行" +method.getName() + "方法");
*/
//代理过程中插入监测方法,计算该方法耗时
MonitorUtil.start();
Object result = method.invoke(target, args);
MonitorUtil.finish(method.getName());
return result;
}
}
测试代理类:
public class ProxyTest {
public static void main(String[] args) {
//创建一个实例对象,这个对象是被代理的对象
Person zhangsan = new Student("张三");
//创建一个与代理对象相关联的InvocationHandler
InvocationHandler stuHandler = new StuInvocationHandler(zhangsan);
//创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class>[]{Person.class}, stuHandler);
//代理执行上交班费的方法
stuProxy.giveMoney();
}
}
打印结果:
3.Rxjava(https://gank.io/post/560e15be2dca930e00da1083#toc_4)
(1).Rxjava一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序库。
(2).Rxjava原理就是类似于观察者模式
观察者模式面向的需求是:A 对象(观察者)对 B 对象(被观察者)的某种变化高度敏感,需要在 B 变化的一瞬间做出反应。举个例子,新闻里喜闻乐见的警察抓小偷,警察需要在小偷伸手作案的时候实施抓捕。在这个例子里,警察是观察者,小偷是被观察者,警察需要时刻盯着小偷的一举一动,才能保证不会漏过任何瞬间。程序的观察者模式和这种真正的『观察』略有不同,观察者不需要时刻盯着被观察者(例如 A 不需要每过 2ms 就检查一次 B 的状态),而是采用注册(Register)或者称为订阅(Subscribe)的方式,告诉被观察者:我需要你的某某状态,你要在它变化的时候通知我。 Android 开发中一个比较典型的例子是点击监听器 OnClickListener 。对设置 OnClickListener 来说, View 是被观察者, OnClickListener 是观察者,二者通过 setOnClickListener() 方法达成订阅关系。订阅之后用户点击按钮的瞬间,Android Framework 就会将点击事件发送给已经注册的 OnClickListener 。采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。当然,这也得益于我们可以随意定制自己程序中的观察者和被观察者,而警察叔叔明显无法要求小偷『你在作案的时候务必通知我』
RxJava 有四个基本概念:Observable (可观察者,即被观察者)、 Observer (观察者)、 subscribe (订阅)、事件。Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> subscriber) {
//onNext可以调用多次
try {
subscriber.onNext("Hellow Rxjava");
subscriber.onNext("Hellow Rxjava");
//时间序列结束标记
subscriber.onCompleted();
}catch (Exception e){
subscriber.onError(e);
}
}
}).subscribe(new Observer() {//被观察者必须指定观察者或者订阅者,整个事件才可以
@Override
public void onCompleted() {
Log.i(TAG,"onCompleted:");
}
@Override
public void onError(Throwable e) {
Log.i(TAG,"onError:"+e);
}
@Override
public void onNext(String s) {
Log.i(TAG,"onNext:"+s);
}
});
在 RxJava 的 subscribe 过程中,Observer 也总是会先被转换成一个 Subscriber 再使用。所以如果你只想使用基本功能,选择 Observer 和 Subscriber 是完全一样的。它们的区别对于使用者来说主要有两点。
A:onStart():这是 Subscriber 增加的方法。
B: unsubscribe(): 这是 Subscriber 所实现的另一个接口 Subscription 的方法,用于取消订阅,
一般在这个方法调用前,可以使用 isUnsubscribed() 先判断一下状态。 unsubscribe() 这个方法很重要,因为在 subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。
(3).操作符
(3-1).create,just,from操作符创建Observable被观察者对象
Observable.just(1,2,3,4,5).subscribe(new Subscriber() {
@Override
public void onCompleted() {
Log.i(TAG,"onCompleted:");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Integer integer) {
Log.i(TAG,"onNext:"+integer);
}
});
Observable.from(new String[]{"AAA","BBB","CCC"}).subscribe(new Action1() {
@Override
public void call(String s) {
Log.i(TAG, "onNext:" + s);
}
});
(3-2)map,floatmap,filter ,take ,takelast,distinct,skip变换操作符
map操作符----将原Observable发射出来的数据转换为另外一种类型的数据
Observable.just(666).map(new Func1() {
@Override
public String call(Integer integer) {//Integer---->String
return integer+"";
}
}).map(new Func1() {
@Override
public Long call(String s) {
return Long.parseLong(s);
}
}).subscribe(new Action1() {
@Override
public void call(Long aLong) {
Log.i(TAG,"call:"+aLong);
}
});
floatmap操作符---作用类似于map又比map强大,map是单纯的数据类型的转换,而flapMap可以将原数转换成新的Observables,再将这些Observables的数据顺序缓存到一个新的队列中,在统一发射出来
List students= DataUtils.getStudentList();
Observable.from(students).flatMap(new Func1>() {
@Override
public Observable call(Student student) {
return Observable.from(student.getCourses());
}
}).subscribe(new Observer() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onNext(String s) {
Log.i("TAG","couseName:"+s.toString());
}
});
filter操作符----对发射的数据做一个限制,只有满足条件的数据才会被发射
//对发射的数据做一个限制,只有满足条件的数据才会被发射
Observable.just("hello","Rxjava","Nice to meet you").filter(new Func1() {
@Override
public Boolean call(String s) {
return s.length()>5;
}
}).subscribe(new Observer() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onNext(String s) {
Log.i("TAG","filter过滤后的数据:"+s.toString());
}
});
distinct操作符----过滤掉重复项
Observable.just("hello","hello","hello","Rxjava","Rxjava","Nice to meet you").filter(new Func1() {
@Override
public Boolean call(String s) {
return s.length()>5;
}
}).subscribe(new Observer() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onNext(String s) {
Log.i("TAG","distinct去除重复之后的数据:"+s.toString());
}
});
Skip操作符----发射数据时忽略前N项数据(skpiLast忽略后N项数据)
Observable.just("hello","Rxjava","Nice to meet you").skip(2).subscribe(new Observer() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onNext(String s) {
Log.i("TAG","Skip之后的数据:"+s.toString());
}
});
take操作符----只发射前N项的数据(takeLast与take想反,只取最后N项数据)
Observable.just("hello","Rxjava","Nice to meet you").take(2).subscribe(new Observer() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onNext(String s) {
Log.i("TAG","Take之后的数据:"+s.toString());
}
});
另外还有一些其他的操作符 range,Interval,empty,error等(https://www.jianshu.com/p/eceb6b31d8cb)
(3-3).线程调度Scheduler
Observable.just(1, 2, 3, 4)
.subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Action1() {
@Override
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
});
上面这段代码中,由于 subscribeOn(Schedulers.io()) 的指定,被创建的事件的内容 1、2、3、4 将会在 IO 线程发出;而由于 observeOn(AndroidScheculers.mainThread()) 的指定,因此 subscriber 数字的打印将发生在主线程 。事实上,这种在 subscribe() 之前写上两句 subscribeOn(Scheduler.io()) 和 observeOn(AndroidSchedulers.mainThread()) 的使用方式非常常见,它适用于多数的 『后台线程取数据,主线程显示』的程序策略
4.Okhttp
(1).Get请求
new OkHttpClient ,构造Request对象,调用newCall方法获取Call对象,通过call#enqueue或者excute来提交请求。
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.get()//默认就是GET请求,可以不写
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});
(2).Post请求
在构建Request对象的时候,需要多构造一个RequestBody对象,同时指定MediaType用于描述请求/响应body的内容类型
Post提交String
MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
String requestBody = "I am Jdqm.";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(mediaType, requestBody))
.build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});
Post提交流
RequestBody requestBody = new RequestBody() {
@Nullable
@Override
public MediaType contentType() {
return MediaType.parse("text/x-markdown; charset=utf-8");
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
sink.writeUtf8("I am Jdqm.");
}
};
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(requestBody)
.build();
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});
Post提交文件
MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
OkHttpClient okHttpClient = new OkHttpClient();
File file = new File("test.md");
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(mediaType, file))
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});
Post提交表单
HttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
.add("search", "Jurassic Park")
.build();
Request request = new Request.Builder()
.url("https://en.wikipedia.org/w/index.php")
.post(requestBody)
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: " + e.getMessage());
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());
Headers headers = response.headers();
for (int i = 0; i < headers.size(); i++) {
Log.d(TAG, headers.name(i) + ":" + headers.value(i));
}
Log.d(TAG, "onResponse: " + response.body().string());
}
});
Post提交分块请求
private static final String IMGUR_CLIENT_ID = "...";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private void postMultipartBody() {
OkHttpClient client = new OkHttpClient();
// Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
MultipartBody body = new MultipartBody.Builder("AaB03x")
.setType(MultipartBody.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"title\""),
RequestBody.create(null, "Square Logo"))
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"image\""),
RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
.build();
Request request = new Request.Builder()
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.url("https://api.imgur.com/3/image")
.post(body)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println(response.body().string());
}
});
}
OKhttp的原理:OkhttpClient (Builder) --->build()-->OKhttpClient-----(Request)>newCall()-->RealCall()-1->excute() --2-Dispacher-->excute()————>getResponseWithInterceptorChain()--->interceptors--->RetryAndFollowUpInterceptor--->BridgeInterceptor--->CacheInterceptor--->ConntecInterceptor-->
NetWorkInterceptors--->CallServerInterceptor----Response结果。责任链模式
ConnectInterceptor:HttpCodeC这个类利用OKIO对Socket的读写进行封装