MVP接口回调注册
来源:互联网 发布:知乎 大泽佑香 编辑:程序博客网 时间:2024/05/29 13:09
权限
<uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
xml
<LinearLayout 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" android:orientation="vertical" tools:context="com.bwie.asus.project_two.RegisterActivity"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp"> <ImageView android:id="@+id/iv_regBack" android:layout_width="wrap_content" android:layout_height="50dp" android:padding="5dp" android:layout_centerVertical="true" android:src="@mipmap/btn_back_detail_normal" /> <TextView android:layout_margin="10dp" android:layout_alignParentRight="true" android:layout_width="wrap_content" android:layout_height="50dp" android:layout_centerVertical="true" android:text="帮助" android:textSize="20sp" /> </RelativeLayout> <EditText android:id="@+id/et_regName" android:layout_margin="20dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入用户名" android:textColorHint="#BDBDBD" android:textSize="25sp" android:textStyle="bold" /> <EditText android:id="@+id/et_regPwd" android:layout_margin="20dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请输入密码" android:textColorHint="#BDBDBD" android:textSize="25sp" android:textStyle="bold" android:password="true" /> <EditText android:id="@+id/et_regAgainPwd" android:layout_margin="20dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="确认输入密码" android:textColorHint="#BDBDBD" android:textSize="25sp" android:textStyle="bold" android:password="true" /> <EditText android:id="@+id/et_regEmail" android:layout_margin="20dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="请填写邮箱" android:textColorHint="#BDBDBD" android:textSize="25sp" android:textStyle="bold" /> <Button android:id="@+id/bt_regCommit" android:layout_margin="20dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="提交注册" android:textSize="25sp" android:textColor="#FFECDC" android:background="@drawable/shape_login_register" /></LinearLayout>
RegModelImpl类
package com.bwie.asus.project_two.model;import android.content.Context;import android.text.TextUtils;import android.util.Log;import com.bwie.asus.project_two.api.URLBean;import com.bwie.asus.project_two.bean.Register;import com.bwie.asus.project_two.port.RegFinishListener;import com.bwie.asus.project_two.utlis.GsonObjectCallback;import com.bwie.asus.project_two.utlis.OKHttp3Utils;import java.io.IOException;import java.util.HashMap;import java.util.Map;import okhttp3.Call;/** * Created by ASUS on 2017/10/15. */public class RegModelImpl implements RegModelInterface { private RegFinishListener listener; public RegModelImpl(RegFinishListener listener) { this.listener = listener; } @Override public void RegLogin(Context context, String regName, String regPwd, String regAgainPwd, String regEmail) { //注册用户名为空时 if(TextUtils.isEmpty(regName)){ //调用方法 listener.NameEmpty(); return; } //注册密码为空时 if(TextUtils.isEmpty(regPwd)){ //调用方法 listener.PwdEmpty(); return; } //注册确认密码为空时 if(TextUtils.isEmpty(regAgainPwd)){ //调用方法 listener.AgainPwdEmpty(); return; } //注册邮箱为空时 if(TextUtils.isEmpty(regEmail)){ //调用方法 listener.EmailEmpty(); return; } regRequest(context, regName, regPwd, regAgainPwd, regEmail); } @Override public void regRequest(final Context context, String regName, String regPwd, final String regAgainPwd, String regEmail) { //定义一个Map集合将参数进行封装 Map<String, String> regParams = new HashMap<String, String>(); //将参数添加到集合 regParams.put("username", regName); regParams.put("password", regPwd); regParams.put("password_confirm", regAgainPwd); regParams.put("email", regEmail); regParams.put("client", URLBean.REGISTERM);// OkHttpClient client = new OkHttpClient();// Request request = new Request.Builder().url(URLBean.REGISTERM).build();// client.newCall(request).enqueue(new Callback() {// @Override// public void onFailure(Call call, IOException e) {//// }//// @Override// public void onResponse(Call call, Response response) throws IOException {// String string = response.body().string();// System.out.println("string = " + string);// Gson gson = new Gson();// Register register = gson.fromJson(string, Register.class);// Register.DatasBean datas = register.getDatas();//// }//// }); OKHttp3Utils.doPost(URLBean.REGISTERM, regParams, new GsonObjectCallback<Register>() { @Override public void onUi(Register regBean) { Log.i("内容",regBean.toString()); if(regBean.getCode()==200){ listener.RegSucceed(); }else if(regBean.getCode()==400){ listener.RegFailed(); } } @Override public void onFailed(Call call, IOException e) { } }); }}RegModelInterface类
package com.bwie.asus.project_two.model;import android.content.Context;/** * Created by ASUS on 2017/10/15. */public interface RegModelInterface { void RegLogin(Context context, String regName, String regPwd, String regAgainPwd, String regEmail); void regRequest(Context context,String regName, String regPwd, String regAgainPwd, String regEmail);}RegFinishListener类
package com.bwie.asus.project_two.port;/** * Created by ASUS on 2017/10/15. */public interface RegFinishListener { void NameEmpty(); void PwdEmpty(); void AgainPwdEmpty(); void EmailEmpty(); void RegSucceed(); void RegFailed();}RegPresenterImpl类
package com.bwie.asus.project_two.presenter;import android.content.Context;import com.bwie.asus.project_two.model.RegModelImpl;import com.bwie.asus.project_two.port.RegFinishListener;import com.bwie.asus.project_two.view.RegViewInterface;/** * Created by ASUS on 2017/10/15. */public class RegPresenterImpl implements RegPresenterInterface,RegFinishListener{ private RegViewInterface regViewInterface; private final RegModelImpl regModel; public RegPresenterImpl(RegViewInterface regViewInterface) { this.regViewInterface = regViewInterface; regModel = new RegModelImpl(this); } @Override public void regGetData(Context context, String regName, String regPwd, String regAgainPwd, String regEmail) { if(regModel!=null){ regModel.RegLogin(context,regName,regPwd,regAgainPwd,regEmail); } } @Override public void NameEmpty() { if(regViewInterface!=null){ regViewInterface.onNameEmpty(); } } @Override public void PwdEmpty() { if(regViewInterface!=null) { regViewInterface.onPwdEmpty(); } } @Override public void AgainPwdEmpty() { if(regViewInterface!=null) { regViewInterface.onAgainPwdEmpty(); } } @Override public void EmailEmpty() { if(regViewInterface!=null) { regViewInterface.onEmailEmpty(); } } @Override public void RegSucceed() { if(regViewInterface!=null) { regViewInterface.onRegSucceed(); } } @Override public void RegFailed() { if(regViewInterface!=null) { regViewInterface.onRegFailed(); } }}RegPresenterInterface类
package com.bwie.asus.project_two.presenter;import android.content.Context;/** * Created by ASUS on 2017/10/15. */public interface RegPresenterInterface { void regGetData(Context context, String regName, String regPwd, String regAgainPwd, String regEmail);}RegViewInterface类
package com.bwie.asus.project_two.view;/** * Created by ASUS on 2017/10/15. */public interface RegViewInterface { void toBack(); void onNameEmpty(); void onPwdEmpty(); void onAgainPwdEmpty(); void onEmailEmpty(); void onRegSucceed(); void onRegFailed();}RegisterActivity类
package com.bwie.asus.project_two;import android.content.Intent;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.ImageView;import android.widget.Toast;import com.bwie.asus.project_two.presenter.RegPresenterImpl;import com.bwie.asus.project_two.view.RegViewInterface;public class RegisterActivity extends AppCompatActivity implements View.OnClickListener,RegViewInterface { private ImageView iv_regBack; private EditText et_regName; private EditText et_regPwd; private EditText et_regAgainPwd; private EditText et_regEmail; private Button bt_regCommit; private RegPresenterImpl regPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_register); initView(); //初始化RegPresenterImpl对象 regPresenter = new RegPresenterImpl(this); } private void initView() { iv_regBack = (ImageView) findViewById(R.id.iv_regBack); et_regName = (EditText) findViewById(R.id.et_regName); et_regPwd = (EditText) findViewById(R.id.et_regPwd); et_regAgainPwd = (EditText) findViewById(R.id.et_regAgainPwd); et_regEmail = (EditText) findViewById(R.id.et_regEmail); bt_regCommit = (Button) findViewById(R.id.bt_regCommit); bt_regCommit.setOnClickListener(this); iv_regBack.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bt_regCommit: Toast.makeText(this,"点击了注册按钮",Toast.LENGTH_SHORT).show(); if(regPresenter!=null){ regPresenter.regGetData(RegisterActivity.this, et_regName.getText().toString(), et_regPwd.getText().toString(), et_regAgainPwd.getText().toString(), et_regEmail.getText().toString()); } break; case R.id.iv_regBack: toBack(); break; } } @Override public void toBack() { //跳转到登录页面 startActivity(new Intent(RegisterActivity.this,LoginRegister.class)); } @Override public void onNameEmpty() { et_regName.setError("注册名不能为空"); } @Override public void onPwdEmpty() { et_regPwd.setError("注册密码不能为空"); } @Override public void onAgainPwdEmpty() { et_regAgainPwd.setError("请填写再次确定密码"); } @Override public void onEmailEmpty() { et_regEmail.setError("邮箱不能为空"); } @Override public void onRegSucceed() { Toast.makeText(RegisterActivity.this,"注册成功",Toast.LENGTH_SHORT).show(); //跳转到登录页面 startActivity(new Intent(RegisterActivity.this,LoginActivity.class)); } @Override public void onRegFailed() { et_regName.setText(""); et_regPwd.setText(""); et_regAgainPwd.setText(""); et_regEmail.setText(""); }}OKHttp3Utils类
package com.bwie.asus.project_two.utlis;import android.content.Context;import android.content.Intent;import android.net.Uri;import android.os.Build;import android.os.Environment;import android.os.Handler;import android.support.annotation.RequiresApi;import android.util.Log;import com.bwie.asus.project_two.app.MyApplication;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.Map;import java.util.concurrent.TimeUnit;import okhttp3.Cache;import okhttp3.CacheControl;import okhttp3.Call;import okhttp3.Callback;import okhttp3.FormBody;import okhttp3.Interceptor;import okhttp3.MediaType;import okhttp3.MultipartBody;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.RequestBody;import okhttp3.Response;import okhttp3.logging.HttpLoggingInterceptor;public class OKHttp3Utils { /** * 懒汉 安全 加同步 * 私有的静态成员变量 只声明不创建 * 私有的构造方法 * 提供返回实例的静态方法 */ //定义私有的静态成员变量 private static OKHttp3Utils okHttp3Utils=null; //私有的构造方法 private OKHttp3Utils(){ } //公共的静态方法用来返回实例 public static OKHttp3Utils getInstance(){ if(okHttp3Utils==null){ //加同步安全 synchronized (OKHttp3Utils.class){ if(okHttp3Utils==null){ okHttp3Utils=new OKHttp3Utils(); } } } return okHttp3Utils; } /** * 封装OKHttpClient对象 * */ //定义私有的静态的OKHttpClient成员变量 private static OkHttpClient okHttpClient=null; //定义公共的返回OkHttpClient实例的方法 public synchronized static OkHttpClient getOkHttpClient(){ if(okHttpClient==null){ //缓存目录 File sdcache=new File(Environment.getExternalStorageDirectory(),"cache"); //设置大小 int cacheSize=10*1024*1024; //OKHttp3拦截器 HttpLoggingInterceptor httpLoggingInterceptor=new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { @Override public void log(String message) { Log.i("XXX",message.toString()); } }); //OKHttp3的拦截器日志分类 4种 httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); //初始化OKHTTPClient对象 //判空 为空创建实例 // okHttpClient = new OkHttpClient(); /** * 和OkHttp2.x有区别的是不能通过OkHttpClient直接设置超时时间和缓存了, * 而是通过OkHttpClient.Builder来设置, * 通过builder配置好OkHttpClient后用builder.build()来返回OkHttpClient, * 所以我们通常不会调用new OkHttpClient()来得到OkHttpClient, * 而是通过builder.build(): */ okHttpClient =new OkHttpClient.Builder() //添加日志拦截 .addInterceptor(httpLoggingInterceptor) //添加网络拦截,进行缓存或从内存中读取 .addNetworkInterceptor(new CacheInterceptor()) //添加网络连接超时时间 .connectTimeout(20, TimeUnit.SECONDS) //设置写超时时间 .writeTimeout(20, TimeUnit.SECONDS) //设置读取超时时间 .readTimeout(20, TimeUnit.SECONDS) //设置缓存路径 .cache(new Cache(sdcache.getAbsoluteFile(),cacheSize)) .build(); } return okHttpClient; } /** *封装Handler,返回的此实例在二次封装的CallBack中使用 */ private static Handler mHandler=null; public synchronized static Handler getHandler(){ if(mHandler==null){ mHandler=new Handler(); } return mHandler; } /** * get请求 * 参数1:url * 参数2:回调CallBack */ public static void doGet(String url, Callback callback){ //创建OKHttpClient请求对象 OkHttpClient okHttpClient = getOkHttpClient(); //创建Request对象 Request request=new Request.Builder() .url(url) .build(); //得到Call对象 Call call = okHttpClient.newCall(request); //执行异步请求 call.enqueue(callback); } /** * post请求 * 参数1 url * 参数2 参数集合 * 参数3 回调CallBack */ public static void doPost(String url, Map<String,String> params, Callback callback){ //创建OKHttpClient对象 OkHttpClient okHttpClient = getOkHttpClient(); //3.X版本post请求换成FormBody封装键值对参数 FormBody.Builder builder=new FormBody.Builder(); //遍历参数集合 for(String key:params.keySet()){ //根据key值得到value值 String value = params.get(key); //将值添加到FormBody.Builder builder.add(key,value); } //创建Body FormBody body = builder.build(); //创建Request对象 Request request=new Request.Builder() .url(url) .post(body) .build(); //得到Call对象 Call call = okHttpClient.newCall(request); //进行异步请求 call.enqueue(callback); } /** * post请求上传文件 */ public static void uploadPic(String url, File file, String fileName){ //创建OKHttpClient请求对象 OkHttpClient okHttpClient = getOkHttpClient(); //创建RequestBody封装file对象 RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file); //创建RequestBody设置类型等 RequestBody requestBody=new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("file",fileName,fileBody) .build(); //创建Request对象 Request request=new Request.Builder() .url(url) .post(requestBody) .build(); //得到Call对象 Call call = okHttpClient.newCall(request); //执行请求 call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { } }); } /** * post请求发送JSON数据 * 参数1 请求Url * 参数2 请求的JSON * 参数3 请求回调 */ public static void doPostJson(String url, String jsonParams, Callback callback){ RequestBody requestBody= RequestBody.create(MediaType.parse("application/json;charset=utf-8"),jsonParams); //创建Request对象 Request request=new Request.Builder() .url(url) .post(requestBody) .build(); //创建Call对象 Call call = getOkHttpClient().newCall(request); //进行异步请求 call.enqueue(callback); } /** * 下载文件 以流的形式把apk写入指定文件 得到file文件后进行安装 * 参数1 请求Url * 参数2 保存文件的路径名 * 参数3 保存文件的文件名 */ public static void download(final Context context, final String url, final String saveDir){ //创建Request对象 Request request=new Request.Builder() .url(url) .build(); //获取Call对象 Call call = getOkHttpClient().newCall(request); //进行请求 call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.i("xxx",e.toString()); } @Override public void onResponse(Call call, Response response) throws IOException { InputStream is=null; byte[] buffer=new byte[1024]; int len=0; FileOutputStream fos=null; try { is=response.body().byteStream(); String fileDir = isExistDir(saveDir); File file=new File(fileDir,getNameFromUrl(url)); fos=new FileOutputStream(file); //执行读写操作 while((len=is.read(buffer))!=-1){ fos.write(buffer,0,len); } //刷新流 fos.flush(); //apk下载完成后 调用系统的安装方法 Intent intent=new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive"); context.startActivity(intent); } catch (IOException e) { e.printStackTrace(); } finally { //关闭流 if(is!=null){ is.close(); } if(fos!=null){ fos.close(); } } } }); } /** * 判断下载目录是否存在 */ public static String isExistDir(String saveDir) throws IOException { if(Environment.getExternalStorageDirectory().equals(Environment.MEDIA_MOUNTED)){ File downloadFile=new File(Environment.getExternalStorageDirectory(),saveDir); if(!downloadFile.mkdirs()){ downloadFile.createNewFile(); } String savePath = downloadFile.getAbsolutePath(); Log.e("savePath",savePath); return savePath; } return null; } /** * 从下载连接中解析出文件名 */ private static String getNameFromUrl(String url){ return url.substring(url.lastIndexOf("/")+1); } /** * 为OKHttp添加缓存,考虑到服务器不支持缓存时,让OKHttp支持缓存 */ private static class CacheInterceptor implements Interceptor { @RequiresApi(api = Build.VERSION_CODES.M) @Override public Response intercept(Chain chain) throws IOException { //有网络时设置缓存超时时间1个小时 int maxAge=60*60; //无网络时,设置超时时为1天 int maxStale=60*60*24; Request request = chain.request(); //判断当前是否有网 if(NetWorkUtils.isNetWorkAvailable(MyApplication.getInstance())){ //有网络时只从缓存中读取 request=request.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build(); }else{ //无网络时只从缓存中读取 request=request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build(); } Response response = chain.proceed(request); if(NetWorkUtils.isNetWorkAvailable(MyApplication.getInstance())){ response=response.newBuilder() .removeHeader("Pragma") .header("Cache-Control","public,max-age="+maxAge) .build(); }else { response=response.newBuilder() .removeHeader("Pragma") .header("Cache-Control","public,only-if-cached,max-stale="+maxStale) .build(); } return response; } }}NetWorkUtils类
package com.bwie.asus.project_two.utlis;import android.content.Context;import android.net.ConnectivityManager;import android.net.NetworkInfo;/** * Created by ASUS on . */public class NetWorkUtils { public static boolean isNetWorkAvailable(Context context){ //网络连接管理器 ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); //网络信息 NetworkInfo info = connectivityManager.getActiveNetworkInfo(); if (info != null) { return true; } return false; }}GsonObjectCallback类
package com.bwie.asus.project_two.utlis;import android.os.Handler;import com.google.gson.Gson;import java.io.IOException;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import okhttp3.Call;import okhttp3.Callback;import okhttp3.Response;/** * 类的用途 如果要将得到的json直接转化为集合 建议使用该类的 * onUi() * onFailed()方法运行在主线程 * Created by ASUS on 2017/10/10. */public abstract class GsonObjectCallback<T> implements Callback { //得到Handler对象 private Handler handler=OKHttp3Utils.getHandler(); //主线程处理 public abstract void onUi(T t); //主线程处理 public abstract void onFailed(Call call, IOException e); //请求失败 @Override public void onFailure(final Call call, final IOException e) { handler.post(new Runnable() { @Override public void run() { onFailed(call, e); } }); } //请求成功,JSON 并直接返回泛型的对象 主线程处理 @Override public void onResponse(Call call, Response response) throws IOException { //将请求结果转换成字符串 String json = response.body().string(); Class<T> cls=null; Class clz=this.getClass(); //表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type //简而言之就是获得超类的泛型参数的实际类型 ParameterizedType type= (ParameterizedType) clz.getGenericSuperclass(); // 获取泛型类型的泛型参数 Type[] types = type.getActualTypeArguments(); cls= (Class<T>) types[0]; //获取Gson对象 Gson gson=new Gson(); //将内容进行解析 final T t = gson.fromJson(json, cls); //通过Handler发送消息 handler.post(new Runnable() { @Override public void run() { //将对象交给主线程 onUi(t); } }); }}GsonArrayCallback类
package com.bwie.asus.project_two.utlis;import android.os.Handler;import com.google.gson.Gson;import com.google.gson.JsonArray;import com.google.gson.JsonElement;import com.google.gson.JsonParser;import java.io.IOException;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.ArrayList;import java.util.List;import okhttp3.Call;import okhttp3.Callback;import okhttp3.Response;public abstract class GsonArrayCallback<T> implements Callback { //获取Handler对象 private Handler handler=OKHttp3Utils.getHandler(); //主线程处理 public abstract void onUi(List<T> list); //主线程处理 public abstract void onFiled(Call call, IOException e); //请求失败 @Override public void onFailure(final Call call, final IOException e) { handler.post(new Runnable() { @Override public void run() { onFailure(call, e); } }); } @Override public void onResponse(Call call, Response response) throws IOException { //创建一个集合 final List<T> list=new ArrayList<T>(); //将获取的数据转换成字符串 String json = response.body().string(); //Json的解析类对象 JsonParser()将JSON的String 转成一个JsonArray对象 JsonArray array=new JsonParser().parse(json).getAsJsonArray(); //获取Gson对象 Gson gson=new Gson(); // Class<T> cls=null; Class clz=this.getClass(); ParameterizedType type= (ParameterizedType) clz.getGenericSuperclass(); Type[] types = type.getActualTypeArguments(); cls= (Class<T>) types[0]; /** * JsonElement 四种具体实现类型: * JsonPrimitive (Java Doc) —— 例如一个字符串或整型 * JsonObject (Java Doc) —— 一个以 JsonElement 名字(类型为 String)作为索引的集合。类似于 Map<String,JsonElement>集合(Java Doc) * JsonArray (Java Doc)—— JsonElement 的集合。注意数组的元素可以是四种类型中的任意一种,或者混合类型都支持。 * JsonNull (Java Doc) —— 值为null */ //遍历集合 for(JsonElement elem:array){ list.add((gson.fromJson(elem,cls))); } //通过Handler将集合发送到主线程 handler.post(new Runnable() { @Override public void run() { onUi(list); } }); }}
MyApplication类
package com.bwie.asus.project_two.app;import android.app.Application;import com.nostra13.universalimageloader.core.ImageLoader;import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;/** * Created by ASUS on 2017/10/12. */public class MyApplication extends Application { public static MyApplication mapp; @Override public void onCreate() { super.onCreate(); mapp = this; ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this).build(); ImageLoader.getInstance().init(configuration); } public static MyApplication getInstance(){ return mapp; }}
Bean类
阅读全文
0 0
- MVP接口回调注册
- MVP接口登录注册
- MVP接口回调登录
- MVP注册
- 请求网络接口_注册登录之MVP模式
- 广播方式注册的接口回调
- 接口回调实现登陆注册界面
- MVP入门,接口回调new接口和implement实现,防止内存泄露解绑
- MVP 实现登录注册
- 登录注册mvp模式
- MVP注册登录
- Mvp实现登陆注册
- MVP注册用户
- MVP 登录注册
- MVP注册登录
- MVP 登录+注册
- MVP登录注册
- MVP登录注册
- 关于对getchar一些小小的自学理解。。。
- 160个CrackMe之51
- c++ string中的reserve()和resize()
- Ubuntu安装anaconda,tensorflow,keras,pytorch
- 剑指offer--栈的压入、弹出序列
- MVP接口回调注册
- dpkg 被中断,您必须手工运行 sudo dpkg –configure -a解决此问题
- Idea中Git的使用和两种类型的冲突解决
- unity3d Unity协程(Coroutine)yield 表达式解释
- 笔试_公司(2)
- (M)DFS:129. Sum Root to Leaf Numbers
- PKU Helper 招新面试二
- 双精度有效位
- python 更换windows壁纸(简单)