APP架構(gòu)和mvp + retrofit + rxjava的設(shè)計

App項目架構(gòu)

來公司實習(xí)的第二個月,開始了人生的第二個項目。因為項目大,所以是多人合作,于是乎終于擺脫了在學(xué)校的那種跟著功能走的處境,有大佬搭了一個簡易的框架于是乎學(xué)習(xí)了一番

項目總覽

好像上傳不了照片,那就一點一點的說吧

1.netService包
這個包用于網(wǎng)絡(luò)上傳

Server.class 這個類的作用是用于存放整個項目所用到的接口地址

public class Server {

    public static final String getUserInfo = "/teacher-api/images/labels";

}

RetrofitService.class是引用Server.class的地址的retrofit的類

public interface RetrofitService {
    @GET(Server.getUserInfo)
    Flowable<BaseRsp> getUserInfo();
    

}

RetrofitHelper
它的作用通過單例模式獲得到retrofitService的實際操作對象

package com.example.yangyang.mvpproject.netService;

import com.example.yangyang.mvpproject.BuildConfig;
import com.google.gson.GsonBuilder;

import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitHelper {

    public static final String BASE_URL = "http://www.baidu.com";

    private static RetrofitHelper retrofitHelper = null;




    private RetrofitService retrofitService = null;


    private RetrofitHelper(){
        Retrofit retrofit = new Retrofit
                .Builder()
                .baseUrl(BASE_URL)
                .client(HttpsFactroy.getClient())

                .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().create()))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
        retrofitService = retrofit.create(RetrofitService.class);
    }

    public static RetrofitHelper getInstance(){
        if(retrofitHelper == null){
            synchronized (RetrofitHelper.class){
                if(retrofitHelper == null){
                    retrofitHelper = new RetrofitHelper();
                }
            }
        }
        return retrofitHelper;

    }

    public RetrofitService getRetrofitService(){
        return retrofitService;
    }




}


HttpsFactroy.class這個類的作用是用于得到client,同時自定義的攔截器,可以動態(tài)的在http請求中添加一些東西,比如token,同時導(dǎo)入一些第三方庫,可以加入http的日志攔截器

package com.example.yangyang.mvpproject.netService;

import android.util.Log;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.logging.HttpLoggingInterceptor;

public class HttpsFactroy {
    private static final int CONNECT_TIMEOUT = 10;
    private static final int READ_TIMEOUT = 10;

    //得到請求client
    public static OkHttpClient getClient(){
        //日志顯示級別
        HttpLoggingInterceptor.Level level= HttpLoggingInterceptor.Level.BODY;
        //新建log攔截器
        HttpLoggingInterceptor loggingInterceptor=new HttpLoggingInterceptor(message -> Log.i("HTTPS","OkHttp====Message:"+message));
        loggingInterceptor.setLevel(level);
        OkHttpClient client = null;
        try {
            client = new OkHttpClient.Builder()
                    .addInterceptor(loggingInterceptor)
                    .addInterceptor(new HeaderIntercepter())

                    .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                    .readTimeout(READ_TIMEOUT,TimeUnit.SECONDS)
                    .build();
        } catch (Exception e) {
            Log.e("error", Log.getStackTraceString(e));
        }

        return client;
    }


    /**
     * 用于動態(tài)添加header
     */
    private static class HeaderIntercepter implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain
                    .request()
                    .newBuilder()
                    /*.addHeader()*/
                    .build();
                    return chain.proceed(request);
        }
    }
}



DataManager.class
這個類是最后retrofit的入口,管理所有的http請求,其實說白了,知道retrofit怎么用,這幾個類都是對retrofit調(diào)用的一些封裝

package com.example.yangyang.mvpproject.netService;

import com.example.yangyang.mvpproject.base.BaseRsp;

import io.reactivex.Flowable;

public class DataManager {
    private RetrofitService mRetrofitService;

    public DataManager(){
        mRetrofitService = RetrofitHelper.getInstance().getRetrofitService();
    }
    public Flowable<BaseRsp> getUserInfo(){
        return mRetrofitService.getUserInfo();
    }
}


同時因為用的是rxjava,所以flowable之后得有一個下游的管道去接它,同時接數(shù)據(jù)的時候也得有一個回調(diào),所以在callback包里面就有一個整體的回調(diào)
2.callback

先上代碼
RequestCallBack.class

package com.example.yangyang.mvpproject.callback;

import android.util.Log;

import com.example.yangyang.mvpproject.base.BaseRsp;

import org.apache.http.conn.ConnectTimeoutException;

import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.Locale;

import javax.net.ssl.SSLException;

import io.reactivex.exceptions.OnErrorNotImplementedException;
import io.reactivex.subscribers.DisposableSubscriber;
import retrofit2.adapter.rxjava2.HttpException;

public abstract class RequestCallBack<T> extends DisposableSubscriber<BaseRsp<T>> {

    @Override
    public void onNext(BaseRsp<T> tBaseRsp) {
        if (tBaseRsp.getCode() == 200) {
            onReqSuccess(tBaseRsp.getData());
        }
        else {
            onBizError(tBaseRsp.getCode(),tBaseRsp.getMsg());
        }

    }

    @Override
    public void onError(Throwable e) {
        String msg;
        if ((e instanceof HttpException)) {
            msg = ((retrofit2.HttpException) e).message();
            onNetError(((retrofit2.HttpException) e).code(), msg);
        } else if (e instanceof UnknownHostException) {
            msg = "域名解析失敗";
            onNetError(-1001,msg);
        } else if (e instanceof ConnectTimeoutException) {
            msg = "連接超時";
            onNetError(-1002,msg);
        } else if (e instanceof SocketTimeoutException) {
            msg = "Socket連接超時";
            onNetError(-1003,msg);
        } else if (e instanceof NoRouteToHostException) {
            msg = "無法連接遠程地址與端口";
            onNetError(-1004,msg);
        } else if (e instanceof SSLException) {
            msg = "SSL失敗";
            onNetError(-1005,msg);
        } else if (e instanceof ConnectException) {
            msg = "連接失敗";
            onNetError(-1006,msg);
        } else if (e instanceof retrofit2.HttpException) {
            retrofit2.HttpException exception = (retrofit2.HttpException) e;
            msg = exception.message();
            Log.d("HttpException",msg);
            onNetError(exception.code(),msg);
        } else if (e instanceof OnErrorNotImplementedException) {
            msg = e.getMessage();
            onNetError(-1007, msg);
        }
         else {
            msg = "網(wǎng)絡(luò)請求出錯";
            onNetError(-1009, msg);
        }

    }

    @Override
    public void onComplete() {

    }

    protected abstract void onReqSuccess(T t);

    //業(yè)務(wù)錯誤
    protected abstract void onBizError(int code, String msg);

    //網(wǎng)絡(luò)錯誤
    protected abstract void onNetError(int code, String msg);


}

DisposableSubscriber其實我也不太了解具體,就當他是一個觀察者吧,<BaseRsp<T>這些事前后臺帶的一些數(shù)據(jù)其實也可以帶json數(shù)據(jù)然后自己來解析也可以的,同時最下面有3個抽象函數(shù),分別對應(yīng)成功了干啥,這些具體的回調(diào)函數(shù)的實現(xiàn)是放在p層實現(xiàn)的,p層再根據(jù)結(jié)果回調(diào)v層的方法

以上便是網(wǎng)絡(luò)層的封裝

2.mvp

-M層

一般來說我是一個activity一個model,如果兩個不同activity調(diào)用同一個接口,此時我會提取公共model,讓需要這個功能的人去繼承它,M層的功能就是進行數(shù)據(jù)轉(zhuǎn)化,同時將requestcall返回給p層

public class LoginModel {
    private DataManager manager;

    public LoginModel(DataManager manager) {
        this.manager = manager;
    }

    private RequestCallBack getUserInfo(RequestCallBack callBack){
         manager.getUserInfo()
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .subscribeOn(AndroidSchedulers.mainThread())
                .subscribe(callBack);
        return callBack;
    }
}


-P層

首先有一個BasePresenter,大家都知道的它的作用莫不過在于拿到V層的實例,以及要返回的數(shù)據(jù)

BasePresenter

package com.example.yangyang.mvpproject.mvp.presenter.base;

import com.example.yangyang.mvpproject.mvp.view.contract.base.BaseView;

public class BasePresenter <V extends BaseView , T > {

    protected V mview = null;

    public BasePresenter(V mview) {
        this.mview = mview;
    }
}

為什么會有泛型了,因為P層得持有V層的引用,但是并不知道V是哪個,所以加入V層泛型便能得到類型,但是后面接著的那個T其實可用可不用,刪掉也沒關(guān)系。因為T是從網(wǎng)絡(luò)端返回的數(shù)據(jù)類型,在RequestCall中我們已經(jīng)定義好了其類型,而且P層接Model層,M層接RequestCall中的泛型,所以刪除掉也可以的

BaseView

package com.example.yangyang.mvpproject.mvp.view.contract.base;

public interface BaseView {

    void showProgress();

    void dismissProgress();


}

這是在contract包中的base,contract包分為兩個,一個是V層接口,一個是impl包放的是activity和fragment的實現(xiàn),所以V extend BaseView ,activity和fragment實現(xiàn)這個V,但是其實BaseView的方法其實是共有的,其實是可以讓BaseActivity實現(xiàn)的,不用每個Activity或者fragment實現(xiàn)的,但有丟丟神奇的是,這個框架在BaseActivity中實現(xiàn)具體的 showProgress()和 dismissProgress();在每個activity中調(diào)用其方法,好吧,這樣也可以,

以上就是mvp的實現(xiàn)

3.BaseActivity

BaseActivity

package com.example.yangyang.mvpproject.mvp.view.impl.activity.base;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

import com.example.yangyang.mvpproject.mvp.view.contract.base.BaseView;
import com.example.yangyang.mvpproject.widget.dialog.ProgressDialog;
import com.example.yangyang.mvpproject.widget.placeHolder.PlaceHolderView;

public abstract class BaseActivity extends AppCompatActivity  {
    private ProgressDialog progressDialog = null;

    protected PlaceHolderView mPlaceHolderView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        initWindows();
        if (initArgs(getIntent().getExtras())) {
            setContentView(getContentLayoutId());
            initWidget();
            initData();
        } else {
            Toast.makeText(this, "Bundle傳值錯誤", Toast.LENGTH_SHORT).show();
        }
    }

    protected void initWindows() {

    }

    protected boolean initArgs(Bundle bundle) {  // Bundle傳值拿參數(shù)時可以復(fù)寫這個函數(shù)
        return true;
    }

    protected abstract int getContentLayoutId();

    protected void initWidget() {

    }

    protected void initData() {

    }

    protected void showProgress(String message){
        if (progressDialog == null){
            progressDialog = new ProgressDialog(this);
            progressDialog.setMessage(message);
            progressDialog.show();
        }
    }
    protected void hideProgress(){
        if (progressDialog != null){
            progressDialog.dismiss();
        }
    }

    protected void setmPlaceHolderView(PlaceHolderView mPlaceHolderView) {
        this.mPlaceHolderView = mPlaceHolderView;
    }
}

這個我是借鑒了之前的一個BaseActivity搭建,將view 和 data的初始化分開了,同時因為intent中帶有bundle,可以復(fù)寫initArgs將bundle取出,其實在這里是可以實現(xiàn)Baseview的方法,就不用每個界面都重寫這兩個方法了

重點介紹下PlaceHolderView 是當我們數(shù)據(jù)返回為空或者網(wǎng)絡(luò)錯誤時我們一般都會顯示一個界面,這個占位布局的功能就是如此

先貼出PlaceHolderView 代碼,他只是一個接口啦

package com.example.yangyang.mvpproject.widget.placeHolder;

import android.support.annotation.StringRes;

public interface PlaceHolderView {
    /**
     * 沒有數(shù)據(jù)
     * 顯示空布局,隱藏當前數(shù)據(jù)布局
     */
    void triggerEmpty();

    /**
     * 網(wǎng)絡(luò)錯誤
     * 顯示一個網(wǎng)絡(luò)錯誤的圖標
     */
    void triggerNetError();

    /**
     * 加載錯誤,并顯示錯誤信息
     *
     * @param strRes 錯誤信息
     */
    void triggerError(@StringRes int strRes);

    /**
     * 顯示正在加載的狀態(tài)
     */
    void triggerLoading();

    /**
     * 數(shù)據(jù)加載成功,
     * 調(diào)用該方法時應(yīng)該隱藏當前占位布局
     */
    void triggerOk();

    /**
     * 該方法如果傳入的isOk為True則為成功狀態(tài),
     * 此時隱藏布局,反之顯示空數(shù)據(jù)布局
     *
     * @param isOk 是否加載成功數(shù)據(jù)
     */
    void triggerOkOrEmpty(boolean isOk);


}


這里有注釋我就不說了

其實現(xiàn)類是EmptyView

package com.example.yangyang.mvpproject.widget.placeHolder;

import android.content.Context;
import android.opengl.Visibility;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.example.yangyang.mvpproject.R;

public class EmptyView extends LinearLayout implements PlaceHolderView {

    private ImageView mEmptyImg;
    private TextView mStatusText;

    private int[] mDrawableIds = new int[]{0, 0};  // 設(shè)置不同情況下的圖片
    private String[] mTextI = { "數(shù)據(jù)為空","網(wǎng)絡(luò)不太好啊"};   //設(shè)置不同情況下的文字

    private View[] mBindViews;

    public EmptyView(Context context) {
        super(context);
        init(null, 0);
    }

    public EmptyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(attrs,0);
    }

    public EmptyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs,0);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public EmptyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(attrs,0);
    }

    private void init(AttributeSet attrs, int defStyle) {
        inflate(getContext(), R.layout.layout_empty, this);
        mEmptyImg = findViewById(R.id.img_empty);
        mStatusText = findViewById(R.id.txt_empty);


    }

    /**
     * 將外部布局綁定進來
     * @param views
     */

    public void bind(View... views) {
        this.mBindViews = views;
    }

    /**
     * 隱藏外部布局
     * @param visible
     */

    private void changeBindViewVisibility(int visible) {
        final View[] views = mBindViews;
        if (views == null || views.length == 0)
            return;

        for (View view : views) {
            view.setVisibility(visible);
        }
    }

    @Override
    public void triggerEmpty() {
        mEmptyImg.setImageResource(mDrawableIds[0]);
        mStatusText.setText(mTextI[0]);
        setVisibility(VISIBLE);

        changeBindViewVisibility(GONE);

    }

    @Override
    public void triggerNetError() {
        mEmptyImg.setImageResource(mDrawableIds[1]);
        mStatusText.setText(mTextI[1]);
        setVisibility(VISIBLE);

        changeBindViewVisibility(GONE);
    }

    @Override
    public void triggerError(int strRes) {

    }

    @Override
    public void triggerLoading() {

    }

    @Override
    public void triggerOk() {

        setVisibility(GONE);

        changeBindViewVisibility(VISIBLE);

    }

    @Override
    public void triggerOkOrEmpty(boolean isOk) {
        if (isOk) triggerOk();
        else triggerEmpty();

    }
}

主要是就是bind方法 就是你要講你所改變的布局給傳進來,然后通過changeBindViewVisibility()來將傳進來布局設(shè)置為可見或者不可見()ememm反正我剛開始看時候沒看懂的,后來才知道啥回事,入宮看不懂問我怎么用吧,我會仔細講解

這個時候,BaseActivity中的PlaceHolderView 就是EmptyView 所以將這個布局寫上去,就可以控制可見與不可見了,我覺得超叼,我以前寫項目都是在activity里面臨時判斷,代碼賊多,還難改,佩服佩服

這個是BaseFragment

package com.i61.user.teacher.mvp.view.impl.fragment.base;


import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.i61.user.teacher.mvp.dialog.ProgressDialog;
import com.i61.user.teacher.mvp.view.contract.base.BaseViewInterface;
import com.i61.user.teacher.networkServices.disposable.SubscriptionManager;

import java.util.List;

/**
 * 所有fragment繼承此fragment(onFragmentResume和onFragmentPause:fragment的可見和不可見,避免了fragment生命周期對不的情況)
 */
public abstract class BaseFragment extends Fragment {

    private boolean isLastVisible = false;
    private boolean hidden = false;
    private boolean isFirst = true;
    private boolean isResuming = false;
    private boolean isViewDestroyed = false;

    private ProgressDialog progressDialog;

    protected View parentView;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        isLastVisible = false;
        hidden = false;
        isFirst = true;
        isViewDestroyed = false;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        parentView = inflater.inflate(getLayoutResId(), container, false);
        return parentView;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        finishCreateView(savedInstanceState);
    }

    /**
     *  把Fragment里的請求綁到生命周期上
     */
    public abstract BaseViewInterface bindToFragmentCycle();

    /**
     * 添加layout
     * @return
     */
    public abstract int getLayoutResId();

    /**
     * view完成了創(chuàng)建
     * @param state
     */
    public abstract void finishCreateView(Bundle state);
    /**
     * Fragment 可見時回調(diào)
     *
     * @param isFirst       是否是第一次顯示
     * @param isViewDestroyed Fragment中的View是否被回收過。
     * 存在這種情況:Fragment 的 View 被回收,但是Fragment實例仍在。
     */
    protected void onFragmentResume(boolean isFirst, boolean isViewDestroyed) {
    }

    /**
     * Fragment 不可見時回調(diào)
     */
    protected void onFragmentPause() {
    }

    /**
     * fragment里面顯示loading
     */
    protected void showProgressDialog(String msg) {
        if (progressDialog == null) {
            progressDialog = new ProgressDialog(getActivity());
            progressDialog.setTextView(msg);
            progressDialog.show();
        }
    }

    /**
     * fragment隱藏loading
     */
    protected void hideProgressDialog() {
        if (progressDialog != null && progressDialog.isShowing()) {
            progressDialog.dismiss();
            progressDialog = null;
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        isResuming = true;
        tryToChangeVisibility(true);
    }

    @Override
    public void onPause() {
        super.onPause();
        isResuming = false;
        tryToChangeVisibility(false);
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        setUserVisibleHintClient(isVisibleToUser);
    }

    private void setUserVisibleHintClient(boolean isVisibleToUser) {
        tryToChangeVisibility(isVisibleToUser);
        if (isAdded()) {
            // 當Fragment不可見時,其子Fragment也是不可見的。因此要通知子Fragment當前可見狀態(tài)改變了。
            List<Fragment> fragments = getChildFragmentManager().getFragments();
            if (fragments != null) {
                for (Fragment fragment : fragments) {
                    if (fragment instanceof BaseFragment) {
                        ((BaseFragment) fragment).setUserVisibleHintClient(isVisibleToUser);
                    }
                }
            }
        }
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        onHiddenChangedClient(hidden);
    }

    public void onHiddenChangedClient(boolean hidden) {
        this.hidden = hidden;
        tryToChangeVisibility(!hidden);
        if (isAdded()) {
            List<Fragment> fragments = getChildFragmentManager().getFragments();
            if (fragments != null) {
                for (Fragment fragment : fragments) {
                    if (fragment instanceof BaseFragment) {
                        ((BaseFragment) fragment).onHiddenChangedClient(hidden);
                    }
                }
            }
        }
    }

    private void tryToChangeVisibility(boolean tryToShow) {
        // 上次可見
        if (isLastVisible) {
            if (tryToShow) {
                return;
            }
            if (!isFragmentVisible()) {
                onFragmentPause();
                isLastVisible = false;
            }
            // 上次不可見
        } else {
            boolean tryToHide = !tryToShow;
            if (tryToHide) {
                return;
            }
            if (isFragmentVisible()) {
                onFragmentResume(isFirst, isViewDestroyed);
                isLastVisible = true;
                isFirst = false;
            }
        }
    }

    //Fragment是否可見
    public boolean isFragmentVisible() {
        if (isResuming()
                && getUserVisibleHint()
                && !hidden) {
            return true;
        }
        return false;
    }

    //Fragment 是否在前臺
    private boolean isResuming() {
        return isResuming;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        isViewDestroyed = true;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(bindToFragmentCycle() != null){
            SubscriptionManager.getInstance().removeViewReqs(bindToFragmentCycle());
        }
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
    }

    @Override
    public void onDetach() {
        super.onDetach();
    }
}

哈哈我差點把這個遺漏了,主要是我自己也沒看,不過很簡單的,我先把代碼貼出來

其余就直接貼代碼了

RecyclerView的封裝

對application 的封裝

ActivityLifecycle

package com.example.yangyang.mvpproject.app;

import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class ActivityLifecycle implements Application.ActivityLifecycleCallbacks {

    public static final String IS_NOT_ADD_ACTIVITY_LIST = "IS_NOT_ADD_ACTIVITY_LIST";

    private ActivityManager activityManager;

    public ActivityLifecycle(ActivityManager activityManager) {
        this.activityManager = activityManager;
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        //如果intent包含了此字段,并且為true說明不加入到list
        // 默認為false,如果不需要管理(比如不需要在退出所有activity(killAll)時,退出此activity就在intent加此字段為true)
        boolean isNotAdd = false;
        if (activity.getIntent() != null)
            isNotAdd = activity.getIntent().getBooleanExtra(IS_NOT_ADD_ACTIVITY_LIST, false);

        if (!isNotAdd)
            activityManager.addActivity(activity);

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityResumed(Activity activity) {
        activityManager.setCurrentActivity(activity);

    }

    @Override
    public void onActivityPaused(Activity activity) {
        if (activityManager.getCurrentActivity() == activity) {
            activityManager.setCurrentActivity(null);
        }

    }

    @Override
    public void onActivityStopped(Activity activity) {

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        activityManager.removeActivity(activity);
    }
}


ActivityManager

package com.example.yangyang.mvpproject.app;

import android.app.Activity;
import android.app.Application;
import android.content.Intent;
import android.view.View;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class ActivityManager {

    private Application mApplication;

    //管理所有activity
    public List<Activity> mActivityList;
    //當前在前臺的activity
    private static Activity mCurrentActivity;



    private static ActivityManager mInstance;

    public static ActivityManager getInstance(Application application) {
        if (mInstance == null) {
            synchronized (ActivityManager.class) {
                if (mInstance == null) {
                    mInstance = new ActivityManager(application);
                }
            }
        }
        return mInstance;
    }

    private ActivityManager(Application application) {
        this.mApplication = application;
    }
    /**
     * 使用snackbar顯示內(nèi)容
     *
     * @param message
     * @param isLong
     */
    public void showSnackbar(String message, boolean isLong) {
        if (getCurrentActivity() == null) {
            return;
        }
        View view = getCurrentActivity().getWindow().getDecorView().findViewById(android.R.id.content);

    }


    /**
     * 讓在前臺的activity,打開下一個activity
     *
     * @param intent
     */
    public void startActivity(Intent intent) {
        if (getCurrentActivity() == null) {
            //如果沒有前臺的activity就使用new_task模式啟動activity
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            mApplication.startActivity(intent);
            return;
        }
        getCurrentActivity().startActivity(intent);
    }

    /**
     * 讓在前臺的activity,打開下一個activity
     *
     * @param activityClass
     */
    public void startActivity(Class activityClass) {
        startActivity(new Intent(mApplication, activityClass));
    }

    /**
     * 釋放資源
     */
    public void release() {
        mActivityList.clear();
        mActivityList = null;
        mCurrentActivity = null;
        mApplication = null;
    }

    /**
     * 將在前臺的activity保存
     *
     * @param currentActivity
     */
    public void setCurrentActivity(Activity currentActivity) {
        this.mCurrentActivity = currentActivity;
    }

    /**
     * 獲得當前在前臺的activity
     *
     * @return
     */
    public static Activity getCurrentActivity() {
        return mCurrentActivity;
    }

    /**
     * 返回一個存儲所有未銷毀的activity的集合
     *
     * @return
     */
    public List<Activity> getActivityList() {
        if (mActivityList == null) {
            mActivityList = new LinkedList<>();
        }
        return mActivityList;
    }


    /**
     * 添加Activity到集合
     */
    public void addActivity(Activity activity) {
        if (mActivityList == null) {
            mActivityList = new LinkedList<>();
        }
        synchronized (ActivityManager.class) {
            if (!mActivityList.contains(activity)) {
                mActivityList.add(activity);
            }
        }
    }

    /**
     * 刪除集合里的指定activity
     *
     * @param activity
     */
    public void removeActivity(Activity activity) {
        if (mActivityList == null) {
            return;
        }
        synchronized (ActivityManager.class) {
            if (mActivityList.contains(activity)) {
                mActivityList.remove(activity);
            }
        }
    }

    /**
     * 刪除集合里的指定位置的activity
     *
     * @param location
     */
    public Activity removeActivity(int location) {
        if (mActivityList == null) {
            return null;
        }
        synchronized (ActivityManager.class) {
            if (location > 0 && location < mActivityList.size()) {
                return mActivityList.remove(location);
            }
        }
        return null;
    }

    /**
     * 關(guān)閉指定activity
     *
     * @param activityClass
     */
    public void killActivity(Class<?> activityClass) {
        if (mActivityList == null) {
            return;
        }
        for (Activity activity : mActivityList) {
            if (activity.getClass().equals(activityClass)) {
                activity.finish();
            }
        }
    }


    /**
     * 指定的activity實例是否存活
     *
     * @param activity
     * @return
     */
    public boolean activityInstanceIsLive(Activity activity) {
        if (mActivityList == null) {
            return false;
        }
        return mActivityList.contains(activity);
    }


    /**
     * 指定的activity class是否存活(一個activity可能有多個實例)
     *
     * @param activityClass
     * @return
     */
    public boolean activityClassIsLive(Class<?> activityClass) {
        if (mActivityList == null) {
            return false;
        }
        for (Activity activity : mActivityList) {
            if (activity.getClass().equals(activityClass)) {
                return true;
            }
        }

        return false;
    }


    /**
     * 關(guān)閉所有activity
     */
    private void killAll() {

        Iterator<Activity> iterator = getActivityList().iterator();
        while (iterator.hasNext()) {
            iterator.next().finish();
            iterator.remove();
        }

    }


    /**
     * 退出應(yīng)用程序
     */
    public void AppExit() {
        try {
            killAll();
            if (mActivityList != null)
                mActivityList = null;
//            android.app.ActivityManager activityMgr =
//                    (android.app.ActivityManager) mApplication.getSystemService(Context.ACTIVITY_SERVICE);
//            activityMgr.killBackgroundProcesses(mApplication.getPackageName());
//            System.exit(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


MyApp

package com.example.yangyang.mvpproject.app;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Application;
import android.os.Build;

import java.util.LinkedList;
import java.util.List;

public class MyApp extends Application {

    /**
     * 需要持有context的方法可以傳遞這個app,避免內(nèi)存泄漏
     */
    public static MyApp app = null;

    /**
     * Activity管理
     */
    private List<Activity> mActivityList = new LinkedList<>();
    protected ActivityManager mActivityManager;
    protected ActivityLifecycle mActivityLifecycle;



    @Override
    public void onCreate() {
        super.onCreate();

        app = this;

        mActivityManager = ActivityManager.getInstance(this);

        mActivityLifecycle = new ActivityLifecycle(mActivityManager);

        registerActivityLifecycleCallback(mActivityLifecycle);


    }

    public List<Activity> getmActivityList() {
        return mActivityList;
    }

    public void setmActivityList(List<Activity> mActivityList) {
        this.mActivityList = mActivityList;
    }

    /**
     * 添加activity
     * @param activity
     */
    public void addActivity(Activity activity) {
        if (mActivityList != null && mActivityList.size() > 0) {
            if (!mActivityList.contains(activity)) {
                mActivityList.add(activity);
            }
        } else {
            mActivityList.add(activity);
        }
    }

    /**
     * 移除activity
     */
    public void removeActivity(Activity activity) {
        if (mActivityList != null && mActivityList.size() > 0) {
            if (mActivityList.contains(activity)) {
                mActivityList.remove(activity);
            }
        }
    }

    /**
     * 遍歷mActivityList,結(jié)束每一個activity的聲明周期
     */
    public void finishAllActivityt() {
        if (mActivityList != null && mActivityList.size() > 0) {
            for (Activity activity : mActivityList) {
                activity.finish();
            }
        }
    }
    /**
     * 完全退出程序
     */
    public void appExit() {
        finishAllActivityt();
        // 正常退出
        System.exit(0);
    }
    /**
     * 出現(xiàn)異常殺掉進程
     */
    public void appKill() {
        finishAllActivityt();
        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(1);
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public void registerActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) {
        this.registerActivityLifecycleCallbacks(callbacks);
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    public void unregisterActivityLifecycleCallback(Application.ActivityLifecycleCallbacks callbacks) {
        this.unregisterActivityLifecycleCallbacks(callbacks);
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        if (mActivityLifecycle != null) {
            unregisterActivityLifecycleCallback(mActivityLifecycle);
        }
        if (mActivityManager != null) {//釋放資源
            this.mActivityManager.release();
            this.mActivityManager = null;
        }
        if(app != null){
            app = null;
        }
    }
}

其實還有對RecyclerView的封裝,這是我看視頻學(xué)到的,其實,也不難

package com.example.base.base.recycler;

import android.support.annotation.LayoutRes;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.example.base.R;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import butterknife.ButterKnife;
import butterknife.Unbinder;

public abstract class RecyclerAdapter<Data>
        extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder<Data>>
        implements View.OnClickListener, View.OnLongClickListener, AdapterCallback<Data> {
    private final List<Data> mDataList;
    private AdapterListener<Data> mListener;

    /**
     * 構(gòu)造函數(shù)模塊
     */
    public RecyclerAdapter() {
        this(null);
    }

    public RecyclerAdapter(AdapterListener<Data> listener) {
        this(new ArrayList<Data>(), listener);
    }

    public RecyclerAdapter(List<Data> dataList, AdapterListener<Data> listener) {
        this.mDataList = dataList;
        this.mListener = listener;
    }

    /**
     * 復(fù)寫默認的布局類型返回
     *
     * @param position 坐標
     * @return 類型,其實復(fù)寫后返回的都是XML文件的ID
     */
    @Override
    public int getItemViewType(int position) {
        return getItemViewType(position, mDataList.get(position));
    }

    /**
     * 得到布局的類型
     *
     * @param position 坐標
     * @param data     當前的數(shù)據(jù)
     * @return XML文件的ID,用于創(chuàng)建ViewHolder
     */
    @LayoutRes
    protected abstract int getItemViewType(int position, Data data);

    /**
     * 創(chuàng)建一個ViewHolder
     *
     * @param parent   RecyclerView
     * @param viewType 界面的類型,約定為XML布局的Id
     * @return ViewHolder
     */
    @Override
    public ViewHolder<Data> onCreateViewHolder(ViewGroup parent, int viewType) {
        // 得到LayoutInflater用于把XML初始化為View
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        // 把XML id為viewType的文件初始化為一個root View
        View root = inflater.inflate(viewType, parent, false);
        // 通過子類必須實現(xiàn)的方法,得到一個ViewHolder
        ViewHolder<Data> holder = onCreateViewHolder(root, viewType);


        // 設(shè)置View的Tag為ViewHolder,進行雙向綁定
        root.setTag(R.id.tag_recycler_holder, holder);
        // 設(shè)置事件點擊
        root.setOnClickListener(this);
        root.setOnLongClickListener(this);

        // 進行界面注解綁定
        holder.unbinder = ButterKnife.bind(holder, root);
        // 綁定callback
        holder.callback = this;

        return holder;
    }

    /**
     * 得到一個新的ViewHolder
     *
     * @param root     根布局
     * @param viewType 布局類型,其實就是XML的ID
     * @return ViewHolder
     */
    protected abstract ViewHolder<Data> onCreateViewHolder(View root, int viewType);

    /**
     * 綁定數(shù)據(jù)到一個Holder上
     *
     * @param holder   ViewHolder
     * @param position 坐標
     */
    @Override
    public void onBindViewHolder(ViewHolder<Data> holder, int position) {
        // 得到需要綁定的數(shù)據(jù)
        Data data = mDataList.get(position);
        // 觸發(fā)Holder的綁定方法
        holder.bind(data);
    }

    /**
     * 得到當前集合的數(shù)據(jù)量
     */
    @Override
    public int getItemCount() {
        return mDataList.size();
    }

    /**
     * 返回整個集合
     *
     * @return List<Data>
     */
    public List<Data> getItems() {
        return mDataList;
    }

    /**
     * 插入一條數(shù)據(jù)并通知插入
     *
     * @param data Data
     */
    public void add(Data data) {
        mDataList.add(data);
        notifyItemInserted(mDataList.size() - 1);
    }

    /**
     * 插入一堆數(shù)據(jù),并通知這段集合更新
     *
     * @param dataList Data
     */
    public void add(Data... dataList) {
        if (dataList != null && dataList.length > 0) {
            int startPos = mDataList.size();
            Collections.addAll(mDataList, dataList);
            notifyItemRangeInserted(startPos, dataList.length);
        }
    }

    /**
     * 插入一堆數(shù)據(jù),并通知這段集合更新
     *
     * @param dataList Data
     */
    public void add(Collection<Data> dataList) {
        if (dataList != null && dataList.size() > 0) {
            int startPos = mDataList.size();
            mDataList.addAll(dataList);
            notifyItemRangeInserted(startPos, dataList.size());
        }
    }

    /**
     * 刪除操作
     */
    public void clear() {
        mDataList.clear();
        notifyDataSetChanged();
    }

    /**
     * 替換為一個新的集合,其中包括了清空
     *
     * @param dataList 一個新的集合
     */
    public void replace(Collection<Data> dataList) {
        mDataList.clear();
        if (dataList == null || dataList.size() == 0)
            return;
        mDataList.addAll(dataList);
        notifyDataSetChanged();
    }



    @Override
    public void update(Data data, ViewHolder<Data> holder) {
        // 得到當前ViewHolder的坐標
        int pos = holder.getAdapterPosition();
        if (pos >= 0) {
            // 進行數(shù)據(jù)的移除與更新
            mDataList.remove(pos);
            mDataList.add(pos, data);
            // 通知這個坐標下的數(shù)據(jù)有更新
            notifyItemChanged(pos);
        }
    }

    @Override
    public void onClick(View v) {
        ViewHolder viewHolder = (ViewHolder) v.getTag(R.id.tag_recycler_holder);
        if (this.mListener != null) {
            // 得到ViewHolder當前對應(yīng)的適配器中的坐標
            int pos = viewHolder.getAdapterPosition();
            // 回掉方法
            this.mListener.onItemClick(viewHolder, mDataList.get(pos));
        }

    }

    @Override
    public boolean onLongClick(View v) {
        ViewHolder viewHolder = (ViewHolder) v.getTag(R.id.tag_recycler_holder);
        if (this.mListener != null) {
            // 得到ViewHolder當前對應(yīng)的適配器中的坐標
            int pos = viewHolder.getAdapterPosition();
            // 回掉方法
            this.mListener.onItemLongClick(viewHolder, mDataList.get(pos));
            return true;
        }
        return false;
    }

    /**
     * 設(shè)置適配器的監(jiān)聽
     *
     * @param adapterListener AdapterListener
     */
    public void setListener(AdapterListener<Data> adapterListener) {
        this.mListener = adapterListener;
    }

    /**
     * 我們的自定義監(jiān)聽器
     *
     * @param <Data> 范型
     */
    public interface AdapterListener<Data> {
        // 當Cell點擊的時候觸發(fā)
        void onItemClick(RecyclerAdapter.ViewHolder holder, Data data);

        // 當Cell長按時觸發(fā)
        void onItemLongClick(RecyclerAdapter.ViewHolder holder, Data data);
    }

    /**
     * 自定義的ViewHolder
     *
     * @param <Data> 范型類型
     */
    public static abstract class ViewHolder<Data> extends RecyclerView.ViewHolder {
        private Unbinder unbinder;
        private AdapterCallback<Data> callback;
        protected Data mData;

        public ViewHolder(View itemView) {
            super(itemView);
        }

        /**
         * 用于綁定數(shù)據(jù)的觸發(fā)
         *
         * @param data 綁定的數(shù)據(jù)
         */
        void bind(Data data) {
            this.mData = data;
            onBind(data);
        }

        /**
         * 當觸發(fā)綁定數(shù)據(jù)的時候,的回掉;必須復(fù)寫
         *
         * @param data 綁定的數(shù)據(jù)
         */
        protected abstract void onBind(Data data);

        /**
         * Holder自己對自己對應(yīng)的Data進行更新操作
         *
         * @param data Data數(shù)據(jù)
         */
        public void updateData(Data data) {
            if (this.callback != null) {
                this.callback.update(data, this);
            }
        }
    }

}
package com.example.base.base.recycler;

/**
 * @author qiujuer Email:qiujuer@live.cn
 * @version 1.0.0
 */
public interface AdapterCallback<Data> {
    void update(Data data, RecyclerAdapter.ViewHolder<Data> holder);
}

接下來便是我以前沒聽過的,加入網(wǎng)絡(luò)返回數(shù)據(jù)并更改UI時,此時Activity被finish掉了,這時候改UI會讓app崩掉,所以要進行截斷,這運用了rxjava2的知識

package com.example.yangyang.mvpproject.netService.disposable;

import com.example.yangyang.mvpproject.mvp.view.contract.base.BaseView;


import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;

/**
 * @description:訂閱關(guān)系處理
 */

public class SubscriptionManager {

    private static SubscriptionManager mManager;
    private CompositeDisposable mDisposables;

    /**
     * 分view保存請求
     */
    private Map<BaseView,List<Disposable>> reqMap;

    private SubscriptionManager() {
        if (mDisposables == null) {
            mDisposables = new CompositeDisposable();
            reqMap = new HashMap<>();
        }
    }

    public synchronized void add(BaseView v, Disposable subscription) {
        if (subscription == null) return;
        mDisposables.add(subscription);

        List<Disposable> requestCallBacks = reqMap.get(v);
        if(requestCallBacks == null){
            requestCallBacks = new LinkedList<>();
        }
        requestCallBacks.add(subscription);
        reqMap.put(v,requestCallBacks);
    }

    public synchronized void remove(Disposable t) {
        if (mDisposables != null) {
            mDisposables.remove(t);
        }
    }

    /**
     * @param v 當前發(fā)起請求的界面
     */
    public synchronized void removeViewReqs(BaseView v){
        try {
            List<Disposable> disposables = reqMap.get(v);
            if(disposables != null){
                for (Disposable t : disposables){
                    remove(t);
                    if(disposables != null){
                        disposables.remove(t);
                    }
                }
            }
        }catch (Exception e){

        }

    }

    public void clear() {
        if (mDisposables != null) {
            mDisposables.clear();
        }
    }

    public static SubscriptionManager getInstance() {
        if (mManager == null) {
            synchronized (SubscriptionManager.class) {
                if (mManager == null) {
                    mManager = new SubscriptionManager();
                }
            }
        }
        return mManager;
    }

}

整個框架大致如此,一些具體實現(xiàn)的細節(jié)我會分部慢慢解析,對此還會擴展

正所謂 活到老學(xué)到死

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容