Android笔记(28)MVVM架构过程

1.加依赖包

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "26.0.1"
    defaultConfig {
        applicationId "com.example.myapplication"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        aaptOptions.cruncherEnabled = false
        aaptOptions.useNewCruncher = false
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    //重点
    dataBinding{
        enabled = true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    //UI dependency
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support:design:25.3.1'
    compile 'com.android.support:recyclerview-v7:25.3.1'
    compile 'com.android.support:cardview-v7:25.3.1'
    // rx android
    compile 'com.jakewharton.rxbinding:rxbinding:0.4.0'
    compile 'io.reactivex:rxjava:1.0.16'
    compile 'io.reactivex:rxandroid:1.0.1'
    // gson
    compile 'com.google.code.gson:gson:2.7'
    // okhttp
    compile 'com.squareup.okhttp3:okhttp:3.9.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.9.0'
    compile 'com.github.simonpercic:oklog3:2.2.0'
    // retrofit
    compile 'com.squareup.retrofit2:retrofit:2.0.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
    compile 'com.squareup.retrofit2:converter-gson:2.0.0'
    // let the Retorfit work with Rxjava
    compile 'com.jakewharton:butterknife:8.4.0'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}

2.新建APP类

import android.app.Application;

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        initEnv();
    }
    //初始化app环境
    private void initEnv(){
        //初始化网络组件
        APIFactory.init();
    }
}

3.AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

4.在values中新建attrs.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ValidatedInputTextLayout">
        <attr name="autoValidate" format="boolean" />
        <attr name="autoTrim" format="boolean" />
        <attr name="isRequired" format="boolean" />
        <attr name="requiredValidationMessage" format="string" />
        <attr name="minLength" format="integer">
            <enum name="zero" value="0" />
        </attr>
        <attr name="maxLength" format="integer">
            <enum name="indefinite" value="-1" />
        </attr>
        <attr name="lengthValidationMessage" format="string" />
        <attr name="regex" format="string" />
        <attr name="regexValidationMessage" format="string" />
    </declare-styleable>
</resources>

5.新建ValidatedTextInputLayout类

import android.content.Context;
import android.content.res.TypedArray;
import android.support.design.widget.TextInputLayout;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;

import java.util.ArrayList;
import java.util.List;

public class ValidatedTextInputLayout extends TextInputLayout {
    private List<BaseValidator> mValidators;
    private boolean mAutoValidate = false;
    private boolean mAutoTrimValue = false;

    public ValidatedTextInputLayout(Context context) {
        super(context);
        initialize();
    }

    public ValidatedTextInputLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
        initializeCustomAttrs(context, attrs);
    }

    public ValidatedTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize();
        initializeCustomAttrs(context, attrs);
    }

    private void initialize() {
        if (!isInEditMode()) {
            mValidators = new ArrayList<>();
            this.post(new Runnable() {
                @Override
                public void run() {
                    if (!getEditText().isInEditMode())
                        initializeTextWatcher();
                }
            });
        }
    }

    private void initializeCustomAttrs(Context context, AttributeSet attrs) {
        if (!isInEditMode()) {
            TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable
                    .ValidatedInputTextLayout, 0, 0);
            try {
                mAutoTrimValue = typedArray.getBoolean(R.styleable.ValidatedInputTextLayout_autoTrim,
                        false);
                mAutoValidate = typedArray.getBoolean(R.styleable
                        .ValidatedInputTextLayout_autoValidate, false);

                initRequiredValidation(context, typedArray);
                initLengthValidation(context, typedArray);
            } finally {
                typedArray.recycle();
            }
        }
    }

    private void initRequiredValidation(Context context, TypedArray typedArray) {
        if (typedArray.getBoolean(R.styleable.ValidatedInputTextLayout_isRequired, false)) {
            String errorMessage = typedArray.getString(R.styleable
                    .ValidatedInputTextLayout_requiredValidationMessage);
            if (errorMessage == null)
                errorMessage = context.getString(R.string.default_required_validation_message);
            addValidator(new RequiredValidator(errorMessage));
        }
    }

    private void initLengthValidation(Context context, TypedArray typedArray) {
        int minLength = typedArray.getInteger(R.styleable.ValidatedInputTextLayout_minLength,
                LengthValidator.LENGTH_ZERO);
        int maxLength = typedArray.getInteger(R.styleable.ValidatedInputTextLayout_maxLength,
                LengthValidator.LENGTH_INDEFINITE);

        if (!(minLength == LengthValidator.LENGTH_ZERO && maxLength == LengthValidator
                .LENGTH_INDEFINITE)) {
            String errorMessage = typedArray.getString(R.styleable
                    .ValidatedInputTextLayout_lengthValidationMessage);
            if (errorMessage == null) {
                if (minLength == LengthValidator.LENGTH_ZERO) {
                    errorMessage = context.getString(R.string.default_required_length_message_max, maxLength);
                } else if (maxLength == LengthValidator.LENGTH_INDEFINITE) {
                    errorMessage = context.getString(R.string
                            .default_required_length_message_min, minLength);
                } else {
                    errorMessage = context.getString(R.string
                            .default_required_length_message_min_max, minLength, maxLength);
                }
            }
            addValidator(new LengthValidator(minLength, maxLength, errorMessage));
        }
    }

    private void initializeTextWatcher() {
        getEditText().addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (isAutoValidated()) validate();
                else setError(null);
            }

            @Override
            public void afterTextChanged(Editable s) {
            }
        });
    }

    public void clearValidators() {
        mValidators.clear();
        setErrorEnabled(false);
    }

    public void addValidator(BaseValidator pValidator) {
        mValidators.add(pValidator);
        setErrorEnabled(true);
    }

    public void autoValidate(boolean flag) {
        mAutoValidate = flag;
    }

    public boolean isAutoValidated() {
        return mAutoValidate;
    }

    public void autoTrimValue(boolean flag) {
        mAutoTrimValue = flag;
    }

    public boolean isAutoTrimEnabled() {
        return mAutoTrimValue;
    }

    public boolean validate() {
        boolean status = true;
        String text = getValue();
        for (IValidator validator : mValidators) {
            if (!validator.isValid(text)) {
                setError(validator.getErrorMessage());
                status = false;
                break;
            } else {
                setError(null);
            }
        }
        return status;
    }

    public String getValue() {
        if (isAutoTrimEnabled()) return getEditText().getText().toString().trim();
        else return getEditText().getText().toString();
    }
}

6.新建BaseValidator类

import android.support.annotation.NonNull;

public abstract class BaseValidator implements IValidator {

    protected String mErrorMessage;

    public BaseValidator(@NonNull String pErrorMessage) {
        setErrorMessage(pErrorMessage);
    }

    @Override
    public abstract boolean isValid(String pText);

    @Override
    public void setErrorMessage(@NonNull String pErrorMessage) {
        mErrorMessage = pErrorMessage;
    }

    @Override
    public String getErrorMessage() {
        return mErrorMessage;
    }
}

7.新建LengthValidator类

import android.support.annotation.NonNull;

public class LengthValidator extends BaseValidator {

    public static final int LENGTH_INDEFINITE = -1;

    public static final int LENGTH_ZERO = 0;

    private int mMinimumLength = LENGTH_ZERO;

    private int mMaximumLength = LENGTH_INDEFINITE;

    public LengthValidator(@NonNull String pErrorMessage) {
        super(pErrorMessage);
    }

    public LengthValidator(int pMaximumLength, @NonNull String pErrorMessage) {
        super(pErrorMessage);
        mMaximumLength = pMaximumLength;
    }

    public LengthValidator(int pMinimumLength, int pMaximumLength, @NonNull String pErrorMessage) {
        super(pErrorMessage);
        mMinimumLength = pMinimumLength;
        mMaximumLength = pMaximumLength;
    }

    @Override
    public boolean isValid(String pText) {
        int length = pText.length();
        if (getMaximumLength() == LENGTH_INDEFINITE) {
            return length >= getMinimumLength();
        } else {
            return (length >= getMinimumLength() && length <= getMaximumLength());
        }
    }

    public void setMinimumLength(int pMinimumLength) {
        mMinimumLength = pMinimumLength;
    }

    public void setMaximumLength(int pMaximumLength) {
        mMaximumLength = pMaximumLength;
    }

    public int getMinimumLength() {
        return mMinimumLength;
    }

    public int getMaximumLength() {
        return mMaximumLength;
    }
}

8.新建RequiredValidator类

public class RequiredValidator extends BaseValidator {

    public RequiredValidator(String pErrorMessage) {
        super(pErrorMessage);
    }

    @Override
    public boolean isValid(String pText) {
        return !pText.isEmpty();
    }
}

9.新建IValidator接口

public interface IValidator {
    boolean isValid(String pText);
    void setErrorMessage(String pErrorMessage);
    String getErrorMessage();
}

10.新建APIFactory类

import com.github.simonpercic.oklog3.OkLogInterceptor;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.lemner.hation.ykbb.BuildConfig;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

public class APIFactory {
    private static APIService API_SERVICE;

    private static final String BASE_URL = "/*服务器网址*/";
    private static final String PREFIX_BASE_URL = BASE_URL+"";
    public static final String PREFIX_BASE_IMG_URL = BASE_URL+"";
    private static Gson sGson;
    private static final int DEFAULT_TIMEOUT = 5;

    public static void init(){
        OkLogInterceptor okLogInterceptor =  OkLogInterceptor.builder().useAndroidLog(true).build();
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient.Builder build=new OkHttpClient.Builder();
        //if model is debug add a interceptor
        if (BuildConfig.DEBUG) {
            build .addInterceptor(okLogInterceptor);
        }
        OkHttpClient client = build.build();
        API_SERVICE = new Retrofit.Builder()
                .baseUrl(PREFIX_BASE_URL)
                .client(client)
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(buildGson()))
                .build().create(APIService.class);

    }

    public static APIService getApiService() {
        return API_SERVICE;
    }

    private static Gson buildGson() {
        if(sGson==null){
            sGson = new GsonBuilder().setPrettyPrinting().setLenient().registerTypeHierarchyAdapter(List.class, new JsonDeserializer<List<?>>() {
                @Override
                public List<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                    if (json.isJsonArray()) {
                        JsonArray array = json.getAsJsonArray();
                        Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
                        List list = new ArrayList<>();
                        for (int i = 0,size=array.size(); i < size; i++) {
                            JsonElement element = array.get(i);
                            Object item = context.deserialize(element, itemType);
                            list.add(item);
                        }
                        return list;
                    } else {
                        //和接口类型不符,返回空List
                        return Collections.EMPTY_LIST;
                    }
                }
            }).create();
        }
        return sGson;
    }
}

11.新建LoginBean类

package com.example.myapplication;

public class LoginBean{
    private String userid;

    public String getUserid() {
        return userid;
    }

    public void setUserid(String userid) {
        this.userid = userid;
    }
}

12.新建APIService类

package com.example.myapplication;

import retrofit2.http.GET;
import retrofit2.http.Query;
import rx.Observable;

public interface APIService {
    //登录
    @GET("userLogin.do")
    Observable<LoginBean> login(
            @Query("username") String username,
            @Query("userpass") String userpass
    );
}

13.新建activity_login.xml文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:validation="http://schemas.android.com/apk/res-auto">

    <data>
        <variable
            name="loginViewModel"
            type="com.example.myapplication.LoginViewModel" />
    </data>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".LoginActivity">

        <com.example.myapplication.ValidatedTextInputLayout
            app:errorTextAppearance="@style/Theme.AppCompat"
            android:id="@+id/validate_et_username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            validation:autoTrim="true"
            validation:isRequired="true">
            <EditText
                android:id="@+id/et_username"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="请输入用户名"/>
        </com.example.myapplication.ValidatedTextInputLayout>
        <com.example.myapplication.ValidatedTextInputLayout
            app:errorTextAppearance="@style/Theme.AppCompat"
            android:id="@+id/validate_et_password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="30dp"
            android:layout_marginRight="30dp"
            validation:autoTrim="true"
            validation:isRequired="true">
            <EditText
                android:id="@+id/et_password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="请输入密码"/>
        </com.example.myapplication.ValidatedTextInputLayout>
        <Button
            android:id="@+id/bt_login"
            android:layout_width="100dp"
            android:layout_height="40dp"
            android:text="登录"
            android:onClick="@{loginViewModel::onClickEvent}"/>
    </LinearLayout>

</layout>

14.新建LoginViewModel类

import android.content.Context;
import android.view.View;
import android.widget.Toast;

import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

public class LoginViewModel{

    protected Context context;

    private LoginViewModelContract.LoginView loginView;

    public LoginViewModel(LoginViewModelContract.LoginView loginView ,Context context) {
        this.context=context;
        this.loginView = loginView;
    }

    public void onClickEvent(View view) {
        switch (view.getId()) {
            case R.id.bt_idcode:
                loginView.postLogin();
                break;
        }
    }

    public void destroy() {

    }

    public void postLogin(String username , String pasword){
        APIFactory.getApiService().login(username,pasword)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<LoginBean>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        Toast.makeText(context, "网络连接不畅",Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onNext(LoginBean loginBean) {
                        if (true/*没写*/){
                            //context.startActivity(new Intent(context,MainActivity.class));//成功后跳转
                        }else {
                            Toast.makeText(context , "账号或密码错误!",Toast.LENGTH_SHORT).show();
                        }
                    }
                });
    }
}

15.新建LoginViewModelContract接口

public interface LoginViewModelContract {

    interface LoginView{
        void showLoadingDialog();
        void dismissLoadingDialog();
        void postLogin();
    }
}

16.新建LoginActivity类

import android.app.ProgressDialog;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

import com.example.myapplication.databinding.ActivityLoginBinding;

import butterknife.ButterKnife;

public class LoginActivity extends AppCompatActivity implements LoginViewModelContract.LoginView{

    private LoginViewModel loginViewModel;
    private ActivityLoginBinding activityLoginBinding;
    private ProgressDialog mProgressDialog;

    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setView();
        initView();
        ButterKnife.bind(this);
    }

    public void initView() {

    }

    public View setView() {
        activityLoginBinding = DataBindingUtil.setContentView(this , R.layout.activity_login);
        loginViewModel = new LoginViewModel(this,LoginActivity.this);
        activityLoginBinding.setLoginViewModel(loginViewModel);
        return activityLoginBinding.getRoot();
    }

    public void onViewDestroy() {
        loginViewModel.destroy();
    }

    public void showLoadingDialog() {
        mProgressDialog.show();
    }

    public void dismissLoadingDialog() {
        mProgressDialog.dismiss();
    }

    public void postLogin() {
        loginViewModel.postLogin(activityLoginBinding.etUsername.getText().toString() , activityLoginBinding.etPassword.getText().toString());
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值