全新MVP,你get到我的點了嗎?(含java和kotlin代碼)

寫在開頭

PS:最近也在一直在學習kotlin,所以在寫完java後也手擼了一遍kotlin,其中包含自己在kotlin學習中的一些筆記什麼的。後續有新想法也會一直更新什麼的。下一步打算加入本地Mock json數據的功能。

不多說,本文圍繞一張圖展開,請查閱,歡迎共同討論,叨擾了。如果你還有什麼需求或者什麼想法,可一起完善此demo一起進步哦!!!

這裏寫圖片描述

github:https://github.com/loveAndroidAndroid/MvpProject ,歡迎共同學習!可下載java和kotlin版本。
CSDN:https://download.csdn.net/download/say_from_wen/10671387 (java)
https://download.csdn.net/download/say_from_wen/10691277 (kotlin版本)

讓我們從library到mouble,讓我們談談我理解的項目的Project架構。本文章全部就java版本來談,如果對於kotlin版本的探討,可留言或者QQ認基友807315559 哈哈

##lib-network封裝淺談

如果是你封裝這個的話,你想到的會是什麼?一個好的網絡底層封裝庫應該具備哪些功能?

首先:

  1. 這個網絡庫不應該和業務有任何的聯繫,只提供對外設置參數的方法。
  2. 無論後端返回數據格式是否變化(比如成功的時候是對象,失敗會返回數組格式),不會報錯解析錯誤。
  3. 自定義各種異常的友好提示
  4. 支持https設置
  5. 支持本地域名驗證

下面我們看一下我的想法:

1.關於第一個問題:主要代碼在RetrofitUtil工具類中,所有設置所需的參數都由外部設置進來,提供必要的可擴展性:

 public void init(String baseURL, long readTime, long writeTime, long connectTime, SocketFactory socketFactory, HostnameVerifier hostnameVerifier, Interceptor... interceptor) {
        if (gson == null) {
            gson = new GsonBuilder()
                    .enableComplexMapKeySerialization() //支持Map的key爲複雜對象的形式
                    .create();
        }
        retrofit = new Retrofit.Builder()
                .baseUrl(baseURL)
                .client(genericClient(readTime, writeTime, connectTime, socketFactory, hostnameVerifier, interceptor))
                //2.自定義ConverterFactory處理異常情況
                .addConverterFactory(JsonArrayConverterFactory.create(gson))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }

    public OkHttpClient genericClient(long readTime, long writeTime, long connectTime, SocketFactory socketFactory, HostnameVerifier hostnameVerifier, Interceptor... interceptors) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .readTimeout(readTime, TimeUnit.SECONDS)
                .writeTimeout(writeTime, TimeUnit.SECONDS)
                .connectTimeout(connectTime, TimeUnit.SECONDS);
        //      可以添加進來https認證
//              .socketFactory(socketFactory)
//              .hostnameVerifier(hostnameVerifier);
        if (interceptors != null && interceptors.length > 0) {
            for (int i = 0; i < interceptors.length; i++) {
                builder.addInterceptor(interceptors[i]);
            }
        }
        return builder.build();
    }

2.不知道你的後臺是不是PHP,不知道你有沒有遇到過後臺數據格式返回在正確的時候是個對象object,出錯的時候是個數組array。然後給你報錯解析異常,後來經過了解,PHP都是以Array取值,給我們返回的object也是他們強轉的,我總不能要求人家每次或者每個錯誤都給我處理吧。無奈之只能自己搞了。

自定義Converter能解決我們的煩惱:主要爲以下代碼,核心思想其實利用Gosn的分段解析的一個思想。

 @Override
    public T convert(ResponseBody value) throws IOException {
        String response = value.string();
        try {
            //ResultResponse 只解析status字段
            ResultResponse resultResponse = gson.fromJson(response, ResultResponse.class);
            if (Integer.parseInt(resultResponse.getStatus()) == 200) {
                //result==200表示成功返回,繼續用本來的Model類解析
                return gson.fromJson(response, type);
            } else {
                //ErrResponse 將msg解析爲異常消息文本
                ErrResponse errResponse = gson.fromJson(response, ErrResponse.class);
                throw new ResultException(resultResponse.getStatus(), errResponse.getMsg());
            }
        } finally {
        }
    }

3.關於網絡請求,出錯的情況千遍萬變,我們總要自定義一些自己的友好提示,我們如何攔截並設置呢?因爲我用的事RxJava2.x,所以此時通過自定義DisposableSubscriber實現,關於友好提示,當然是由你的產品來定,對外提供成功和失敗的方法就行了。建議代碼如下:

/**
 * Created by wen on 2018/5/14.
 * 適配器模式  去除不必要的接口方法
 */
public abstract class ApiSubscriberCallBack<T> extends DisposableSubscriber<T> {

    @Override
    public void onNext(T t) {
        onSuccess(t);
    }

    @Override
    public void onError(Throwable e) {
        e.printStackTrace();

        //在這裏做全局的錯誤處理
        if (e instanceof HttpException||
                e instanceof ConnectException ||
                e instanceof SocketTimeoutException ||
                e instanceof TimeoutException ||
                e instanceof UnknownHostException) {
            //網絡錯誤
            onFailure(new Throwable("網絡不好哦親,請確認網絡重新連接"));
        } else if (e instanceof ResultException) {
            //todo 自定義的ResultException  此處結合業務進行處理
            onFailure(e);
        } else {
            //其他錯誤
            onFailure(new Throwable("未知錯誤,地球即將爆炸,請趕緊跑路"));
        }
    }

    @Override
    public void onComplete() {
    }

    public abstract void onSuccess(T t);

    public abstract void onFailure(Throwable t);
}

case 4:

case 5:關於Https設置和域名設置,暫不提供,可google一下就好,有問題可留言討論。

##lib-image封裝淺談

圖片封裝的話,我感覺我們還是考慮封裝一些通過的效果,比如圓形圓角等,其他的可以通過提供方法設置進去比較好。當然,不要和業務有關聯。

圖片庫功能:

  1. 自定義ResponseBody實現對圖片加載進度的監聽。
  2. 自定義BitmapTransformation實現各種通用效果
  3. 提供初始化工具類
  4. 提供Glide緩存清理工具類

1.自定義ResponseBody(Glide4.x)

如果我們不使用Glide的話,我們首先得自定義RegistersComponents並重寫RegistersComponents方法來實現對網絡請求的監聽,替換Glide的默認加載、解碼和*編碼邏輯。。Glide的話,在4.x以後提供了AppGlideModule的封裝類,我們繼承它實現registerComponents就好了,代碼如下:

@GlideModule
public class ProgressAppGlideModule extends AppGlideModule {
    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        super.registerComponents(context, glide, registry);
        registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(ProgressManager.getOkHttpClient()));
    }
}

然後,我們需要將我們自定義的ResponseBody設置給OkHttpClient,並在ResponseBody的source方法中的ForwardingSource內部類中的read方法返回我們需要的進度,主要代碼如下:

	 private Source source(Source source) {
        return new ForwardingSource(source) {
            long totalBytesRead;
            long lastTotalBytesRead;

            @Override
            public long read(@NonNull Buffer sink, long byteCount) throws IOException {
                long bytesRead = super.read(sink, byteCount);
                totalBytesRead += (bytesRead == -1) ? 0 : bytesRead;

                if (internalProgressListener != null && lastTotalBytesRead != totalBytesRead) {
                    lastTotalBytesRead = totalBytesRead;
                    mainThreadHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            internalProgressListener.onProgress(url, totalBytesRead, contentLength());
                        }
                    });
                   }
                return bytesRead;
            }
        };
    }

2.通過BitmapTransformation實現各種各樣的圖片效果

我們還是主要通過Transformation的transform方法中來對bitmap進行處理來返回我們最終想要的效果,例如我們實現一個圓形效果:(代碼會有詳細的註釋)

	@Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
        //得到圖片最小邊
        int size = Math.min(toTransform.getWidth(), toTransform.getHeight());
        //計算圖片起點
        int x = (toTransform.getWidth() - size) / 2;
        int y = (toTransform.getHeight() - size) / 2;
        //創建新的bitmaop
        Bitmap square = Bitmap.createBitmap(toTransform, x, y, size, size);
        //得到glide中BitmapPool的bitmap位圖對象
        Bitmap circle = pool.get(size, size, Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(circle);
        Paint paint = new Paint();
        //設置TileMode的樣式 CLAMP 拉伸 REPEAT 重複  MIRROR 鏡像
        paint.setShader(new BitmapShader(square, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        float r = size / 2f;
        //畫圓
        canvas.drawCircle(r, r, r, paint);
        return circle;
    }

3.初始化工具類

4.緩存處理工具類

其實沒啥好寫的,就是封裝一些方法共外界調用,具體的話歡迎下載代碼查看。

##lib-core封裝淺談

說到這個模塊,就涉及到組件化的一些概念了。lib-core的概念主要就是爲上層mouble提供公共服務的一個隔離層,起到承上啓下的作用。比如說網絡與圖片,他肯定是所有mouble一定要使用的兩個功能。所以我把它封裝進了lib-core中,在其中採用代理模式隔離底層庫和上層mouble,更大程度的實現瞭解耦。下圖是他的構造。

這裏寫圖片描述

base:主要是MVP的一層封裝,採用泛型和繼承的思想進行了封裝,包括loading的顯示隱藏邏輯,網絡請求的控制,ButterKnife的的註冊與反註冊等等
bean:就會一個總的data類。
config:採用建造者模式給mouble提供網絡庫和圖片庫的全局初始化。
imagehelper:GlideManger提供的圖片加載的方法,mouble傳入固定的參數來加載想要的圖片。
nethelper:這個文件夾下寫了三個interceptor,可以打印okhttp的日誌和在header裏添加和獲取參數。(如果您項目沒在項目中在header中添加固定參數,也可以自定義interceptor實現參數的添加,項目在使用,後續會在demo更新中添加)
view:自定義的loading顯示,不在多說。

PS:關於此部分代碼,在這裏寫不列出,如果您正好有需要,歡迎下載共同學習。

##APPMouble:
主要是對封裝的庫的一些使用,沒啥好看的界面,爭取後面能夠補充到。

#寫在最後

適合自己的架構纔是最好的架構,希望和大家一起學習進步,也希望大家不令賜教。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章