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
<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文件
<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 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>() {
@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 login(
@Query("username") String username,
@Query("userpass") String userpass
);
}
13.新建activity_login.xml文件
<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() {
@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());
}
}