在我看来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
方便代码的维护和单元测试。
以下主要展示的功能和框架有:
- MVP架构+基类+Volley封装
- 底部标签与Fragment的联动
- arguments动态传值
- 接口回调
- js交互,有参无参调用,弹框
- 自定义全局异常捕获
- base封装Activity和Fragment
第一步:添加需要的依赖和权限创建App上下文管理类,创建全局异常捕获类
在build.gradle下加依赖
implementation 'com.google.code.gson:gson:2.8.5'
//volley请求框架
implementation 'com.android.volley:volley:1.1.1'
//recycelrview,列表控件,和listview差不多,升级版
implementation 'androidx.recyclerview:recyclerview:1.1.0'
//glidee
implementation("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;
@Override
public void onCreate() {
super.onCreate();
//设置全局异常类,先创建在设置
final MyCanshHandle myCanshHandle = new MyCanshHandle();
Thread.setDefaultUncaughtExceptionHandler(myCanshHandle);
context=getApplicationContext();
}
public static Context getContext() {
return context;
}
}
全局异常捕获类MyCanshHandle
public class MyCanshHandle implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(@NonNull Thread thread, @NonNull Throwable throwable) {
Log.e("xx",throwable.getMessage());
}
}
第二步: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) {
this.code = 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":"http://172.17.8.100/images/small/commodity/xbsd/dnb/3/1.jpg","price":89,"saleNum":0},{"commodityId":188,"commodityName":"赫登尔(herder)双肩包男时尚旅行背包学生书包电脑包大容量潮流男包0902A","masterPic":"http://172.17.8.100/images/small/commodity/xbsd/sjb/5/1.jpg","price":169,"saleNum":0},{"commodityId":118,"commodityName":" 新款 iPad 128G WIFI 版 平板电脑","masterPic":"http://172.17.8.100/images/small/commodity/sjsm/yyyl/5/1.jpg","price":2988,"saleNum":0},{"commodityId":184,"commodityName":"瑞士军刀双肩包男士背包新款大容量休闲商务旅行电脑包学生书包 USb充电包","masterPic":"http://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":"http://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) {
this.message = 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) {
this.result = result;
}
public static class ResultBean {
/**
* commodityId : 172
* commodityName : 艾奔AspenSpor新款大容量男士双肩包学生书包防盗电脑包充电旅行背包 黑色_标准版
* masterPic : http://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) {
this.commodityId = commodityId;
}
public String getCommodityName() {
return commodityName;
}
public void setCommodityName(String commodityName) {
this.commodityName = 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();
}
//绑定view
public 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(){
return weakReference.get();
}
}
第三步:封装BaseActivity和BaseFragment类
BaseActivity
public abstract class BaseActivity<P extends BasePresenter> extends AppCompatActivity implements IBaseView {
public P presenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layoutId());
presenter=initPresenter();
//绑定view
if (presenter!=null){
presenter.attch(this);
}
initView();
initData();
}
//让子类创建
protected abstract P initPresenter();
protected abstract void initData();
protected abstract void initView();
protected abstract int layoutId();
//解决内存泄漏
@Override
protected void onDestroy() {
super.onDestroy();
if (presenter!=null) {
presenter.deach();
}
}
}
BaseFragment
public abstract class BaseFragment<P extends BasePresenter> extends Fragment implements IBaseView {
public P presenter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View inflate = View.inflate(getActivity(), layoutId(), null);
presenter=initPresenter();
//绑定view
if (presenter!=null){
presenter.attch(this);
}
initView(inflate);
return inflate;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initData();
}
protected abstract void initData();
protected abstract void initView(View inflate);
protected abstract P initPresenter();
protected abstract int layoutId();
//解决内存泄漏
@Override
public void onDestroy() {
super.onDestroy();
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(){
requestQueue=Volley.newRequestQueue(App.getContext());
}
public void doGet(String url, final VolleyCallBack volleyCallBack){
final StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
volleyCallBack.success(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
volleyCallBack.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 {
@Override
public void getFlow(String url, final ImodelCallBack imodelCallBack) {
VolleyUtlis.getInstance().doGet(url, new VolleyUtlis.VolleyCallBack() {
@Override
public void success(String json) {
final FlowEntity flowEntity = new Gson().fromJson(json, FlowEntity.class);
imodelCallBack.success(flowEntity);
}
@Override
public void error(Throwable throwable) {
imodelCallBack.error(throwable);
}
});
}
@Override
public void getProduct(String url, final ImodelCallBack imodelCallBack) {
VolleyUtlis.getInstance().doGet(url, new VolleyUtlis.VolleyCallBack() {
@Override
public void success(String json) {
final ProductEntivity productEntivity = new Gson().fromJson(json, ProductEntivity.class);
imodelCallBack.success(productEntivity);
}
@Override
public void error(Throwable throwable) {
imodelCallBack.error(throwable);
}
});
}
}
v层可以不写,因为activivty,adapter,有关数据的都可以在v层
p层
public class ShouyePresenter extends BasePresenter<ShouyeModel, ShouyeContract.IView> implements ShouyeContract.IPresenter {
@Override
public void getFlow(String url) {
model.getFlow(url, new ShouyeContract.IModel.ImodelCallBack() {
@Override
public void success(Object data) {
getview().success(data);
}
@Override
public void error(Throwable throwable) {
getview().error(throwable);
}
});
}
@Override
public void getProduct(String url) {
model.getProduct(url, new ShouyeContract.IModel.ImodelCallBack() {
@Override
public void success(Object data) {
getview().success(data);
}
@Override
public void error(Throwable throwable) {
getview().error(throwable);
}
});
}
@Override
protected ShouyeModel initModel() {
return new ShouyeModel();
}
}
第五步底部导航 加动态传值setArguments
布局xml
<?xml version="1.0" encoding="utf-8"?>
<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=".view.activity.MainActivity">
<androidx.viewpager.widget.ViewPager
android:id="@+id/vp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<RadioGroup
android:id="@+id/rg"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioButton
android: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"/>
<RadioButton
android: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"/>
<RadioButton
android: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;
@Override
protected 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.check(rg.getChildAt(0).getId());
vp.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@NonNull
@Override
public Fragment getItem(int position) {
return list.get(position);
}
@Override
public int getCount() {
return list.size();
}
});
vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
rg.check(rg.getChildAt(position).getId());
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
rg.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public 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;
}
}
});
}
@Override
protected void initView() {
vp = findViewById(R.id.vp);
rg = findViewById(R.id.rg);
}
@Override
protected BasePresenter initPresenter() {
return null;
}
@Override
protected int layoutId() {
return R.layout.activity_main;
}
}
OtherFragment
接收传值并设置
public class OtherFragment extends Fragment {
private TextView tt;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View
inflate = View.inflate(getContext(), R.layout.fragment_other, null);
final TextView tt = inflate.findViewById(R.id.tt);
//接收setarguments传来的值
final Bundle arguments = getArguments();
final String name = arguments.getString("name");
tt.setText(name);
return inflate;
}
}
布局
fragment_other.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.fragment.OtherFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android: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);
}
@Override
protected 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添加进去的,所以要让系统测量一下每个子控件的大小
childAt.measure(0,0);
final int measuredWidth = childAt.getMeasuredWidth();//view的宽
final int measuredHeight = childAt.getMeasuredHeight();//view的高
//屏幕宽度,px像素单位
final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
final int widthPixels = displayMetrics.widthPixels;
//累加right
right=left+measuredWidth;
if (right>widthPixels){
//折行后第一个控件距离左边距离为0
left=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) {
//动态创建textview
final 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() {
@Override
public void onClick(View view) {
flowonClickListenter.onClick(textView.getText().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;
@Override
protected void initData() {
String url = "http://blog.zhaoliang5156.cn/baweiapi/"+ URLEncoder.encode("手机");
presenter.getFlow(url);
}
@Override
protected void initView(View inflate) {
flow_layout = inflate.findViewById(R.id.flow_layout);
btn_search = inflate.findViewById(R.id.btn_search);
et_keyword = inflate.findViewById(R.id.et_keyword);
rv = inflate.findViewById(R.id.rv);
rv.setLayoutManager(new GridLayoutManager(getActivity(),2));
flow_layout.setFlowonClickListenter(new FlowLayout.FlowonClickListenter() {
@Override
public void onClick(String name) {
String url = "http://172.17.8.100/small/commodity/v1/findCommodityByKeyword?keyword="+URLEncoder.encode(name)+"&count=10&page=1";
presenter.getProduct(url);
}
});
btn_search.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
flow_layout.addTextView(et_keyword.getText().toString());
String url = "http://172.17.8.100/small/commodity/v1/findCommodityByKeyword?keyword="+URLEncoder.encode(et_keyword.getText().toString())+"&count=10&page=1";
presenter.getProduct(url);
}
});
}
@Override
protected ShouyePresenter initPresenter() {
return new ShouyePresenter();
}
@Override
protected int layoutId() {
return R.layout.fragment_shouye;
}
@Override
public 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() {
@Override
public void onclick(String name) {
Toast.makeText(getContext(), ""+name, Toast.LENGTH_SHORT).show();
final Intent intent = new Intent(getContext(), SecondActivity.class);
startActivity(intent);
}
});
}
}
@Override
public void error(Throwable throwable) {
}
}
布局
fragment_shouye.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".view.fragment.ShouyeFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" android:orientation="horizontal">
<EditText
android:id="@+id/et_keyword"
android:hint="请输入搜索关键词"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn_search"
android:text="搜索"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<com.bawei.yuekao.view.widgets.FlowLayout
android:id="@+id/flow_layout"
android:layout_width="match_parent"
android:layout_height="300dp">
</com.bawei.yuekao.view.widgets.FlowLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.recyclerview.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) {
this.context = context;
this.list = list;
}
@NonNull
@Override
public 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;
}
@Override
public void onBindViewHolder(@NonNull MyViewHorlder holder, final int position) {
holder.name.setText(list.get(position).getCommodityName());
Glide.with(context)
.load(list.get(position).getMasterPic())
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.ic_launcher)
.circleCrop()
.into(holder.iv);
//点击事件,通过下面声明的接口,发送商品标题
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
rvItemlistenter.onclick(list.get(position).getCommodityName());
}
});
}
@Override
public 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_item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv"
android:layout_width="80dp"
android:layout_height="80dp"/>
<TextView
android: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){
document.getElementsByClassName("name").innerHTML=zhy;
alert(zhy);
}
</script>
</head>
<body>
<p>
</p>
<p>我是一个段落</p>
<p class="name">我是从Android过来</p>
<button onclick="window.aaa.getZhy('电脑')">有参调用android</button>
<button onclick="window.aaa.getDhx()">无参调用android</button>
</body>
</html>
activity
随便创建一个类交互
public class Zhy {
@JavascriptInterface//必须写
public void getZhy(String name){
Toast.makeText(App.getContext(), ""+name, Toast.LENGTH_SHORT).show();
}
@JavascriptInterface
public void getDhx(){
Toast.makeText(App.getContext(), "这是无参", Toast.LENGTH_SHORT).show();
}
}
SecondActivity 实现功能
public class SecondActivity extends BaseActivity {
private Button b1;
private WebView web;
@Override
protected BasePresenter initPresenter() {
return null;
}
@Override
protected void initData() {
}
@Override
protected void initView() {
b1 = findViewById(R.id.b1);
web = findViewById(R.id.web);
web.getSettings().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() {
@Override
public void onClick(View view) {
web.loadUrl("javascript:dhx()");
}
});
}
@Override
protected int layoutId() {
return R.layout.activity_second;
}
}
布局
activity_second.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.SecondActivity">
<WebView
android:id="@+id/web"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</WebView>
<Button
android: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>
来源:CSDN
作者:huiyangyangyou
链接:https://blog.csdn.net/huiyangyangyou/article/details/103655936