MVP简单抽取+loading动画

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);
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容