BaseApp
import android.app.Application;
import android.content.res.Resources;
import android.support.v7.app.AppCompatDelegate;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
public class BaseApp extends Application {
private static BaseApp sBaseApp;
//默认不是夜间模式
public static int mMode = AppCompatDelegate.MODE_NIGHT_NO;
public static int mWidthPixels;
public static int mHeightPixels;
@Override
public void onCreate() {
super.onCreate();
sBaseApp = this;
getScreenWH();
}
//计算屏幕宽高
private void getScreenWH() {
WindowManager manager = (WindowManager) getSystemService(WINDOW_SERVICE);
Display defaultDisplay = manager.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
defaultDisplay.getMetrics(metrics);
mWidthPixels = metrics.widthPixels;
mHeightPixels = metrics.heightPixels;
}
public static BaseApp getInstance(){
return sBaseApp;
}
public static Resources getRes() {
return sBaseApp.getResources();
}
}
BaseActivity
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import butterknife.ButterKnife;
/**
* MVP
* V: 视图展示+用户交互
* P: V层和M层的桥梁+业务逻辑
* M: 负责数据处理:网络/文件/数据库...耗时操作
*/
public abstract class BaseActivity<V extends BaseView,P extends BasePresenter> extends AppCompatActivity{
protected P basePresenter;
private LoadingDialog mLoadingDialog;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(initLayoutId());
ButterKnife.bind(this);
basePresenter = initPresenter();
if (basePresenter!=null){
//可以强转,但是不对,但是这个基类的子类肯定会实现BaseView或者他的子类
//mPresenter.bind((BaseMvpView) this);
basePresenter.bind((V) this);
}
initView();
initListener();
initData();
}
protected abstract P initPresenter();
protected void initView() {
}
protected void initListener() {
}
protected void initData() {
}
protected abstract int initLayoutId();
@Override
protected void onDestroy() {
super.onDestroy();
basePresenter.onDestory();
basePresenter = null;
}
@Override
public void showLoading() {
if (mLoadingDialog == null){
mLoadingDialog = new LoadingDialog(this);
}
mLoadingDialog.show();
}
@Override
public void hideLoading() {
if (mLoadingDialog != null && mLoadingDialog.isShowing()){
mLoadingDialog.dismiss();
}
}
}
LoadingDialog(有需要时用)
用来显示请求网络数据之前的加载动画
在res文件夹下的drawable文件里创建loading_img.xml
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/icon_loading"
android:pivotX="50%"
android:pivotY="50%" />
在layout文件夹里创建loading_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/loading_img">
</ImageView>
在values文件夹里的styles.xml文件里
<style name="LoadingTheme" parent="Theme.AppCompat.Dialog">
<!--dialog背景设置为透明-->
<item name="android:windowBackground">@color/transparent</item>
<!--去掉背景半透明效果-->
<item name="android:backgroundDimEnabled">false</item>
</style>
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.example.lenovo.everywheretravel.R;
public class LoadingDialog extends Dialog{
public LoadingDialog(@NonNull Context context) {
super(context,R.style.LoadingTheme);
}
public LoadingDialog(@NonNull Context context, int themeResId) {
super(context, themeResId);
}
protected LoadingDialog(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) {
super(context, cancelable, cancelListener);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loading_dialog);
}
}
用法
因为是在BaseActivity中写的显示动画的方法,所以要调用这个方法的界面必须是继承自BaseActivity,然后直接在监听里调用showLoading()就可以了
BasePresenter
public abstract class BasePresenter<V extends BaseView> {
protected V view;
protected ArrayList<BaseModel> mModels = new ArrayList<>();
public void bind(V view) {
this.view=view;
}
public BasePresenter() {
initModel();
}
protected abstract void initModel();
public void onDestory() {
//打断P层和V层的联系,
view = null;
//掐断网络请求
if (mModels.size()>0){
for (BaseModel model :mModels) {
model.onDestory();
}
mModels.clear();
}
}
}
BaseView
public interface BaseView {
//显示加载loading的方法
void showLoading();
//隐藏加载loading的方法
void hideLoading();
}
BaseModel
public class BaseModel {
private CompositeDisposable mCompositeDisposable;
public void onDestory() {
//切换所有的Disposable对象
if (mCompositeDisposable!=null){
mCompositeDisposable.clear();
}
}
public void addDisposable(Disposable d){
if (mCompositeDisposable == null){
mCompositeDisposable = new CompositeDisposable();
}
mCompositeDisposable.add(d);
}
}
BaseFragment
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 butterknife.ButterKnife;
import butterknife.Unbinder;
public abstract class BaseFragment<V extends BaseView,P extends BasePresenter> extends Fragment {
private Unbinder unbinder;
protected P basePresenter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(initLayoutId(), null);
unbinder = ButterKnife.bind(this, view);
basePresenter = initPresenter();
if (basePresenter!=null){
basePresenter.bind((V) this);
}
initView();
initListener();
initData();
return view;
}
protected void initView() {
}
protected void initListener() {
}
protected void initData() {
}
protected abstract P initPresenter();
protected abstract int initLayoutId();
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
basePresenter.onDestory();
basePresenter = null;
}
}
res文件夹下的values文件夹里的strings.xml文件里
<resources>
// app_name 项目生成时自带的,只需要复制下面的就行
//<string name="app_name">EveryWhereTravel</string>
<string name="unknow_error">未知错误</string>
<string name="conn_error">连接失败</string>
<string name="conn_timeout">连接超时</string>
<string name="net_error">网络错误</string>
<string name="parse_error">解析异常</string>
<string name="net_unused">当前网络不可用</string>
</resources>
BaseObserver
SystemUtil和ToastUtil在工具类里
import android.net.ParseException;
import com.example.lenovo.everywheretravel.utils.Logger;
import com.example.lenovo.everywheretravel.utils.SystemUtil;
import com.example.lenovo.everywheretravel.utils.ToastUtil;
import com.google.gson.JsonParseException;
import org.json.JSONException;
import java.io.InterruptedIOException;
import java.net.ConnectException;
import java.net.UnknownHostException;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import retrofit2.HttpException;
public abstract class BaseObserver<T> implements Observer<T> {
private final String TAG = getClass().getName();
/**
* 解析数据失败
*/
public static final int PARSE_ERROR = 1001;
/**
* 网络问题
*/
public static final int BAD_NETWORK = 1002;
/**
* 连接错误
*/
public static final int CONNECT_ERROR = 1003;
/**
* 连接超时
*/
public static final int CONNECT_TIMEOUT = 1004;
@Override
public void onError(Throwable e) {
Logger.logD(TAG, "error: "+e.toString());
if (e instanceof HttpException) {
// HTTP错误
onException(BAD_NETWORK);
} else if (e instanceof ConnectException
|| e instanceof UnknownHostException) {
// 连接错误
onException(CONNECT_ERROR);
} else if (e instanceof InterruptedIOException) {
// 连接超时
onException(CONNECT_TIMEOUT);
} else if (e instanceof JsonParseException
|| e instanceof JSONException
|| e instanceof ParseException) {
// 解析错误
onException(PARSE_ERROR);
} else {
if (e != null) {
error(e.toString());
} else {
error(BaseApp.getRes().getString(R.string.unknow_error));
}
}
}
private void onException(int unknownError) {
switch (unknownError) {
case CONNECT_ERROR:
error(BaseApp.getRes().getString(R.string.conn_error));
break;
case CONNECT_TIMEOUT:
error(BaseApp.getRes().getString(R.string.conn_timeout));
break;
case BAD_NETWORK:
error(BaseApp.getRes().getString(R.string.net_error));
break;
case PARSE_ERROR:
error(BaseApp.getRes().getString(R.string.parse_error));
break;
default:
break;
}
}
public abstract void error(String msg);
@Override
public void onComplete() {
Logger.logD(TAG, "onComplete: ");
}
@Override
public void onSubscribe(Disposable d) {
if (!SystemUtil.isNetworkConnected()){
ToastUtil.showShort(BaseApp.getRes().getString(R.string.net_unused));
return;
}
subscribe(d);
}
protected abstract void subscribe(Disposable d);
}
Logger
public class Logger {
public static void logD(String tag,String msg){
if (Constants.isDebug){
Log.d(tag, "logD: "+msg);
}
}
}
CallBack
public interface CallBack<K> {
void onSuccess(K k);
void onFail(String string);
}
用法
DailyNewsM
public class DailyNewsM extends BaseModel {
public void getData(final CallBack<DailyNewsBean> callBack) {
ZhihuService apiserver = HttpUtils.getInstance().getApiserver(ZhihuService.sBaseUrl, ZhihuService.class);
Observable<DailyNewsBean> lastDailyNews = apiserver.getLastDailyNews();
lastDailyNews.compose(RxUtils.<DailyNewsBean>rxObserableSchedulerHelper())
.subscribe(new BaseObserver<DailyNewsBean>() {
@Override
public void onNext(DailyNewsBean dailyNewsBean) {
callBack.onSuccess(dailyNewsBean);
}
@Override
public void error(String msg) {
}
@Override
protected void subscribe(Disposable d) {
addDisposable(d);
}
});
}
}
DailyNewsP
public class DailyNewsP extends BasePresenter<DailyNewsV> {
private DailyNewsM mDailyNewsM;
@Override
protected void initModel() {
mDailyNewsM = new DailyNewsM();
mModels.add(mDailyNewsM);
}
public void getData() {
mDailyNewsM.getData(new ResultCallBack<DailyNewsBean>() {
@Override
public void onSuccess(DailyNewsBean bean) {
if (bean != null){
if (view != null){
view.setData(bean);
}
}
}
@Override
public void onFail(String msg) {
}
});
}
}
DailyNewsV
public interface DailyNewsV extends BaseMvpView {
void setData(DailyNewsBean bean);
}