Android笔记(28)MVVM架构过程
2017-12-11 18:26
471 查看
1.加依赖包
2.新建APP类
3.AndroidManifest.xml
4.在values中新建attrs.xml文件
5.新建ValidatedTextInputLayout类
6.新建BaseValidator类
7.新建LengthValidator类
8.新建RequiredValidator类
9.新建IValidator接口
10.新建APIFactory类
11.新建LoginBean类
12.新建APIService类
13.新建activity_login.xml文件
14.新建LoginViewModel类
15.新建LoginViewModelContract接口
16.新建LoginActivity类
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笔记:Android App的设计架构:MVC,MVP,MVVM与架构经验谈
- android MVC/MVP/MVVM架构对比
- Android MVVM架构模式 详解和综合运用(四)
- Android源码笔记——Camera系统架构
- android_系统架构笔记之--android系统层次
- Android群英传第三章笔记·Android控件架构与自定义控件详解
- Android架构设计---关于MVVM模式的探讨
- 浅谈Android架构设计模式中MVC、MVP、MVVM
- Android App的设计架构:MVC,MVP,MVVM与架构经验谈
- Android(java)学习笔记160:Framework运行环境之 Android进程产生过程
- Android App的三种架构模式MVC,MVP和MVVM
- 上手Android源码探索AOSP的奥秘过程笔记(不是教程,只是自己遇到的问题或者心得的笔记,持续更新)
- Android GPS架构分析(gps启动过程图)
- Android安全学习笔记1-系统设计与架构
- android是mvc还是mvvm架构?
- android底层开发笔记(2)androidLK启动过程1
- Android 输入系统架构 笔记2
- Android源码笔记——Camera系统架构
- Android架构学习MVC、MVP、MVVM(二)
- 架构设计过程【DDDD笔记】