美文网首页
框架原理

框架原理

作者: Owen270 | 来源:发表于2019-04-09 15:32 被阅读0次

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<ResponseBody> getLatestString();
    //作用:GET请求,指定Path参数和Query参数
    //@GET("article/list/{type}?") Call<QiushiModel> getInfoList(@Path("type") String type, @Query("page") int page);
    //作用:GET请求提交数据
    // @GET("MyWeb/RegServlet") Call<ResponseBody> getRegInfo(@QueryMap Map<String, String> map);
    //作用:GET请求,指定URL参数
    //@GET Call<QiushiModel> getInfoList(@Url String urlString);
    //访问网络,下载大文件。 * 默认情况下,Retrofit在处理结果前会将服务器端的Response全部读进内存
    //@Streaming @GET Call<ResponseBody> getNetworkDataAsync(@Url String urlString);
    /************************************POST网络请求方式******************************************************/
    //作用:post网络请求,向服务器提交表单域数据
    //@FormUrlEncoded @POST("MyWeb/RegServlet") Call<ResponseBody> postFormFields(@Field("username") String username, @Field("password") String password, @Field("age") String age);
    // @FormUrlEncoded @POST("MyWeb/RegServlet") Call<ResponseBody> postFormFieldMap(@FieldMap Map<String , String> map);
    //作用:POST网络请求,上传单个文件,上传后的文件名称已经被指定
    //@Multipart @POST("MyWeb/UploadServlet") Call<ResponseBody> postUploadFile(@Part("uploadfile\";filename=\"myuploadimg.png") RequestBody requestBody);
    //作用:POST网络请求,上传多个文件,同时上传表单域数据
    // @POST("MyWeb/UPloadServlet") Call<ResponseBody> postUploadFilesMultipartBody(@Body MultipartBody multipartBody);}
//和Rxjava一起连用
  @GET(ApiUrl.GET_MARKET)
    Observable<BaseResult<List<MarketBean>>> getMarket(@QueryMap Map<String ,Object> map);

 mRetrofit.create(WebService.class).getMarket(map).
                subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).
                subscribe(new ObserverCallBack<BaseResult<List<MarketBean>>>(new ApiCallBack<BaseResult<List<MarketBean>>>() {
                    @Override
                    public void onSuccess(BaseResult<List<MarketBean>> 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<T> service)返回一个Service的动态代理对象,在调用Service的方法的时候,就是动态调用invoke方法。
(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<T> 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<Person>(zhangsan);
        
        //创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
        Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);

       //代理执行上交班费的方法
        stuProxy.giveMoney();
    }
}

打印结果:


image.png

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<String>() {
                    @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<String>() {//被观察者必须指定观察者或者订阅者,整个事件才可以
                    @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<Integer>() {
                    @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<String>() {
                    @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<Integer, String>() {
                    @Override
                    public String call(Integer integer) {//Integer---->String
                        return integer+"";
                    }
                }).map(new Func1<String, Long>() {
                    @Override
                    public Long call(String s) {
                        return Long.parseLong(s);
                    }
                }).subscribe(new Action1<Long>() {
                    @Override
                    public void call(Long aLong) {
                        Log.i(TAG,"call:"+aLong);
                    }
                });
floatmap操作符---作用类似于map又比map强大,map是单纯的数据类型的转换,而flapMap可以将原数转换成新的Observables,再将这些Observables的数据顺序缓存到一个新的队列中,在统一发射出来
List<Student> students= DataUtils.getStudentList();
                Observable.from(students).flatMap(new Func1<Student, Observable<String>>() {
                    @Override
                    public Observable<String> call(Student student) {
                        return Observable.from(student.getCourses());
                    }
                }).subscribe(new Observer<String>() {
                    @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<String, Boolean>() {
                    @Override
                    public Boolean call(String s) {
                        return s.length()>5;
                    }
                }).subscribe(new Observer<String>() {
                    @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<String, Boolean>() {
                    @Override
                    public Boolean call(String s) {
                        return s.length()>5;
                    }
                }).subscribe(new Observer<String>() {
                    @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<String>() {
                    @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<String>() {
                    @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<Integer>() {
        @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的读写进行封装

相关文章

  • Android中热修复框架Robust原理解析+并将框架代码从&

    一、回顾框架原理本篇继续来看热修复框架Robust原理,在之前的一篇文章中已经详细讲解了:Robust框架原理,因...

  • 前端TODO

    Vue.js 等框架原理了解 webpack 原理了解 browserify 插件开发 Vue.js 等框架原理学习

  • Binder机制

    进程间通信方式 Android Binder框架图 Android系统框架 IPC 进程通信原理 Binder原理...

  • 框架原理

    1.Spring-mvc原理 客户端请求提交到DispathcerServlet 由DispatcherServl...

  • 框架原理

    1.Glide 注意:因为android默认给每一个应用分配16M的内存,如果加载过多的图片的话,容易出现OOM ...

  • Grpc原理

    1 rpc框架原理 rpc调用原理框架如图: 2 业内比较成熟的rpc框架 支持多语言的主要分为3类 -支持多语言...

  • face23 MVC框架基本工作原理

    MVC框架基本工作原理 谈谈你对mvc的认识,介绍几种目前比较流行的mvc框架 MVC工作原理 Model vie...

  • Android核心框架记录OkHttp、EventBus、Gli

    1. OkHttp框架的使用和原理 框架原理是建立线程池,利用调度线程,不断的取任务进行处理: Request,a...

  • Notification框架简介

    目录 Notification介绍 Notification框架原理 Notification框架服务端启动过程 ...

  • Android面试题4(通关四)

    网络框架原理: 1:okhttp原理,这个我总结的有,可以参考okhttp 2:市面上常见的网络框架有哪些? OK...

网友评论

      本文标题:框架原理

      本文链接:https://www.haomeiwen.com/subject/najulqtx.html