依赖:
implementation 'com.squareup.okhttp3:okhttp:3.10.0' implementation 'com.google.code.gson:gson:2.2.4'
Constant:
public class Constant { public static final String BASE_URL = "https://www.zhaoapi.cn/"; }
CrashApplication:
public class CrashApplication extends Application { @Override public void onCreate() { super.onCreate(); // com.example.test_mvp.utils.CrashHandler crashHandler = com.example.test_mvp.utils.CrashHandler.getInstance(); // crashHandler.init(getApplicationContext()); } }
LoginBean:
public class LoginBean { /** * msg : 登录成功 * code : 0 * data : {"age":null,"appkey":"9e3890cbff8d7963","appsecret":"9BCB17D8A710F99598154C979E5DA0F8","createtime":"2018-04-20T13:37:29","email":null,"fans":null,"follow":null,"gender":null,"icon":null,"latitude":null,"longitude":null,"mobile":"18611620300","money":null,"nickname":null,"password":"543E091EFE89E0759D34AC87BDABAB17","praiseNum":null,"token":"8BCCACC86A76B846048697973AAF26F5","uid":13661,"userId":null,"username":"18611620300"} */ private String msg; private String code; private DataBean data; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public DataBean getData() { return data; } public void setData(DataBean data) { this.data = data; } public static class DataBean { /** * age : null * appkey : 9e3890cbff8d7963 * appsecret : 9BCB17D8A710F99598154C979E5DA0F8 * createtime : 2018-04-20T13:37:29 * email : null * fans : null * follow : null * gender : null * icon : null * latitude : null * longitude : null * mobile : 18611620300 * money : null * nickname : null * password : 543E091EFE89E0759D34AC87BDABAB17 * praiseNum : null * token : 8BCCACC86A76B846048697973AAF26F5 * uid : 13661 * userId : null * username : 18611620300 */ private Object age; private String appkey; private String appsecret; private String createtime; private Object email; private Object fans; private Object follow; private Object gender; private Object icon; private Object latitude; private Object longitude; private String mobile; private Object money; private Object nickname; private String password; private Object praiseNum; private String token; private int uid; private Object userId; private String username; public Object getAge() { return age; } public void setAge(Object age) { this.age = age; } public String getAppkey() { return appkey; } public void setAppkey(String appkey) { this.appkey = appkey; } public String getAppsecret() { return appsecret; } public void setAppsecret(String appsecret) { this.appsecret = appsecret; } public String getCreatetime() { return createtime; } public void setCreatetime(String createtime) { this.createtime = createtime; } public Object getEmail() { return email; } public void setEmail(Object email) { this.email = email; } public Object getFans() { return fans; } public void setFans(Object fans) { this.fans = fans; } public Object getFollow() { return follow; } public void setFollow(Object follow) { this.follow = follow; } public Object getGender() { return gender; } public void setGender(Object gender) { this.gender = gender; } public Object getIcon() { return icon; } public void setIcon(Object icon) { this.icon = icon; } public Object getLatitude() { return latitude; } public void setLatitude(Object latitude) { this.latitude = latitude; } public Object getLongitude() { return longitude; } public void setLongitude(Object longitude) { this.longitude = longitude; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; } public Object getMoney() { return money; } public void setMoney(Object money) { this.money = money; } public Object getNickname() { return nickname; } public void setNickname(Object nickname) { this.nickname = nickname; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Object getPraiseNum() { return praiseNum; } public void setPraiseNum(Object praiseNum) { this.praiseNum = praiseNum; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } public int getUid() { return uid; } public void setUid(int uid) { this.uid = uid; } public Object getUserId() { return userId; } public void setUserId(Object userId) { this.userId = userId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } } }
RegisterBean:
public class RegisterBean { /** * msg : 天呢!用户已注册 * code : 1 * data : {} */ private String msg; private String code; private String data; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getData() { return data; } public void setData(String data) { this.data = data; } }
HttpUtilsCallback:
public interface HttpUtilsCallback { void onSuccess(String success); void onFail(int errCode,String errMsg); }
NetUtil:
public class NetUtil implements Callback { private static NetUtil INSTANCE; private final OkHttpClient okHttpClient; private HttpUtilsCallback httpUtilsCallback; private NetUtil() { okHttpClient = new OkHttpClient.Builder().build(); } public static NetUtil getInstance(){ if (INSTANCE==null){ INSTANCE = new NetUtil(); } return INSTANCE; } public String doGet(String path){ String url = "https://www.zhaoapi.cn/user/login?mobile=12345678901&password=123456"; Request request = new Request.Builder() .url(Constant.BASE_URL+path) .build(); Call call = okHttpClient.newCall(request); call.enqueue(this); return "ok"; } public String doPost(String path, HashMap<String,String> map,HttpUtilsCallback httpUtilsCallback){ this.httpUtilsCallback = httpUtilsCallback; FormBody.Builder builder = new FormBody.Builder(); Iterator<String> iterator = map.keySet().iterator(); while (iterator.hasNext()){ String key = iterator.next(); String value = map.get(key); builder.add(key,value); } FormBody body = builder.build(); Request request = new Request.Builder() .url(Constant.BASE_URL+path) .post(body) .build(); Call call = okHttpClient.newCall(request); call.enqueue(this); return ""; } @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { String string = response.body().string(); httpUtilsCallback.onSuccess(string); } }
BasePresenter:
*/ public class BasePresenter<T extends IBaseView> { private T t; public void attachView(T t){ this.t=t; } public T getView(){ return t; } public void detachView(){ t=null; } }
MainPresenter:
public class MainPresenter extends BasePresenter<IMainView>{ private NetUtil netUtil; public MainPresenter() { netUtil = NetUtil.getInstance(); } public void getDataFromServer(String path,HashMap<String, String> map) { netUtil.doPost(path, map, new HttpUtilsCallback() { @Override public void onSuccess(String success) { getView().onSuccess(success); } @Override public void onFail(int errCode, String errMsg) { } }); } }
RegisterPresenter:
public class RegisterPresenter extends BasePresenter<IRegisterView>{ private NetUtil netUtil; public RegisterPresenter() { netUtil = NetUtil.getInstance(); } public void getDataFromServer(String path,HashMap<String, String> map) { netUtil.doPost(path, map, new HttpUtilsCallback() { @Override public void onSuccess(String success) { getView().onSuccess(success); } @Override public void onFail(int errCode, String errMsg) { } }); } }
CommonUtil:
public class CommonUtil { public static boolean isMobileNO(String mobiles){ Pattern p = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$"); Matcher m = p.matcher(mobiles); System.out.println(m.matches()+"---"); return m.matches(); } public static boolean isPassNO(String pass){ Pattern p = Pattern.compile("^(?=.*?[a-z])(?=.*?[0-9])[a-zA-Z0-9_]{6,16}$"); Matcher m = p.matcher(pass); System.out.println(m.matches()+"---"); return m.matches(); } }
CrashHandler:
public class CrashHandler implements Thread.UncaughtExceptionHandler{ public static final String TAG = "CrashHandler"; //系统默认的UncaughtException处理类 private Thread.UncaughtExceptionHandler mDefaultHandler; //CrashHandler实例 private static CrashHandler INSTANCE = new CrashHandler(); //程序的Context对象 private Context mContext; //用来存储设备信息和异常信息 private Map<String, String> infos = new HashMap<String, String>(); //用于格式化日期,作为日志文件名的一部分 private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); /** 保证只有一个CrashHandler实例 */ private CrashHandler() { } /** 获取CrashHandler实例 ,单例模式 */ public static CrashHandler getInstance() { return INSTANCE; } /** * 初始化 * * @param context */ public void init(Context context) { mContext = context; //获取系统默认的UncaughtException处理器 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); //设置该CrashHandler为程序的默认处理器 Thread.setDefaultUncaughtExceptionHandler(this); } /** * 当UncaughtException发生时会转入该函数来处理 */ @Override public void uncaughtException(Thread thread, Throwable ex) { if (!handleException(ex) && mDefaultHandler != null) { //如果用户没有处理则让系统默认的异常处理器来处理 mDefaultHandler.uncaughtException(thread, ex); } else { try { Thread.sleep(3000); } catch (InterruptedException e) { Log.e(TAG, "error : ", e); } //退出程序 android.os.Process.killProcess(android.os.Process.myPid()); System.exit(1); } } /** * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. * * @param ex * @return true:如果处理了该异常信息;否则返回false. */ private boolean handleException(Throwable ex) { if (ex == null) { return false; } //使用Toast来显示异常信息 new Thread() { @Override public void run() { Looper.prepare(); Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG).show(); Looper.loop(); } }.start(); //收集设备参数信息 collectDeviceInfo(mContext); //保存日志文件 saveCrashInfo2File(ex); return true; } /** * 收集设备参数信息 * @param ctx */ public void collectDeviceInfo(Context ctx) { try { PackageManager pm = ctx.getPackageManager(); PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES); if (pi != null) { String versionName = pi.versionName == null ? "null" : pi.versionName; String versionCode = pi.versionCode + ""; infos.put("versionName", versionName); infos.put("versionCode", versionCode); } } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "an error occured when collect package info", e); } Field[] fields = Build.class.getDeclaredFields(); for (Field field : fields) { try { field.setAccessible(true); infos.put(field.getName(), field.get(null).toString()); Log.d(TAG, field.getName() + " : " + field.get(null)); } catch (Exception e) { Log.e(TAG, "an error occured when collect crash info", e); } } } /** * 保存错误信息到文件中 * * @param ex * @return 返回文件名称,便于将文件传送到服务器 */ private String saveCrashInfo2File(Throwable ex) { StringBuffer sb = new StringBuffer(); for (Map.Entry<String, String> entry : infos.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); sb.append(key + "=" + value + "\n"); } Writer writer = new StringWriter(); PrintWriter printWriter = new PrintWriter(writer); ex.printStackTrace(printWriter); Throwable cause = ex.getCause(); while (cause != null) { cause.printStackTrace(printWriter); cause = cause.getCause(); } printWriter.close(); String result = writer.toString(); sb.append(result); try { long timestamp = System.currentTimeMillis(); String time = formatter.format(new Date()); String fileName = "crash-" + time + "-" + timestamp + ".log"; if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { String path = "/sdcard/crash/"; File dir = new File(path); if (!dir.exists()) { dir.mkdirs(); } FileOutputStream fos = new FileOutputStream(path + fileName); fos.write(sb.toString().getBytes()); fos.close(); } return fileName; } catch (Exception e) { Log.e(TAG, "an error occured while writing file...", e); } return null; } }
BaseActivity:
public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements IBaseView { private MyTitleView parent_title; private FrameLayout child_view; private P p; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base); initParentView(); View view = View.inflate(this, setChildContentView(), null); child_view.addView(view); initView(); p=initPresenter(); if (p != null) { p.attachView(this); }else { try { throw new Exception("少年 prenter 没有设置 请在您的Activity 创建 presenter"); } catch (Exception e) { e.printStackTrace(); } } initData(); } public MyTitleView getParent_title(){ return parent_title; } private void initParentView() { parent_title = findViewById(R.id.parent_title); child_view = findViewById(R.id.child_view); parent_title.getBack().setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); } public P getPresenter() { return p; } abstract void initView(); abstract void initData(); abstract P initPresenter(); abstract int setChildContentView(); }
MainActivity:
public class MainActivity extends BaseActivity<MainPresenter> implements IMainView, View.OnClickListener { private EditText et_mobile; private EditText et_password; private LoginBean loginBean=new LoginBean(); private Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 0: Toast.makeText(MainActivity.this, loginBean.getMsg(), Toast.LENGTH_SHORT).show(); // code":"0" 登陆成功 if (loginBean.getCode().equals("0")){ Log.e("--MainActivity--","跳转到内容页"); } break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override void initView() { //初始化控件 et_mobile = findViewById(R.id.et_mobile); et_password = findViewById(R.id.et_password); findViewById(R.id.btn_login).setOnClickListener(this); findViewById(R.id.btn_register).setOnClickListener(this); } @Override void initData() { //设置标题名称 getParent_title().getTitle().setText(getResources().getString(R.string.login)); } @Override MainPresenter initPresenter() { return new MainPresenter(); } @Override int setChildContentView() { return R.layout.activity_main; } @Override public void onSuccess(String success) { //gson解析数据 Gson gson = new Gson(); loginBean = gson.fromJson(success, LoginBean.class); //handler通知主线程操作数据 handler.sendEmptyMessage(0); Log.e("---MainActivity---",success); } @Override public void onError(String error) { } @Override protected void onDestroy() { super.onDestroy(); getPresenter().detachView(); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.btn_login: //判断账号密码 是否符合规格 String name = et_mobile.getText().toString(); String pass = et_password.getText().toString(); if(!CommonUtil.isMobileNO(name)) { Toast.makeText(MainActivity.this,getResources().getString(R.string.wrong_mobile_num),Toast.LENGTH_SHORT).show(); return; } if(!CommonUtil.isPassNO(pass)) { Toast.makeText(MainActivity.this,getResources().getString(R.string.wrong_password),Toast.LENGTH_SHORT).show(); return; } //发送账号密码验证登录 if(getPresenter() != null) { String path = "user/login"; HashMap<String,String> hashMap = new HashMap<>(); hashMap.put("mobile",name); hashMap.put("password",pass); getPresenter().getDataFromServer(path,hashMap); } break; case R.id.btn_register: //跳转到注册页面 Intent intent = new Intent(MainActivity.this, RegisterActivity.class); startActivity(intent); break; } } }
RegisterActivity:
public class RegisterActivity extends BaseActivity<RegisterPresenter> implements IRegisterView,View.OnClickListener { private String s; private EditText password; private EditText mobile; private EditText password_sure; private RegisterBean registerBean=new RegisterBean(); private Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 1: Toast.makeText(RegisterActivity.this, registerBean.getMsg(), Toast.LENGTH_SHORT).show(); if (registerBean.getCode().equals("0")){ Intent intent = new Intent(RegisterActivity.this, MainActivity.class); startActivity(intent); } break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override void initView() { password = findViewById(R.id.password); mobile = findViewById(R.id.mobile); password_sure = findViewById(R.id.password_sure); findViewById(R.id.register).setOnClickListener(this); } @Override void initData() { getParent_title().getTitle().setText(getResources().getString(R.string.register)); } @Override RegisterPresenter initPresenter() { return new RegisterPresenter(); } @Override int setChildContentView() { return R.layout.activity_register; } @Override public void onClick(View view) { switch (view.getId()){ case R.id.register: String phoneNum = mobile.getText().toString(); String passwrd = password.getText().toString(); String passwrd_sure = password_sure.getText().toString(); if(!CommonUtil.isMobileNO(phoneNum)) { Toast.makeText(RegisterActivity.this,getResources().getString(R.string.wrong_mobile_num),Toast.LENGTH_SHORT).show(); return; } if(!CommonUtil.isPassNO(passwrd)) { Toast.makeText(RegisterActivity.this,getResources().getString(R.string.wrong_password),Toast.LENGTH_SHORT).show(); return; } if (!passwrd.equals(passwrd_sure)) { Toast.makeText(RegisterActivity.this,getResources().getString(R.string.wrong_password_diff),Toast.LENGTH_SHORT).show(); return; } if(getPresenter() != null) { String path = "user/reg"; HashMap<String,String> hashMap = new HashMap<>(); hashMap.put("mobile",phoneNum); hashMap.put("password",passwrd); getPresenter().getDataFromServer(path,hashMap); } break; } } @Override public void onSuccess(String success) { Gson gson = new Gson(); registerBean = gson.fromJson(success, RegisterBean.class); handler.sendEmptyMessage(1); Log.e("---MainActivity---",success); } @Override public void onError(String error) { } @Override protected void onDestroy() { super.onDestroy(); getPresenter().detachView(); } }
MyTitleView:
public class MyTitleView extends RelativeLayout implements View.OnClickListener { private Context context; private TextView textView; private ImageView imageView; public MyTitleView(Context context) { this(context,null); } public MyTitleView(Context context, AttributeSet attrs) { this(context, attrs,0); } public MyTitleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context=context; initView(context); } private void initView(final Context context) { LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); params.addRule(RelativeLayout.CENTER_IN_PARENT); textView = new TextView(context); textView.setId(R.id.tv); textView.setText("标题"); textView.setTextSize(20); textView.setTextColor(Color.WHITE); addView(textView,params); textView.setOnClickListener(this); LayoutParams params1 = new LayoutParams(100, 100); params1.addRule(RelativeLayout.ALIGN_LEFT); params1.addRule(RelativeLayout.CENTER_VERTICAL); params1.leftMargin=20; imageView = new ImageView(context); imageView.setId(R.id.img); imageView.setImageResource(R.drawable.icon_back); addView(imageView,params1); } public TextView getTitle(){ return textView; } public ImageView getBack(){ return imageView; } @Override public void onClick(View view) { switch(view.getId()){ case R.id.tv: Toast.makeText(context, ""+textView.getText().toString(), Toast.LENGTH_SHORT).show(); break; } } }
IBaseView:
public interface IBaseView { }
IMainView:
public interface IMainView extends IBaseView { void onSuccess(String success); void onError(String error); }
IRegisterView:
public interface IRegisterView extends IBaseView { void onSuccess(String success); void onError(String error); }
activity_base.xml:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".view.activity.BaseActivity"> <com.example.test_mvp.view.customview.MyTitleView android:id="@+id/parent_title" android:layout_width="match_parent" android:layout_height="56dp" android:background="@color/colorAccent"/> <FrameLayout android:id="@+id/child_view" android:layout_width="match_parent" android:layout_height="match_parent"/> </android.support.constraint.ConstraintLayout>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".view.activity.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_centerInParent="true" android:gravity="center"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/mobile_tag"/> <EditText android:id="@+id/et_mobile" android:layout_width="260dp" android:layout_height="50dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/password_tag"/> <EditText android:id="@+id/et_password" android:layout_width="260dp" android:layout_height="50dp" android:inputType="textPassword"/> <Button android:id="@+id/btn_login" android:layout_width="90dp" android:layout_height="60dp" android:text="@string/login"/> <Button android:id="@+id/btn_register" android:layout_width="90dp" android:layout_height="60dp" android:text="@string/register"/> </LinearLayout> </RelativeLayout>
activity_register.xml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".view.activity.RegisterActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_centerInParent="true" android:gravity="center"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/mobile_tag"/> <EditText android:id="@+id/mobile" android:layout_width="260dp" android:layout_height="50dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/password_tag"/> <EditText android:id="@+id/password" android:layout_width="260dp" android:layout_height="50dp" android:inputType="textPassword"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/password_tag_s"/>
<?xml version="1.0" encoding="utf-8"?> <resources> <item name="tv" type="id"/> <item name="img" type="id"/> </resources>
<EditText android:id="@+id/password_sure" android:layout_width="260dp" android:layout_height="50dp" android:inputType="textPassword"/> <Button android:id="@+id/register" android:layout_width="90dp" android:layout_height="60dp" android:text="@string/register"/> </LinearLayout></RelativeLayout>
ids.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <item name="tv" type="id"/> <item name="img" type="id"/> </resources>
strings.xml:
<resources> <string name="app_name">Test_MVP</string> <string name="mobile_tag">请填写手机号</string> <string name="password_tag">请填写密码</string> <string name="password_tag_s">请确认密码</string> <string name="register">注册</string> <string name="login">登录</string> <string name="wrong_mobile_num">手机号格式不正确</string> <string name="wrong_password">密码格式不正确</string> <string name="wrong_password_diff">两次密码不一致</string> </resources>