├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── mvpteach │ │ └── liuguangli │ │ └── mvpteach │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── mvpteach │ │ │ └── liuguangli │ │ │ └── mvpteach │ │ │ ├── badmvp │ │ │ ├── ILoginManager.java │ │ │ ├── ILoginPresenter.java │ │ │ ├── ILoginView.java │ │ │ ├── LoginActivity.java │ │ │ ├── LoginManagerImp.java │ │ │ ├── LoginPresenterImp.java │ │ │ └── bean │ │ │ │ └── UserInfo.java │ │ │ ├── mvplevel │ │ │ ├── ILoginManager.java │ │ │ ├── ILoginPresenter.java │ │ │ ├── ILoginView.java │ │ │ ├── IUserInfoView.java │ │ │ ├── LoginActivity.java │ │ │ ├── LoginManagerImp.java │ │ │ ├── LoginPresenterImp.java │ │ │ └── bean │ │ │ │ ├── LoginInfo.java │ │ │ │ └── UserInfo.java │ │ │ └── nolevel │ │ │ ├── LoginActivity.java │ │ │ └── UserInfo.java │ └── res │ │ ├── layout │ │ ├── activity_login.xml │ │ ├── activity_user_info.xml │ │ └── content_user_info.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── mvpteach │ └── liuguangli │ └── mvpteach │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | MVPTeach -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Android Lint 39 | 40 | 41 | BashSupport 42 | 43 | 44 | General 45 | 46 | 47 | Java 48 | 49 | 50 | Spelling 51 | 52 | 53 | 54 | 55 | Java 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 77 | 78 | 79 | 80 | 81 | 82 | 87 | 88 | 89 | 90 | 91 | 92 | 1.7 93 | 94 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MVPTeach 2 | 登录为业务场景对比非MVP和MVP设计的例子 3 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.mvpteach.liuguangli.mvpteach" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.1.1' 26 | compile 'com.android.support:design:23.1.1' 27 | compile 'com.loopj.android:android-async-http:1.4.9' 28 | } 29 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/liuguangli/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/mvpteach/liuguangli/mvpteach/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/badmvp/ILoginManager.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.badmvp; 2 | 3 | import com.loopj.android.http.RequestParams; 4 | 5 | /** 6 | * Created by liuguangli on 16/1/18. 7 | */ 8 | public interface ILoginManager { 9 | public void login(RequestParams requestParams); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/badmvp/ILoginPresenter.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.badmvp; 2 | 3 | import com.loopj.android.http.RequestParams; 4 | import com.mvpteach.liuguangli.mvpteach.badmvp.bean.UserInfo; 5 | 6 | /** 7 | * Created by liuguangli on 16/1/18. 8 | */ 9 | public interface ILoginPresenter { 10 | /** 11 | * 登录 12 | * @param requestParams 13 | */ 14 | public void loginToServer(RequestParams requestParams); 15 | /** 16 | * 登录成功 17 | */ 18 | public void loginSuc(UserInfo userInfo); 19 | /** 20 | * 登录失败 21 | */ 22 | public void loginError(int code, String msg); 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/badmvp/ILoginView.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.badmvp; 2 | 3 | /** 4 | * Created by liuguangli on 16/1/18. 5 | */ 6 | public interface ILoginView { 7 | /** 8 | * 提交登录 9 | */ 10 | public void attemptLogin(); 11 | /** 12 | * 显示loading框 13 | */ 14 | public void showProcess(final boolean show); 15 | 16 | /** 17 | * 显示错误信息 18 | * @param code 错误码 19 | * @param devMsg 技术性提示信息 20 | * @param friendlyMsg 用户提示信息 21 | */ 22 | public void showErrorInfo(int code, String devMsg, String friendlyMsg); 23 | 24 | /** 25 | * 处理登录成功 26 | */ 27 | public void loginSuc(); 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/badmvp/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.badmvp; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.text.TextUtils; 8 | import android.view.View; 9 | import android.view.View.OnClickListener; 10 | import android.widget.AutoCompleteTextView; 11 | import android.widget.Button; 12 | import android.widget.EditText; 13 | 14 | import com.loopj.android.http.RequestParams; 15 | import com.mvpteach.liuguangli.mvpteach.R; 16 | 17 | /** 18 | * 登录功能:形式上使用了MVP架构,但本质上还是没完全执行MVP的思想 19 | */ 20 | public class LoginActivity extends AppCompatActivity implements ILoginView { 21 | 22 | private AutoCompleteTextView mUsernameView; 23 | private EditText mPasswordView; 24 | private View mProgressView; 25 | private View mLoginFormView; 26 | private ILoginPresenter mLoginPresenter; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_login); 32 | // Set up the login form. 33 | mUsernameView = (AutoCompleteTextView) findViewById(R.id.username); 34 | mPasswordView = (EditText) findViewById(R.id.password); 35 | mLoginFormView = findViewById(R.id.login_form); 36 | mProgressView = findViewById(R.id.login_progress); 37 | Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button); 38 | mEmailSignInButton.setOnClickListener(new OnClickListener() { 39 | @Override 40 | public void onClick(View view) { 41 | attemptLogin(); 42 | } 43 | }); 44 | mLoginPresenter = new LoginPresenterImp(this); 45 | 46 | } 47 | 48 | 49 | /** 50 | * 提交登录 51 | */ 52 | @Override 53 | public void attemptLogin() { 54 | 55 | // Reset errors. 56 | mUsernameView.setError(null); 57 | mPasswordView.setError(null); 58 | 59 | // Store values at the time of the login attempt. 60 | String email = mUsernameView.getText().toString(); 61 | String password = mPasswordView.getText().toString(); 62 | 63 | boolean cancel = false; 64 | // Check for a valid password, if the user entered one. 65 | if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) { 66 | mPasswordView.setError(getString(R.string.error_invalid_password)); 67 | cancel = true; 68 | } 69 | // Check for a valid email address. 70 | if (TextUtils.isEmpty(email)) { 71 | mUsernameView.setError(getString(R.string.error_field_required)); 72 | cancel = true; 73 | } else if (!isEmailValid(email)) { 74 | mUsernameView.setError(getString(R.string.error_invalid_email)); 75 | cancel = true; 76 | } 77 | if (!cancel){ 78 | /**形式上使用了MVP架构,但本质上还是没完全执行MVP的思想。因为这里已经暴露了,网络框架层的实现特性 79 | (如果那天不使用android-async-http这个框架了,那么这里就会受到影响)*/ 80 | RequestParams request = new RequestParams(); 81 | request.put("username",email); 82 | request.put("password",password); 83 | mLoginPresenter.loginToServer(request); 84 | } 85 | 86 | 87 | } 88 | 89 | /** 90 | * 显示错误信息 91 | * @param code 错误码 92 | * @param devMsg 技术性提示信息 93 | * @param friendlyMsg 用户提示信息 94 | */ 95 | @Override 96 | public void showErrorInfo(int code, String devMsg, String friendlyMsg) { 97 | 98 | } 99 | 100 | /** 101 | * 登录成功 102 | */ 103 | @Override 104 | public void loginSuc() { 105 | 106 | } 107 | 108 | /** 109 | * 显示进度 110 | */ 111 | @Override 112 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) 113 | public void showProcess(final boolean show) { 114 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); 115 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); 116 | } 117 | 118 | 119 | 120 | private boolean isEmailValid(String email) { 121 | //TODO: Replace this with your own logic 122 | return email.contains("@"); 123 | } 124 | 125 | private boolean isPasswordValid(String password) { 126 | //TODO: Replace this with your own logic 127 | return password.length() > 4; 128 | } 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | } 137 | 138 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/badmvp/LoginManagerImp.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.badmvp; 2 | 3 | import com.loopj.android.http.AsyncHttpClient; 4 | import com.loopj.android.http.RequestParams; 5 | import com.loopj.android.http.TextHttpResponseHandler; 6 | import com.mvpteach.liuguangli.mvpteach.badmvp.bean.UserInfo; 7 | 8 | import cz.msebera.android.httpclient.Header; 9 | 10 | /** 11 | * Created by liuguangli on 16/1/18. 12 | */ 13 | public class LoginManagerImp implements ILoginManager { 14 | private ILoginPresenter presenter; 15 | 16 | public LoginManagerImp(ILoginPresenter presenter) { 17 | this.presenter = presenter; 18 | } 19 | 20 | @Override 21 | public void login(RequestParams request) { 22 | 23 | new AsyncHttpClient().post(null, "http://192.168.12.12/app/user/login", request, new TextHttpResponseHandler() { 24 | @Override 25 | public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { 26 | //// TODO: 16/1/18 错误码解析和提示 27 | presenter.loginError(statusCode, responseString); 28 | } 29 | 30 | @Override 31 | public void onSuccess(int statusCode, Header[] headers, String responseString) { 32 | UserInfo userInfo = new UserInfo(); 33 | // TODO: 16/1/18 34 | presenter.loginSuc(userInfo); 35 | } 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/badmvp/LoginPresenterImp.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.badmvp; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.loopj.android.http.RequestParams; 7 | import com.mvpteach.liuguangli.mvpteach.badmvp.bean.UserInfo; 8 | 9 | /** 10 | * mvp分层 11 | */ 12 | public class LoginPresenterImp extends Handler implements ILoginPresenter { 13 | public final static int METHOD_LONIN_ERROR = 0; 14 | public final static int METHOD_LONIN_SUC = 2; 15 | private ILoginManager loginManager; 16 | private ILoginView loginView; 17 | 18 | 19 | public LoginPresenterImp(ILoginView view){ 20 | loginManager = new LoginManagerImp(this); 21 | this.loginView = view; 22 | } 23 | @Override 24 | public void loginToServer(RequestParams requestParams) { 25 | 26 | loginView.showProcess(true); 27 | loginManager.login(requestParams); 28 | } 29 | 30 | @Override 31 | public void loginSuc(UserInfo userInfo) { 32 | // TODO: 16/1/23 save userInfo 33 | Message msg = obtainMessage(); 34 | msg.what = METHOD_LONIN_SUC; 35 | sendMessage(msg); 36 | } 37 | 38 | @Override 39 | public void loginError(int code, String msgInfo) { 40 | Message msg = obtainMessage(); 41 | msg.what = METHOD_LONIN_SUC; 42 | msg.arg1 = code; 43 | msg.obj = msgInfo; 44 | sendMessage(msg); 45 | } 46 | 47 | @Override 48 | public void handleMessage(Message msg) { 49 | switch (msg.what){ 50 | case METHOD_LONIN_ERROR: 51 | loginErroOnUi(msg.arg1, msg.obj.toString()); 52 | break; 53 | case METHOD_LONIN_SUC: 54 | loginSucOnUi(); 55 | break; 56 | } 57 | } 58 | 59 | public void loginErroOnUi(int code,String message){ 60 | loginView.showErrorInfo(code, message, message); 61 | loginView.showProcess(false); 62 | } 63 | 64 | private void loginSucOnUi(){ 65 | loginView.showProcess(false); 66 | loginView.loginSuc(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/badmvp/bean/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.badmvp.bean; 2 | 3 | /** 4 | * Created by liuguangli on 16/1/24. 5 | */ 6 | public class UserInfo { 7 | private String nickName; 8 | 9 | private String level; 10 | 11 | public String getNickName() { 12 | return nickName; 13 | } 14 | 15 | public void setNickName(String nickName) { 16 | this.nickName = nickName; 17 | } 18 | 19 | public String getLevel() { 20 | return level; 21 | } 22 | 23 | public void setLevel(String level) { 24 | this.level = level; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/mvplevel/ILoginManager.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.mvplevel; 2 | 3 | import com.mvpteach.liuguangli.mvpteach.mvplevel.bean.LoginInfo; 4 | 5 | /** 6 | * Created by liuguangli on 16/1/18. 7 | */ 8 | public interface ILoginManager { 9 | public void login(LoginInfo info); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/mvplevel/ILoginPresenter.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.mvplevel; 2 | 3 | import com.mvpteach.liuguangli.mvpteach.mvplevel.bean.LoginInfo; 4 | import com.mvpteach.liuguangli.mvpteach.mvplevel.bean.UserInfo; 5 | 6 | /** 7 | * Created by liuguangli on 16/1/18. 8 | */ 9 | public interface ILoginPresenter { 10 | /** 11 | * 登录 12 | * @param userName 13 | * @param password 14 | */ 15 | public void loginToServer(String userName,String password); 16 | /** 17 | * 登录成功 18 | */ 19 | public void loginSuc(UserInfo userInfo); 20 | /** 21 | * 登录失败 22 | */ 23 | public void loginError(int code, String msg); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/mvplevel/ILoginView.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.mvplevel; 2 | 3 | /** 4 | * Created by liuguangli on 16/1/18. 5 | */ 6 | public interface ILoginView { 7 | /** 8 | * 提交登录 9 | */ 10 | public void attemptLogin(); 11 | /** 12 | * 显示loading框 13 | */ 14 | public void showProcess(final boolean show); 15 | 16 | /** 17 | * 显示错误信息 18 | * @param code 错误码 19 | * @param devMsg 技术性提示信息 20 | * @param friendlyMsg 用户提示信息 21 | */ 22 | public void showErrorInfo(int code ,String devMsg,String friendlyMsg); 23 | 24 | /** 25 | * 处理登录成功 26 | */ 27 | public void loginSuc(); 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/mvplevel/IUserInfoView.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.mvplevel; 2 | 3 | import com.mvpteach.liuguangli.mvpteach.mvplevel.bean.UserInfo; 4 | 5 | /** 6 | * Created by liuguangli on 16/1/24. 7 | */ 8 | public interface IUserInfoView { 9 | /** 10 | * 显示loading框 11 | */ 12 | public void showProcess(final boolean show); 13 | 14 | /** 15 | * 显示用户信息 16 | * @param userInfo 17 | */ 18 | public void showUserInfo(UserInfo userInfo); 19 | 20 | /** 21 | * 回退到登录 22 | */ 23 | public void toLogin(); 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/mvplevel/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.mvplevel; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.text.TextUtils; 8 | import android.view.View; 9 | import android.view.View.OnClickListener; 10 | import android.widget.AutoCompleteTextView; 11 | import android.widget.Button; 12 | import android.widget.EditText; 13 | 14 | import com.mvpteach.liuguangli.mvpteach.R; 15 | import com.mvpteach.liuguangli.mvpteach.mvplevel.bean.LoginInfo; 16 | 17 | /** 18 | * 登录功能MVP设计 19 | */ 20 | public class LoginActivity extends AppCompatActivity implements ILoginView { 21 | 22 | private AutoCompleteTextView mUsernameView; 23 | private EditText mPasswordView; 24 | private View mProgressView; 25 | private View mLoginFormView; 26 | private ILoginPresenter mLoginPresenter; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_login); 32 | // Set up the login form. 33 | mUsernameView = (AutoCompleteTextView) findViewById(R.id.username); 34 | mPasswordView = (EditText) findViewById(R.id.password); 35 | mLoginFormView = findViewById(R.id.login_form); 36 | mProgressView = findViewById(R.id.login_progress); 37 | Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button); 38 | mEmailSignInButton.setOnClickListener(new OnClickListener() { 39 | @Override 40 | public void onClick(View view) { 41 | attemptLogin(); 42 | } 43 | }); 44 | mLoginPresenter = new LoginPresenterImp(this); 45 | 46 | } 47 | 48 | 49 | /** 50 | * 提交登录 51 | */ 52 | @Override 53 | public void attemptLogin() { 54 | 55 | // Reset errors. 56 | mUsernameView.setError(null); 57 | mPasswordView.setError(null); 58 | 59 | // Store values at the time of the login attempt. 60 | String email = mUsernameView.getText().toString(); 61 | String password = mPasswordView.getText().toString(); 62 | 63 | boolean cancel = false; 64 | // Check for a valid password, if the user entered one. 65 | if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) { 66 | mPasswordView.setError(getString(R.string.error_invalid_password)); 67 | cancel = true; 68 | } 69 | // Check for a valid email address. 70 | if (TextUtils.isEmpty(email)) { 71 | mUsernameView.setError(getString(R.string.error_field_required)); 72 | cancel = true; 73 | } else if (!isEmailValid(email)) { 74 | mUsernameView.setError(getString(R.string.error_invalid_email)); 75 | cancel = true; 76 | } 77 | if (!cancel){ 78 | mLoginPresenter.loginToServer(email,password); 79 | } 80 | 81 | 82 | } 83 | 84 | /** 85 | * 显示错误信息 86 | * @param code 错误码 87 | * @param devMsg 技术性提示信息 88 | * @param friendlyMsg 用户提示信息 89 | */ 90 | @Override 91 | public void showErrorInfo(int code, String devMsg, String friendlyMsg) { 92 | 93 | } 94 | 95 | /** 96 | * 登录成功 97 | */ 98 | @Override 99 | public void loginSuc() { 100 | 101 | } 102 | 103 | /** 104 | * 显示进度 105 | */ 106 | @Override 107 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) 108 | public void showProcess(final boolean show) { 109 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); 110 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); 111 | } 112 | 113 | 114 | 115 | private boolean isEmailValid(String email) { 116 | //TODO: Replace this with your own logic 117 | return email.contains("@"); 118 | } 119 | 120 | private boolean isPasswordValid(String password) { 121 | //TODO: Replace this with your own logic 122 | return password.length() > 4; 123 | } 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | } 132 | 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/mvplevel/LoginManagerImp.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.mvplevel; 2 | 3 | import com.loopj.android.http.AsyncHttpClient; 4 | import com.loopj.android.http.RequestParams; 5 | import com.loopj.android.http.TextHttpResponseHandler; 6 | import com.mvpteach.liuguangli.mvpteach.mvplevel.bean.LoginInfo; 7 | import com.mvpteach.liuguangli.mvpteach.mvplevel.bean.UserInfo; 8 | 9 | import cz.msebera.android.httpclient.Header; 10 | 11 | /** 12 | * Created by liuguangli on 16/1/18. 13 | */ 14 | public class LoginManagerImp implements ILoginManager { 15 | private ILoginPresenter presenter; 16 | 17 | public LoginManagerImp(ILoginPresenter presenter) { 18 | this.presenter = presenter; 19 | } 20 | 21 | @Override 22 | public void login(LoginInfo info) { 23 | RequestParams request = new RequestParams(); 24 | request.put("username",info.getUserName()); 25 | request.put("password",info.getPassword()); 26 | new AsyncHttpClient().post(null, "http://192.168.12.12/app/user/login", request, new TextHttpResponseHandler() { 27 | @Override 28 | public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { 29 | //// TODO: 16/1/18 错误码解析和提示 30 | presenter.loginError(statusCode, responseString); 31 | } 32 | 33 | @Override 34 | public void onSuccess(int statusCode, Header[] headers, String responseString) { 35 | UserInfo userInfo = new UserInfo(); 36 | // TODO: 16/1/18 37 | presenter.loginSuc(userInfo); 38 | } 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/mvplevel/LoginPresenterImp.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.mvplevel; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.mvpteach.liuguangli.mvpteach.mvplevel.bean.LoginInfo; 7 | import com.mvpteach.liuguangli.mvpteach.mvplevel.bean.UserInfo; 8 | 9 | /** 10 | * mvp分层 11 | */ 12 | public class LoginPresenterImp extends Handler implements ILoginPresenter { 13 | public final static int METHOD_LONIN_ERROR = 0; 14 | public final static int METHOD_LONIN_SUC = 2; 15 | private ILoginManager loginManager; 16 | private ILoginView loginView; 17 | 18 | 19 | public LoginPresenterImp(ILoginView view){ 20 | loginManager = new LoginManagerImp(this); 21 | this.loginView = view; 22 | } 23 | @Override 24 | public void loginToServer(String userName,String password) { 25 | LoginInfo info = new LoginInfo(); 26 | info.setUserName(userName); 27 | info.setPassword(password); 28 | loginView.showProcess(true); 29 | loginManager.login(info); 30 | } 31 | 32 | @Override 33 | public void loginSuc(UserInfo userInfo) { 34 | // TODO: 16/1/23 save userInfo 35 | Message msg = obtainMessage(); 36 | msg.what = METHOD_LONIN_SUC; 37 | sendMessage(msg); 38 | } 39 | 40 | @Override 41 | public void loginError(int code, String msgInfo) { 42 | Message msg = obtainMessage(); 43 | msg.what = METHOD_LONIN_SUC; 44 | msg.arg1 = code; 45 | msg.obj = msgInfo; 46 | sendMessage(msg); 47 | } 48 | 49 | @Override 50 | public void handleMessage(Message msg) { 51 | switch (msg.what){ 52 | case METHOD_LONIN_ERROR: 53 | loginErroOnUi(msg.arg1,msg.obj.toString()); 54 | break; 55 | case METHOD_LONIN_SUC: 56 | loginSucOnUi(); 57 | break; 58 | } 59 | } 60 | 61 | public void loginErroOnUi(int code,String message){ 62 | loginView.showErrorInfo(code, message, message); 63 | loginView.showProcess(false); 64 | } 65 | 66 | private void loginSucOnUi(){ 67 | loginView.showProcess(false); 68 | loginView.loginSuc(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/mvplevel/bean/LoginInfo.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.mvplevel.bean; 2 | 3 | /** 4 | * Created by liuguangli on 16/1/18. 5 | */ 6 | public class LoginInfo { 7 | private String userName; 8 | private String password; 9 | 10 | public String getUserName() { 11 | return userName; 12 | } 13 | 14 | public void setUserName(String userName) { 15 | this.userName = userName; 16 | } 17 | 18 | public String getPassword() { 19 | return password; 20 | } 21 | 22 | public void setPassword(String password) { 23 | this.password = password; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/mvplevel/bean/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.mvplevel.bean; 2 | 3 | /** 4 | * Created by liuguangli on 16/1/24. 5 | */ 6 | public class UserInfo { 7 | private String nickName; 8 | 9 | private String level; 10 | 11 | public String getNickName() { 12 | return nickName; 13 | } 14 | 15 | public void setNickName(String nickName) { 16 | this.nickName = nickName; 17 | } 18 | 19 | public String getLevel() { 20 | return level; 21 | } 22 | 23 | public void setLevel(String level) { 24 | this.level = level; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/nolevel/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.nolevel; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.SharedPreferences; 5 | import android.support.v7.app.AppCompatActivity; 6 | 7 | import android.os.Build; 8 | import android.os.Bundle; 9 | import android.text.TextUtils; 10 | import android.view.View; 11 | import android.view.View.OnClickListener; 12 | import android.widget.AutoCompleteTextView; 13 | import android.widget.Button; 14 | import android.widget.EditText; 15 | import android.widget.Toast; 16 | 17 | import com.loopj.android.http.AsyncHttpClient; 18 | import com.loopj.android.http.RequestParams; 19 | import com.loopj.android.http.TextHttpResponseHandler; 20 | import com.mvpteach.liuguangli.mvpteach.R; 21 | import com.mvpteach.liuguangli.mvpteach.mvplevel.bean.*; 22 | 23 | import cz.msebera.android.httpclient.Header; 24 | 25 | /** 26 | * 登录功能无层次的设计,视图逻辑和数据逻辑耦合 27 | */ 28 | public class LoginActivity extends AppCompatActivity { 29 | 30 | private AutoCompleteTextView mUsernameView; 31 | private EditText mPasswordView; 32 | private View mProgressView; 33 | private View mLoginFormView; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_login); 39 | // Set up the login form. 40 | mUsernameView = (AutoCompleteTextView) findViewById(R.id.username); 41 | mPasswordView = (EditText) findViewById(R.id.password); 42 | mLoginFormView = findViewById(R.id.login_form); 43 | mProgressView = findViewById(R.id.login_progress); 44 | Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button); 45 | mEmailSignInButton.setOnClickListener(new OnClickListener() { 46 | @Override 47 | public void onClick(View view) { 48 | attemptLogin(); 49 | } 50 | }); 51 | 52 | } 53 | 54 | /** 55 | * 提交登录 56 | */ 57 | public void attemptLogin() { 58 | 59 | // Reset errors. 60 | mUsernameView.setError(null); 61 | mPasswordView.setError(null); 62 | // Store values at the time of the login attempt. 63 | String email = mUsernameView.getText().toString(); 64 | String password = mPasswordView.getText().toString(); 65 | boolean cancel = false; 66 | // Check for a valid password, if the user entered one. 67 | if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) { 68 | mPasswordView.setError(getString(R.string.error_invalid_password)); 69 | 70 | cancel = true; 71 | } 72 | // Check for a valid email address. 73 | if (TextUtils.isEmpty(email)) { 74 | mUsernameView.setError(getString(R.string.error_field_required)); 75 | cancel = true; 76 | } else if (!isEmailValid(email)) { 77 | mUsernameView.setError(getString(R.string.error_invalid_email)); 78 | cancel = true; 79 | } 80 | 81 | if (!cancel){ 82 | loginToServer(email,password); 83 | } 84 | } 85 | 86 | /** 87 | * 登录到服务器 88 | * @param email 89 | * @param password 90 | */ 91 | private void loginToServer(String email, String password) { 92 | showProcess(true); 93 | RequestParams request = new RequestParams(); 94 | request.put("username",email); 95 | request.put("password",password); 96 | new AsyncHttpClient().post(this, "http://192.168.12.12/app/user/login", request, new TextHttpResponseHandler() { 97 | @Override 98 | public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { 99 | //// TODO: 16/1/18 错误码解析和提示 100 | showErrorInfo(statusCode,responseString,responseString); 101 | } 102 | 103 | @Override 104 | public void onSuccess(int statusCode, Header[] headers, String responseString) { 105 | UserInfo userInfo = parseRes(responseString); 106 | saveInfo(userInfo); 107 | loginSuc(); 108 | } 109 | }); 110 | } 111 | 112 | private void saveInfo(UserInfo userInfo) { 113 | /* 114 | 为了说明逻辑,这里没有实现,假设这里使用sharedPreferences实现,那么以后想换一种方式, 115 | 涉及到UserInfo的地方都要修改了,而以我们的经验,通常一个App大部业务都会设计UserInfo */ 116 | 117 | SharedPreferences sharedPreferences = getSharedPreferences("user",MODE_APPEND); 118 | } 119 | 120 | private UserInfo parseRes(String string) { 121 | //为了说明逻辑,这里没有实现 122 | return null; 123 | } 124 | 125 | /** 126 | * 显示错误信息 127 | * @param code 错误码 128 | * @param devMsg 技术性提示信息 129 | * @param friendlyMsg 用户提示信息 130 | */ 131 | public void showErrorInfo(int code, String devMsg, String friendlyMsg) { 132 | Toast.makeText(this,devMsg,Toast.LENGTH_LONG).show(); 133 | } 134 | 135 | /** 136 | * 登录成功 137 | */ 138 | public void loginSuc() { 139 | 140 | Toast.makeText(this,getString(R.string.login_suc),Toast.LENGTH_LONG).show(); 141 | } 142 | 143 | /** 144 | * 显示进度 145 | */ 146 | @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2) 147 | public void showProcess(final boolean show) { 148 | mProgressView.setVisibility(show ? View.VISIBLE : View.GONE); 149 | mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE); 150 | } 151 | private boolean isEmailValid(String email) { 152 | //TODO: Replace this with your own logic 153 | return email.contains("@"); 154 | } 155 | 156 | private boolean isPasswordValid(String password) { 157 | //TODO: Replace this with your own logic 158 | return password.length() > 4; 159 | } 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | } 168 | 169 | -------------------------------------------------------------------------------- /app/src/main/java/com/mvpteach/liuguangli/mvpteach/nolevel/UserInfo.java: -------------------------------------------------------------------------------- 1 | package com.mvpteach.liuguangli.mvpteach.nolevel; 2 | 3 | /** 4 | * Created by liuguangli on 16/1/24. 5 | */ 6 | public class UserInfo { 7 | private String nickName; 8 | 9 | private String level; 10 | 11 | public String getNickName() { 12 | return nickName; 13 | } 14 | 15 | public void setNickName(String nickName) { 16 | this.nickName = nickName; 17 | } 18 | 19 | public String getLevel() { 20 | return level; 21 | } 22 | 23 | public void setLevel(String level) { 24 | this.level = level; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | 21 | 22 | 26 | 27 | 32 | 33 | 36 | 37 | 45 | 46 | 47 | 48 | 51 | 52 | 63 | 64 | 65 | 66 |