依赖:
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>