您的位置:首页 > 运维架构 > 网站架构

Android笔记(28)MVVM架构过程

2017-12-11 18:26 471 查看
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 fl
1209a
ag) {
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());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android mvvm