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é)到死