在我看来mvp框架其实是mvc框架变种产品。讲原本的activity/fragment的层次划分成present层和view层。m还是原来的实体层用来组装数据,p层则用来隔离view层,被称为中介层,v层还是view层主要用来展示数据的层。如下图所示:
有了present层之后呢?view层就专心在activity/fragment里面主要去处理视图层和维护自己的生命周期,将业务逻辑委托给present层,present层作为实体层和视图层的中介。实体层和视图层不直接进行交互,而是通过委托给persent层进行交互,这样做的好处是:
分离了视图逻辑和业务逻辑,降低了耦合
Activity只处理生命周期的任务,代码变得更加简洁
视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中去,提高代码的可阅读性
Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
把业务逻辑抽到Presenter中去,避免后台线程引用着Activity导致Activity的资源无法被系统回收从而引起内存泄露和OOM
方便代码的维护和单元测试。
以下主要展示的功能和框架有:
第一步:添加需要的依赖和权限创建App上下文管理类,创建全局异常捕获类
在adle下加依赖
implementation le.code.gson:gson:2.8.5'//volley请求框架implementation 'com.android.volley:volley:1.1.1'//recycelrview,列表控件,和listview差不多,升级版implementation lerview:recyclerview:1.1.0'//glideeimplementation("com.github.bumptech.glide:glide:4.10.0") {exclude group: "com.android.support"}
在清单文件加联网权限
<uses-permission android:name="android.permission.INTERNET" />
App
public class App extends Application {private static Context context;@Overridepublic void onCreate() {Create();//设置全局异常类,先创建在设置final MyCanshHandle myCanshHandle = new MyCanshHandle();Thread.setDefaultUncaughtExceptionHandler(myCanshHandle);context=getApplicationContext();}public static Context getContext() {return context;}
}
全局异常捕获类MyCanshHandle
public class MyCanshHandle implements Thread.UncaughtExceptionHandler {@Overridepublic void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {Log.e("xx",Message());}
}
第二步:base封装mvp框架 创建Entity类
Entity类
FlowEntity
public class FlowEntity {/*** msg : 响应成功* code : 200* tags : ["手机壁纸","手机app","手机cpu天梯图","手机号码测吉凶","手机新浪网","手机号码测吉凶(超准)","手机电影","手机在线","手机排名","小米手机"]*/private String msg;private int code;private List<String> tags;public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public int getCode() {return code;}public void setCode(int code) {de = code;}public List<String> getTags() {return tags;}public void setTags(List<String> tags) {this.tags = tags;}
ProductEntivity
public class ProductEntivity {/*** result : [{"commodityId":172,"commodityName":"艾奔AspenSpor新款大容量男士双肩包学生书包防盗电脑包充电旅行背包 黑色_标准版","masterPic":"172.17.8.100/images/small/commodity/xbsd/dnb/3/1.jpg","price":89,"saleNum":0},{"commodityId":188,"commodityName":"赫登尔(herder)双肩包男时尚旅行背包学生书包电脑包大容量潮流男包0902A","masterPic":"172.17.8.100/images/small/commodity/xbsd/sjb/5/1.jpg","price":169,"saleNum":0},{"commodityId":118,"commodityName":" 新款 iPad 128G WIFI 版 平板电脑","masterPic":"172.17.8.100/images/small/commodity/sjsm/yyyl/5/1.jpg","price":2988,"saleNum":0},{"commodityId":184,"commodityName":"瑞士军刀双肩包男士背包新款大容量休闲商务旅行电脑包学生书包 USb充电包","masterPic":"172.17.8.100/images/small/commodity/xbsd/sjb/1/1.jpg","price":99,"saleNum":0},{"commodityId":174,"commodityName":"帆布派 Canvas artisan 苹果笔记本电脑包 女14/15.6寸惠普电脑包联想1 PT38-1酒红色 14寸可用","masterPic":"172.17.8.100/images/small/commodity/xbsd/dnb/5/1.jpg","price":229,"saleNum":0}]* message : 查询成功* status : 0000*/private String message;private String status;private List<ResultBean> result;public String getMessage() {return message;}public void setMessage(String message) {ssage = message;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}public List<ResultBean> getResult() {return result;}public void setResult(List<ResultBean> result) {sult = result;}public static class ResultBean {/*** commodityId : 172* commodityName : 艾奔AspenSpor新款大容量男士双肩包学生书包防盗电脑包充电旅行背包 黑色_标准版* masterPic : 172.17.8.100/images/small/commodity/xbsd/dnb/3/1.jpg* price : 89* saleNum : 0*/private int commodityId;private String commodityName;private String masterPic;private int price;private int saleNum;public int getCommodityId() {return commodityId;}public void setCommodityId(int commodityId) {thismodityId = commodityId;}public String getCommodityName() {return commodityName;}public void setCommodityName(String commodityName) {thismodityName = commodityName;}public String getMasterPic() {return masterPic;}public void setMasterPic(String masterPic) {this.masterPic = masterPic;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public int getSaleNum() {return saleNum;}public void setSaleNum(int saleNum) {this.saleNum = saleNum;}}
}
m层:
暂时没用到所以只创建一个接口即可
public interface IBaseModel {
}
v层
也暂时没用到所以只创建一个接口即可
public interface IBaseView {
}
p层
public abstract class BasePresenter<M extends IBaseModel,V extends IBaseView> {public M model;public WeakReference<V> weakReference;public BasePresenter(){model=initModel();}//绑定viewpublic void attch(V v){weakReference=new WeakReference<>(v);}protected abstract M initModel();//解绑view,解决内存泄露public void deach(){if (weakReference!=null){weakReference.clear();weakReference=null;}}public V getview(){();}
}
第三步:封装BaseActivity和BaseFragment类
BaseActivity
public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements IBaseView {public P presenter;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {Create(savedInstanceState);setContentView(layoutId());presenter=initPresenter();//绑定viewif (presenter!=null){presenter.attch(this);}initView();initData();}//让子类创建protected abstract P initPresenter();protected abstract void initData();protected abstract void initView();protected abstract int layoutId();//解决内存泄漏@Overrideprotected void onDestroy() {Destroy();if (presenter!=null) {presenter.deach();}}
}
BaseFragment
public abstract class BaseFragment<P extends BasePresenter> extends Fragment implements IBaseView {public P presenter;@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {final View inflate = View.inflate(getActivity(), layoutId(), null);presenter=initPresenter();//绑定viewif (presenter!=null){presenter.attch(this);}initView(inflate);return inflate;}@Overridepublic void onActivityCreated(@Nullable Bundle savedInstanceState) {ActivityCreated(savedInstanceState);initData();}protected abstract void initData();protected abstract void initView(View inflate);protected abstract P initPresenter();protected abstract int layoutId();//解决内存泄漏@Overridepublic void onDestroy() {Destroy();if (presenter!=null){presenter.deach();}}
}
第四部,单例模式封装网络工具类Volley,mvp分包,创建统一契约类管理
网络工具类VolleyUtlis
public class VolleyUtlis {private RequestQueue requestQueue;//volley请求队列private static VolleyUtlis volleyUtlis;//双重检验锁的单例模式---企业中,让你手写单例模式//暴露公共方法,创建私有对象,供外部调用,双重:两次判断,检验锁:同步锁public static VolleyUtlis getInstance() {if (volleyUtlis==null){synchronized (Volley.class){volleyUtlis=new VolleyUtlis();}}return volleyUtlis;}//构造方法私有,防止外界(调用者)new 出新的对象private VolleyUtlis(){requestQueueContext());}public void doGet(String url, final VolleyCallBack volleyCallBack){final StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, url, new Response.Listener<String>() {@Overridepublic void onResponse(String response) {volleyCallBack.success(response);}}, new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {(error);}});requestQueue.add(stringRequest);}public interface VolleyCallBack{void success(String json);void error(Throwable throwable);}
}
契约类ShouyeContract
public interface ShouyeContract{interface IModel extends IBaseModel {void getFlow(String url,ImodelCallBack imodelCallBack);void getProduct(String url,ImodelCallBack imodelCallBack);interface ImodelCallBack{void success(Object data);void error(Throwable throwable);}}interface IView extends IBaseView {void success(Object data);void error(Throwable throwable);}interface IPresenter{void getFlow(String url);void getProduct(String url);}
}
M层 ShouyeModel
public class ShouyeModel implements ShouyeContract.IModel {@Overridepublic void getFlow(String url, final ImodelCallBack imodelCallBack) {Instance().doGet(url, new VolleyUtlis.VolleyCallBack() {@Overridepublic void success(String json) {final FlowEntity flowEntity = new Gson().fromJson(json, FlowEntity.class);imodelCallBack.success(flowEntity);}@Overridepublic void error(Throwable throwable) {(throwable);}});}@Overridepublic void getProduct(String url, final ImodelCallBack imodelCallBack) {Instance().doGet(url, new VolleyUtlis.VolleyCallBack() {@Overridepublic void success(String json) {final ProductEntivity productEntivity = new Gson().fromJson(json, ProductEntivity.class);imodelCallBack.success(productEntivity);}@Overridepublic void error(Throwable throwable) {(throwable);}});}
}
v层可以不写,因为activivty,adapter,有关数据的都可以在v层
p层
public class ShouyePresenter extends BasePresenter<ShouyeModel, ShouyeContract.IView> implements ShouyeContract.IPresenter {@Overridepublic void getFlow(String url) {Flow(url, new ShouyeContract.IModel.ImodelCallBack() {@Overridepublic void success(Object data) {getview().success(data);}@Overridepublic void error(Throwable throwable) {getview().error(throwable);}});}@Overridepublic void getProduct(String url) {Product(url, new ShouyeContract.IModel.ImodelCallBack() {@Overridepublic void success(Object data) {getview().success(data);}@Overridepublic void error(Throwable throwable) {getview().error(throwable);}});}@Overrideprotected ShouyeModel initModel() {return new ShouyeModel();}
}
第五步底部导航 加动态传值setArguments
布局xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""xmlns:app=""xmlns:tools=""android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".view.activity.MainActivity"><androidx.viewpager.widget.ViewPagerandroid:id="@+id/vp"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"/><RadioGroupandroid:id="@+id/rg"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"><RadioButtonandroid:padding="10dp"android:text="首页"android:gravity="center"android:id="@+id/r1"android:layout_width="0dp"android:layout_weight="1"android:background="@drawable/select"android:button="@null"android:layout_height="wrap_content"/><RadioButtonandroid:padding="10dp"android:gravity="center"android:text="新闻"android:button="@null"android:id="@+id/r2"android:layout_width="0dp"android:layout_weight="1"android:background="@drawable/select"android:layout_height="wrap_content"/><RadioButtonandroid:padding="10dp"android:button="@null"android:gravity="center"android:text="我的"android:id="@+id/r3"android:layout_weight="1"android:background="@drawable/select"android:layout_width="0dp"android:layout_height="wrap_content"/></RadioGroup>
</LinearLayout>
然后创建两个fragment
一个首页fragment,一个共用fragment
activity
public class MainActivity extends BaseActivity {private ViewPager vp;private RadioGroup rg;@Overrideprotected void initData() {final List<Fragment> list=new ArrayList<>();final ShouyeFragment shouyeFragment = new ShouyeFragment();list.add(shouyeFragment);final OtherFragment otherFragment = new OtherFragment();//setArguments传值final Bundle bundle = new Bundle();bundle.putString("name","新闻");otherFragment.setArguments(bundle);list.add(otherFragment);//setArguments传值final OtherFragment otherFragment1 = new OtherFragment();final Bundle bundle1 = new Bundle();bundle1.putString("name","我的");otherFragment1.setArguments(bundle1);list.add(otherFragment1);rg.ChildAt(0).getId());vp.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {@NonNull@Overridepublic Fragment getItem(int position) {(position);}@Overridepublic int getCount() {return list.size();}});vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}@Overridepublic void onPageSelected(int position) {rg.ChildAt(position).getId());}@Overridepublic void onPageScrollStateChanged(int state) {}});rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(RadioGroup radioGroup, int i) {switch (i){case R.id.r1:vp.setCurrentItem(0);break;case R.id.r2:vp.setCurrentItem(1);break;case R.id.r3:vp.setCurrentItem(2);break;}}});}@Overrideprotected void initView() {vp = findViewById(R.id.vp);rg = findViewById();}@Overrideprotected BasePresenter initPresenter() {return null;}@Overrideprotected int layoutId() {return R.layout.activity_main;}
}
OtherFragment
接收传值并设置
public class OtherFragment extends Fragment {private TextView tt;@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {final Viewinflate = View.inflate(getContext(), R.layout.fragment_other, null);final TextView tt = inflate.findViewById();//接收setarguments传来的值final Bundle arguments = getArguments();final String name = String("name");tt.setText(name);return inflate;}
}
布局
l
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android=""xmlns:tools=""android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".view.fragment.OtherFragment"><!-- TODO: Update blank fragment layout --><TextViewandroid:id="@+id/tt"android:layout_width="match_parent"android:layout_height="match_parent"android:text="@string/hello_blank_fragment" /></FrameLayout>
第六部自定义view显示流式布局和拓展功能,点击搜索框显示相对应的RecyclerView列表,点击列表
FlowLayout
public class FlowLayout extends ViewGroup {public FlowLayout(Context context) {super(context);}public FlowLayout(Context context, AttributeSet attrs) {super(context, attrs);}public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onLayout(boolean b, int i, int i1, int i2, int i3) {int left=0;int top=0;int right=0;int bottom=0;//得到子控件的数量final int childCount = getChildCount();if (childCount>0){//循环每一个子控件for (int j = 0; j < childCount; j++) {final View childAt = getChildAt(j);//子view添加进去的,所以要让系统测量一下每个子控件的大小asure(0,0);final int measuredWidth = MeasuredWidth();//view的宽final int measuredHeight = MeasuredHeight();//view的高//屏幕宽度,px像素单位final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();final int widthPixels = displayMetrics.widthPixels;//累加rightright=left+measuredWidth;if (right>widthPixels){//折行后第一个控件距离左边距离为0left=0;right=left+measuredWidth;top=bottom+30;}bottom=top+measuredHeight;//就是对view进行摆放childAt.layout(left,top,right,bottom);left=left+measuredWidth+30;}}}//显示流式布局,加入数据public void add(List<String> tags){for (String tag : tags) {//动态创建textviewfinal TextView textView = new TextView(getContext());//设置文本textView.setText(tag);//添加子控件到流式布局中addView(textView);}}//将输入的数据单个添加到流式布局中public void addTextView(String name){final TextView textView = new TextView(getContext());textView.setText(name);addView(textView);//最后,设置回调接口准备过去的数据textView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View view) {Text().toString());}});}//第二步,声明接口private FlowonClickListenter flowonClickListenter;//第三部public void setFlowonClickListenter(FlowonClickListenter flowonClickListenter) {this.flowonClickListenter = flowonClickListenter;}//第一步创建回调接口public interface FlowonClickListenter{void onClick(String name);}}
然后在首页fragment显示
public class ShouyeFragment extends BaseFragment<ShouyePresenter> implements ShouyeContract.IView {private FlowLayout flow_layout;private Button btn_search;private EditText et_keyword;private RecyclerView rv;@Overrideprotected void initData() {String url = "/"+ de("手机");Flow(url);}@Overrideprotected void initView(View inflate) {flow_layout = inflate.findViewById(R.id.flow_layout);btn_search = inflate.findViewById(R.id.btn_search);et_keyword = inflate.findViewById(_keyword);rv = inflate.findViewById(R.id.rv);rv.setLayoutManager(new GridLayoutManager(getActivity(),2));flow_layout.setFlowonClickListenter(new FlowLayout.FlowonClickListenter() {@Overridepublic void onClick(String name) {String url = "172.17.8.100/small/commodity/v1/findCommodityByKeyword?keyword="de(name)+"&count=10&page=1";Product(url);}});btn_search.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {flow_layout.addTextView(Text().toString());String url = "172.17.8.100/small/commodity/v1/findCommodityByKeyword?keyword="de(Text().toString())+"&count=10&page=1";Product(url);}});}@Overrideprotected ShouyePresenter initPresenter() {return new ShouyePresenter();}@Overrideprotected int layoutId() {return R.layout.fragment_shouye;}@Overridepublic void success(Object data) {if (data instanceof FlowEntity){final List<String> tags = ((FlowEntity) data).getTags();flow_layout.add(tags);}else if (data instanceof ProductEntivity){final List<ProductEntivity.ResultBean> result = ((ProductEntivity) data).getResult();final ProductAdapter productAdapter = new ProductAdapter(getActivity(), result);rv.setAdapter(productAdapter);productAdapter.setRvItemlistenter(new ProductAdapter.RvItemlistenter() {@Overridepublic void onclick(String name) {Toast.makeText(getContext(), ""+name, Toast.LENGTH_SHORT).show();final Intent intent = new Intent(getContext(), SecondActivity.class);startActivity(intent);}});}}@Overridepublic void error(Throwable throwable) {}
}
布局
l
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""xmlns:tools=""android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".view.fragment.ShouyeFragment"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content" android:orientation="horizontal"><EditTextandroid:id="@+id/et_keyword"android:hint="请输入搜索关键词"android:layout_width="wrap_content"android:layout_height="wrap_content"/><Buttonandroid:id="@+id/btn_search"android:text="搜索"android:layout_width="wrap_content"android:layout_height="wrap_content"/></LinearLayout><com.bawei.yuekao.view.widgets.FlowLayoutandroid:id="@+id/flow_layout"android:layout_width="match_parent"android:layout_height="300dp"></com.bawei.yuekao.view.widgets.FlowLayout>&lerview.widget.RecyclerViewandroid:id="@+id/rv"android:layout_width="match_parent"android:layout_height="wrap_content"></lerview.widget.RecyclerView></LinearLayout>
RecyclerView适配器
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.MyViewHorlder> {private Context context;private List<ProductEntivity.ResultBean> list;public ProductAdapter(Context context, List<ProductEntivity.ResultBean> list) {t = context;this.list = list;}@NonNull@Overridepublic MyViewHorlder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {final View inflate = View.inflate(context, R.layout.product_item_layout, null);final MyViewHorlder myViewHorlder = new MyViewHorlder(inflate);return myViewHorlder;}@Overridepublic void onBindViewHolder(@NonNull MyViewHorlder holder, final int position) {holder.name.(position).getCommodityName());Glide.with(context).(position).getMasterPic()).placeholder(R.mipmap.ic_launcher).error(R.mipmap.ic_launcher).circleCrop().into(holder.iv);//点击事件,通过下面声明的接口,发送商品标题holder.itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {(position).getCommodityName());}});}@Overridepublic int getItemCount() {return list.size();}class MyViewHorlder extends RecyclerView.ViewHolder {private final ImageView iv;private final TextView name;public MyViewHorlder(@NonNull View itemView) {super(itemView);iv = itemView.findViewById(R.id.iv);name = itemView.findViewById(R.id.name);}}private RvItemlistenter rvItemlistenter;public void setRvItemlistenter(RvItemlistenter rvItemlistenter) {this.rvItemlistenter = rvItemlistenter;}public interface RvItemlistenter{void onclick(String name);}}
布局
product_l
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android=""android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:id="@+id/iv"android:layout_width="80dp"android:layout_height="80dp"/><TextViewandroid:id="@+id/name"android:layout_width="wrap_content"android:layout_height="wrap_content"/>
</LinearLayout>
第7步 js交互,有参无参调用,弹框
在main里创建一个assets包
创建一个html
<html><head><meta charset="UTF-8"><script type="text/javascript">function dhx(zhy){ElementsByClassName("name").innerHTML=zhy;alert(zhy);}</script>
</head><body><p></p><p>我是一个段落</p>
<p class="name">我是从Android过来</p>
<button onclick="Zhy('电脑')">有参调用android</button>
<button onclick="Dhx()">无参调用android</button></body>
</html>
activity
随便创建一个类交互
public class Zhy {@JavascriptInterface//必须写public void getZhy(String name){Toast.Context(), ""+name, Toast.LENGTH_SHORT).show();}@JavascriptInterfacepublic void getDhx(){Toast.Context(), "这是无参", Toast.LENGTH_SHORT).show();}
}
SecondActivity 实现功能
public class SecondActivity extends BaseActivity {private Button b1;private WebView web;@Overrideprotected BasePresenter initPresenter() {return null;}@Overrideprotected void initData() {}@Overrideprotected void initView() {b1 = findViewById(R.id.b1);web = findViewById(R.id.web);Settings().setJavaScriptEnabled(true);web.setWebChromeClient(new WebChromeClient());final Zhy zhy = new Zhy();web.addJavascriptInterface(zhy,"aaa");web.loadUrl("file:///android_asset/hello.html");b1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {web.loadUrl("javascript:dhx()");}});}@Overrideprotected int layoutId() {return R.layout.activity_second;}
}
布局
l
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android=""xmlns:app=""xmlns:tools=""android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".view.activity.SecondActivity"><WebViewandroid:id="@+id/web"android:layout_width="match_parent"android:layout_height="wrap_content"></WebView><Buttonandroid:id="@+id/b1"android:layout_alignParentBottom="true"android:layout_alignParentRight="true"android:text="去调用js的空参"android:layout_width="wrap_content"android:layout_height="wrap_content"></Button></RelativeLayout>
本文发布于:2024-01-31 05:34:03,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170665044425923.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |