P1-Android基于MVP实现号码归属地查询

mac2022-06-30  104

零、前言

[1].最近在总结了安卓的知识点,现在来穿插一个小项目,算是对前面的一个小小总结 [2].本案例是以前在慕课网的学习的一个免费课程,代码看不懂的可以去看看:号码归属地查询实用工具 [3].相比与视频课程,本案例按照我的理解,对项目结构进行了优化。 [4].案例网络模块是自己对okhttp3的封装,当然你也完全可以使用其他的上层网络框架 [5].相比课程,加入缓存机制,使用前面写过的缓存封装:详见:缓存文件封装 [6].使用前面的listview封装类:详见:ListView的封装 [7].Json的解析详见:Json在Android中的使用--Gson

项目结构及类图
号码归属地查询MVP类图.png 号码归属地查询.gif 手机归属地查询缓存.png

一、M:模型层:负责数据的请求、解析、过滤等数据层操作

[1].将网络加载数据逻辑放在模型层,提供数据给控制层。 [2].模型层中设置加载监听用来传递数据,及状态(利于控制层对视图层控制)

1.模型层接口--定义模型的方法接口
/** * 作者:张风捷特烈<br/> * 时间:2018/8/31 0031:13:32<br/> * 邮箱:1981462002@qq.com<br/> * 说明:模型层接口 */ public interface ICallModel { /** * 获取数据 * * @param ctx 上下文 * @param phoneNum 电话号码 */ void getData(Context ctx, String phoneNum); }
2.模型层接口实现类:负责数据的获取
/** * 作者:张风捷特烈<br/> * 时间:2018/8/31 0031:13:34<br/> * 邮箱:1981462002@qq.com<br/> * 说明:模型层,提供数据 */ public class CallModelImpl implements ICallModel { private String mUrl = "https://tcc.taobao.com/cc/json/mobile_tel_segment.htm"; /** * 获取Json * * @param phoneNum 电话 */ public void getData(Context ctx, String phoneNum) { //获取网络数据} HashMap<String, String> param = new HashMap<>(); param.put("tel", phoneNum); new GetDataWithCache(mUrl, param, new InnerFileStrategy(ctx)) { @Override public void success(String response) { String[] split = response.split("="); Phone phone = new Gson().fromJson(split[1].trim(), Phone.class); if (mOnLoadListener != null) { mOnLoadListener.success(phone); } } @Override public void error(String error) { if (mOnLoadListener != null) { mOnLoadListener.error(error); } } }; } ///设置加载监听,传递数据,及状态(利于控制层对视图层控制) public interface OnLoadListener { /** * 成功监听 * * @param phone 解析后得到的实体 */ void success(Phone phone); /** * 失败监听 * * @param str 失败信息 */ void error(String str); } private OnLoadListener mOnLoadListener; public void setOnLoadListener(OnLoadListener onLoadListener) { mOnLoadListener = onLoadListener; } }
3.实体类:Phone
public class Phone { /** * mts : 1871507 * province : 安徽 * catName : 中国移动 * telString : 18715079389 * areaVid : 30509 * ispVid : 3236139 * carrier : 安徽移动 */ private String mts; private String province; private String catName; private String telString; private String areaVid; private String ispVid; private String carrier; //get set 方法省略......

二、控制层:View和Model沟通的桥梁

1.基类BasePresenter:为了方便让控制层和Activity生命周期同步
/** * 作者:张风捷特烈 * 时间:2018/4/25:9:40 * 邮箱:1981462002@qq.com * 说明:Presenter基类--为了方便让控制层和Activity生命周期同步 */ public class BasePresenter { private Context mCtx; public void attach(Context ctx) { mCtx = ctx; } public void onPause() { } public void onResume() { } public void onDestroy() { mCtx = null; } public Context getCtx() { return mCtx; } }
2.控制层实现类:CallPresenterImpl
/** * 作者:张风捷特烈 * 时间:2018/4/25:9:38 * 邮箱:1981462002@qq.com * 说明:控制层实现类 */ public class CallPresenterImpl extends BasePresenter { public ICallView mICallView; private Phone mPhone; private final CallModelImpl mCallModel; Handler handler = new Handler(); public CallPresenterImpl(ICallView iCallView) { mICallView = iCallView; mCallModel = new CallModelImpl(); } /** * 从网络获取数据 * * @param phoneNum 手机号 */ public void getDataFromInternet(final String phoneNum) { if (!checkPhoneNum(phoneNum)) { //号码错误让视图层处理 mICallView.numError(); return; } //校验正确--视图层:显示进度条 mICallView.showLoading(); //耗时操作新开线程 new Thread() { @Override public void run() { handler.post( new Thread(new Runnable() { @Override public void run() { getDataFromModel(phoneNum); } })); } }.start(); } /** * 从模型层获取数据,并根据监听设置视图层 * @param phoneNum 号码 */ private void getDataFromModel(String phoneNum) { mCallModel.getData(getCtx(), phoneNum); mCallModel.setOnLoadListener(new CallModelImpl.OnLoadListener() { @Override public void success(Phone phone) { //接收模型层数据 mPhone = phone; //网络加载、解析数据完成--视图层:隐藏进度条 mICallView.hideLoading(); //视图层--更新视图 mICallView.updateView(); } @Override public void error(String str) { //网络加载失败--视图层:隐藏进度条 mICallView.hideLoading(); mICallView.loadDataError(); } }); } public Phone getPhone() { return mPhone; } /** * 检查手机号是否合法 * * @param phone 手机号 * @return 是否合法 */ public boolean checkPhoneNum(String phone) { Pattern pattern = Pattern.compile("^[1][3,4,5,8][0-9]{9}$"); // 验证手机号 Matcher matcher = pattern.matcher(phone); return matcher.matches(); } }

三、视图层 V:负责视图部分展示、视图事件处理

1.显示和消失对话框接口--由于非常常见所以单独抽出
/** * 作者:张风捷特烈 * 时间:2018/4/25:9:37 * 邮箱:1981462002@qq.com * 说明:显示和消失对话框接口--由于非常常见所以单独抽出 */ public interface ILoadingView { /** * 显示进度条 */ void showLoading(); /** * 隐藏进度条 */ void hideLoading(); }
2.视图层接口
/** * 作者:张风捷特烈 * 时间:2018/4/25:9:31 * 邮箱:1981462002@qq.com * 说明:视图层接口 */ public interface ICallView extends ILoadingView { /** * 更新视图 */ void updateView(); /** * 号码错误视图操作 */ void numError(); /** * 网络获取数据异常视图操作 */ void loadDataError(); }
3.视图层基类--已封装进度条显隐逻辑
/** * 作者:张风捷特烈 * 时间:2018/4/25:12:52 * 邮箱:1981462002@qq.com * 说明:视图层基类--已封装进度条显隐逻辑 */ public abstract class BaseICallActivity extends AppCompatActivity implements ICallView { private ProgressDialog mProgressDialog; /** * 更新视图 */ public abstract void updateView(); @Override public void showLoading() { if (mProgressDialog == null) { mProgressDialog = ProgressDialog.show(this, "", "Loading...", true, false); } else if (mProgressDialog.isShowing()) { mProgressDialog.setTitle(""); mProgressDialog.setMessage("Loading..."); } mProgressDialog.show(); } @Override public void hideLoading() { if (mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.dismiss(); } } @Override public void onBackPressed() { if (mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.dismiss(); } super.onBackPressed(); } }
4.视图层核心:CallPhoneActivity
/** * 作者:张风捷特烈 * 时间:2018/4/25:12:52 * 邮箱:1981462002@qq.com * 说明:视图层核心 */ public class CallPhoneActivity extends BaseICallActivity { @BindView(R.id.et_phone) EditText mEtPhone; @BindView(R.id.btn_search) Button mBtnSearch; @BindView(R.id.textView) TextView mTextView; @BindView(R.id.lv_info) ListView mLvInfo; private CallPresenterImpl mCallPresenterImpl; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_call); ButterKnife.bind(this); //视图层持有控制层对象 mCallPresenterImpl = new CallPresenterImpl(this); mCallPresenterImpl.attach(this); } @OnClick(R.id.btn_search) public void onViewClicked() { //控制层对象执行逻辑,将视图层数据传入控制层 mCallPresenterImpl.getDataFromInternet(mEtPhone.getText().toString()); } @Override public void updateView() { Phone phone = mCallPresenterImpl.getPhone(); ArrayList<String> infos = new ArrayList<>(); infos.add("手机号:" + phone.getTelString()); infos.add("运营商:" + phone.getCatName()); infos.add("省份:" + phone.getProvince()); infos.add("详情信息:" + phone.getCarrier()); mLvInfo.setAdapter(new MyLVAdapter<String>(this, infos, R.layout.simple_item_tv1) { @Override public void setData(MyLVHolder holder, String data, int position) { holder.setText(R.id.tv_item1, data); } }); } @Override public void numError() { mTextView.setError(""); ToastUtil.show(this, "输入正确的手机号"); } @Override public void loadDataError() { ToastUtil.show(this, "无网络,无缓存"); } @Override protected void onDestroy() { super.onDestroy(); mCallPresenterImpl.onDestroy(); } }
网络封装
public class ZHttp { private String mUrl; private Map<String, String> mParam; private HttpResponse mHttpResponse; private OkHttpClient mHttpClient = new OkHttpClient(); private Handler mHandler = new Handler(Looper.getMainLooper()); public interface HttpResponse { void onSuccess(String result); void onFail(String error); } public ZHttp(HttpResponse httpResponse) { mHttpResponse = httpResponse; } public void sendPostHttp(String url, Map<String, String> param) { sendHttp(url, param, true); } public void sendGetHttp(String url, Map<String, String> param) { sendHttp(url, param, false); } private void sendHttp(String url, Map<String, String> param, boolean isPost) { mUrl = url; mParam = param; //获取网络数据 getData(isPost); } /** * 获取网络数据 * * @param isPost */ private void getData(boolean isPost) { //创建request请求 final Request request = createRequest(isPost); mHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { if (mHttpResponse != null) { mHandler.post(new Runnable() { @Override public void run() { mHttpResponse.onFail("请求错误"); } }); } } @Override public void onResponse(Call call, final Response response) throws IOException { if (mHttpResponse == null) { return; } mHandler.post(new Runnable() { @Override public void run() { if (!response.isSuccessful()) { mHttpResponse.onFail("请求失败:code" + response); } else { try { mHttpResponse.onSuccess(response.body().string()); } catch (IOException e) { e.printStackTrace(); } } } }); } }); } /** * @param isPost * @return */ private Request createRequest(boolean isPost) { Request request; if (isPost) { MultipartBody.Builder builder = new MultipartBody.Builder(); builder.setType(MultipartBody.FORM); //遍历map请求参数 Iterator<Map.Entry<String, String>> iterator = mParam.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, String> entry = iterator.next(); builder.addFormDataPart(entry.getKey(), entry.getValue()); } request = new Request.Builder().url(mUrl).post(builder.build()).build(); } else { String urlStr = mUrl + "?" + MapParamToString(mParam); request = new Request.Builder().url(urlStr).build(); } return request; } /** * @param param * @return */ private String MapParamToString(Map<String, String> param) { StringBuilder sb = new StringBuilder(); Iterator<Map.Entry<String, String>> iterator = mParam.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, String> entry = iterator.next(); sb.append(entry.getKey() + "=" + entry.getValue() + "&"); } String str = sb.toString().substring(0, sb.length() - 1); return str; } }
网络封装,连接网络获取数据,并写缓存
/** * 作者:张风捷特烈 * 时间:2018/3/29:10:21 * 邮箱:1981462002@qq.com * 说明:网络封装,连接网络获取数据,并写缓存 */ public abstract class GetDataWithCache { private CacheStrategy mCacheStrategy; private String mUrl; private Map<String, String> mParam; public GetDataWithCache(String url, Map<String, String> param, CacheStrategy cacheStrategy) { mCacheStrategy = cacheStrategy; mUrl = url; mParam = param; String cache = new CacheWorker(mCacheStrategy).getCache(mUrl);//读缓存 if (!TextUtils.isEmpty(cache)) {//如果有缓存 success(cache);//解析数据抽象方法 } getDataFromService();//连接网络获取数据,并写缓存 } /** * 从网络获取数据 */ private void getDataFromService() { new ZHttp(new ZHttp.HttpResponse() { @Override public void onSuccess(String response) { if (response != null) { success(response); } mCacheStrategy.setCache(mUrl, response, 10);//写缓存 } @Override public void onFail(String error) { if (mCacheStrategy.getCache(mUrl) != null) { success(mCacheStrategy.getCache(mUrl)); } else { error(error); } } }).sendGetHttp(mUrl, mParam); } public abstract void success(String response); public abstract void error(String error); }

这是我第一次接触MVP模式,如有不恰,欢迎指正


后记、

1.声明:

[1]本文由张风捷特烈原创,转载请注明 [2]欢迎广大编程爱好者共同交流 [3]个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正 [4]你的喜欢与支持将是我最大的动力

2.连接传送门:

更多安卓技术欢迎访问:安卓技术栈 我的github地址:欢迎star 简书首发,腾讯云+社区同步更新张风捷特烈个人网站,编程笔记请访问:http://www.toly1994.com

3.联系我

QQ:1981462002 邮箱:1981462002@qq.com 微信:zdl1994328

4.欢迎关注我的微信公众号,最新精彩文章,及时送达:
公众号.jpg

转载于:https://www.cnblogs.com/toly-top/p/9781910.html

最新回复(0)