当前位置: 首页 > news >正文

能够做代理的网站有哪些问题免费商标图案设计logo

能够做代理的网站有哪些问题,免费商标图案设计logo,diy建站系统,数商云招聘前言 前面我们说过 ButterKnife 这个库#xff0c;这个库实现不仅实现了 View 的绑定#xff0c;而且还提供了大量的注解如 BindView、OnClick、OnLongClick 等来简化开发过程中事件绑定。而这些功能的实现是通过 APT 也就是注解处理器#xff0c;在编译期间生成 Java 代码…前言 前面我们说过 ButterKnife 这个库这个库实现不仅实现了 View 的绑定而且还提供了大量的注解如 BindView、OnClick、OnLongClick 等来简化开发过程中事件绑定。而这些功能的实现是通过 APT 也就是注解处理器在编译期间生成 Java 代码来实现的。 关于这一部分大家请看前面的这篇文章这篇文章将 ButterKnife 讲解的非常好可以跟着一步一步实现一个自己的简易版本 制作自己的 ButterKnife使用 AutoService 和 APT 注解处理器在编译期生成 Java 代码 不过这一次我们不再使用 APT而是利用注解和反射的巧妙结合在运行时进行事件和 View 的绑定让我们告别 setOnClickListener 这类的方法 。这里我们拿 OnClick 和 OnLongClick 这两个注解为例自己实现这两个注解的功能。 不过想要实现自己的绑定注解还是有一些前置条件的需要学习注解反射和动态代理这三个方面的知识此处推荐下面的三篇文章建议看完并对刚说的三个知识点有一定认识再来看本文。 由浅入深 带你了解 JAVA 注解Java Reflection 反射使用 完全指南代理模式与静态代理、动态代理的实现Proxy.newProxyInstance、InvocationHandler 这里插播一下我的公众号也是最近开始弄希望多多关注以后我会发更多的高质量内容 确定目标 首先我们确定要实现的是两个注解的功能OnClick 和 OnLongClick。在没有这两个注解时我们做事件绑定的代码如下 public class MainActivity extends AppCompatActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//为 id 为 button_1 的 View 设置 点击事件findViewById(R.id.button_1).setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this, 点击, Toast.LENGTH_SHORT).show();}});//为 id 为 button_2 的 View 设置 长按事件findViewById(R.id.button_2).setOnLongClickListener(new View.OnLongClickListener() {Overridepublic boolean onLongClick(View v) {Toast.makeText(MainActivity.this, 长按, Toast.LENGTH_LONG).show();return true;}});} }而有了这两个事件绑定注解时我们会将上面的代码改为下面这样这也是我们最终效果的代码 public class MainActivity extends AppCompatActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);InjectUtils.inject(this); //在此处处理此类中的时间绑定注解}OnClick({R.id.button_1}) //为 id 为 button_1 的 View 设置 点击事件public void click(View view) { //当 button_1 点击时将触发此函数Toast.makeText(this, 点击, Toast.LENGTH_SHORT).show();}OnLongClick({R.id.button_2}) //为 id 为 button_2 的 View 设置 长按事件public boolean longClick(View view) { 当 button_2 长按时将触发此函数Toast.makeText(this, 长按, Toast.LENGTH_LONG).show();return true;} }确定了目标之后我们就一步一步来实现这两个功能。这里可以看到有三个地方需要我们去实现 OnClick 注解OnLongClick 注解InjectUtils.inject(this) 代码 这三个只是我们现在看到的如果要实现这个功能要写的代码肯定只多不少。 实现 OnClick 和 OnLongClick 注解 我们先拿 OnClick 来举个例子正常情况下根据要求我们会写如下的注解 Target({ElementType.METHOD}) Retention(RetentionPolicy.RUNTIME) public interface OnClick {int[] value(); }这是没问题的Target 设置为 METHOD 表明了这个注解是放到方法上的RUNTIME 保证了我们能够在运行时拿到这个注解里面设置了 int[] 类型的方法使得其可以指定多个 View 的 ID。 到现在看似没什么问题但是这里还是有问题。想象一下后续我们会使用反射来进行 View 的事件绑定那么在事件的绑定时需要什么信息呢需要的信息有两个 事件绑定的方法例如 View.setOnClickListener() 这个方法设置的事件的类型例如 View.OnClickListener 这个类型 这里说需要者两个信息大家可能会一知半解那么先放在这里只知道需要这两个信息就行了。等看到后面自然就明白了。 现在知道需要这两个信息那么我们添加这两个信息不就可以了确实是这样的但是问题又来了这两个信息添加到哪里呢如果我们直接添加到 OnClick 这个注解的方法中就像这样 Target({ElementType.METHOD}) Retention(RetentionPolicy.RUNTIME) public interface OnClick {int[] value();String listenerSetter() default setOnClickListener;Class? listenerType() default View.OnClickListener.class; }也不是不行但是这样外层在用的时候还需要指定这两个参数。这会对使用方造成误解而且对于每一个注解这两个信息是固定的外面再指定是多余的即使用 default 设置默认值外边再重新指定这两个参数也是我们不想看到的。 那最好的办法是怎样的呢那就是注解多态也就是使用自定义元注解。此处我们为 OnClick 和 OnLongClick 自定义一个元注解 EventBase。 自定义元注解 EventBase 上面我们知道那两个额外的信息是跟注解相关的也就是说相同的注解这两个值是相同的这种情况自定义一个元注解然后来修饰这两个注解是最合适不过了。如下我自定义了一个 EventBase 的元注解这个注解只能放到注解上且两个属性值对应着上面的两个信息 Retention(RetentionPolicy.RUNTIME) Target(ElementType.ANNOTATION_TYPE) public interface EventBase {String listenerSetter(); //绑定事件的方法例如 setOnClickListenerClass? listenerType(); //绑定的事件的类型例如 View.OnClickListener.class }那么后面我们用这个注解来修改 OnClick 和 OnLongClick 注解。 最终的 OnClick 注解 Target({ElementType.METHOD}) Retention(RetentionPolicy.RUNTIME) EventBase(listenerSetter setOnClickListener, listenerType View.OnClickListener.class) public interface OnClick {int[] value(); }最终的 OnLongClick 注解 Target({ElementType.METHOD}) Retention(RetentionPolicy.RUNTIME) EventBase(listenerSetter setOnLongClickListener, listenerType View.OnLongClickListener.class) public interface OnLongClick {int[] value(); }注意这两个注解虽然都使用了 EventBase 来修改但是传递给 EventBase 的两个参数是不同的都是与自己这个事件相关的方法和参数类型。 现在这两个注解已经确定下来了接下来我们就要去实现 InjectUtils 这个类而且这个类也是实现这个功能的关键所在。 利用反射和动态代理绑定事件初期器 有人会问你这个绑定的功能为什么会起个名字叫 InjectUtils大家不要在意这个细节只要知道这个类里的方法是实现 setOnClickListener 这个方法的就行而且一般情况下是在 MainActivity.onCreate 方法中调用的。 在最开始我们确定了这个类里面有 InjectUtils.inject(this) 方法我们将会在 onCreate 中调用这个方法就像调用 ButterKnife.bind(this) 一样。那么怎么写这个方法呢我们一步一步来。 找到有 OnClick、OnLongClick 注解的函数 既然我么要处理带有绑定注解的函数那我们肯定就要找到有哪些函数被标记了自定义的 OnClick 和 OnLongClick 注解。 这一步分的代码很简单因为我们在 MainActivity.onCreate 方法中调用了 InjectUtils.inject(this)而这个 this 就表示需要进行注解解析的类通过它的 Class对象我们就能够找到哪些函数添加了需要处理的注解。 这部分的代码如下 public class InjectUtils {public static void inject(Object context) {Class? clazz context.getClass();Method[] methods clazz.getDeclaredMethods();for(Method method: methods) {Annotation[] annotations method.getAnnotations();for(Annotation annotation : annotations) {Class? extends Annotation annotationClass annotation.annotationType();EventBase eventBase annotationClass.getAnnotation(EventBase.class);//判断这个注解有没有被 EventBase 标记如果标记了那么就能获取到。是我们应该处理的注解if(eventBase null)continue;//走到这里就表示这个方法是被 OnClick 或 OnLongClick 标记过的应该处理绑定//TODO: binding}}} }这里主要有两个循环外层循环是对这个类的所有方法循环内层循环是对方法上的注解的循环。另外判断这个函数是否是事件处理的方法则是判断注解是否被 EventBase 注解标记如果被这个注解标记那么就是我们需要处理的方法了。 找到 View 并调用 setOnClickListener 接下来走到上面 TODO 的地方就是处理事件绑定。这里快到了全文的重点了我们慢慢来看。 后面我们要做的其实就是调用 View.setOnClickListener(new OnClickListener())那么用反射完成这个调用需要分几步呢很简单这就像要把大象装冰箱总共要分三步 首先要找到 View 对象再找到 setOnClickListener 方法通过反射 invoke 这个方法 是不是很简单下面就是代码了 try {Method valueMethod annotationClass.getMethod(value);int[] viewIds (int[]) valueMethod.invoke(annotation); //获取传递给 OnClick 的所有 View 的 IDif(viewIds null)continue;for(int viewId: viewIds) { // 每一个 View 都要调用 setOnClickListenerMethod findViewByIdMethod clazz.getMethod(findViewById, int.class);View view (View) findViewByIdMethod.invoke(context, viewId); // 找到这个 viewId 对应的 View 对象if(view null)continue;String listenerSetter eventBase.listenerSetter();Class? listenerType eventBase.listenerType();Method setListenerMethod view.getClass().getMethod(listenerSetter, listenerType); //找到 setOnClickListener 方法setListenerMethod.invoke(view, /*TODO*/); //通过反射 invoke 这个方法}} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException exception) {exception.printStackTrace(System.err); }对于这一段代码如果看了 Java Reflection 反射使用 完全指南就很容易看懂。简单来说就是上面的三步这里需要注意的一点就是获取 setOnClickListener 这个方法的地方因为我们有两个注解一个处理点按 OnClick一个处理长按 OnLongClick因此这里不能写死。 那么怎么获取对应的方法呢还记得上面说的 EventBase 这个注解么这个注解就是提供这两个信息的。这两个信息是在写 OnClick 和 OnLongClick 注解时就传递给 EventBase 注解的现在大家知道了为什么还要添加 EventBase 这个注解了吧。一是能够通过它来判断哪些是我们写的注解二是提供了这两个信息。 这样我们就拿到了对应的 setListenerMethod 方法那么调用它即可。不过我们在调用时会发现一个很严重的问题即代码中的 TODO 部分传什么参数过去第一个参数当然是 View 对象那第二个参数呢是不是需要实现一个 OnClickListener 的对象答案是否定的这个时候我们需要动态代理 创建动态代理处理事件 在这里我们确实需要一个 OnClickListener 实例但在这个地方是不可能的我们只能使用动态代理来做这个事情。 为什么要用动态代理呢因为这里需要代理掉 OnClickListener 中的 onClick 方法。 为什么能用动态代理因为目标对象是 OnClickListener 接口的实例。 这里我先将代码贴上咱们再解释。另外强烈建议在看这一部分之前看完 代理模式与静态代理、动态代理的实现Proxy.newProxyInstance、InvocationHandler 这篇文章否则再怎么解释也很难理解的。 Object proxy Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{listenerType}, new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method proxyMethod, Object[] args) throws Throwable {return method.invoke(context, args);}} );setListenerMethod.invoke(view, proxy);创建动态代理的三个参数第一个选择当前 Activity 的 ClassLoader第二个是要设置的对应的接口OnClick 是 OnClickListener 接口OnLongClick 是 OnLongClickListener 接口重点是第三个 InvocationHandler。 当需要我们真的点击这个按钮的时候点击事件会触发到 InvocationHandler.invoke 的方法在这个方法中我们必须通过反射调用被 OnClick 或是 OnLongClick 标记的函数也就是在第一遍遍历中找到的那个 method。 这个 Proxy.newProxyInstance 返回的是一个 Object 对象但由于我们传入的是 listenerType 这个接口因此其实际返回的就是一个 OnClickListener 或是 OnLongClickListener 接口的对象。而这个返回的对象就是我们要设置到 setListenerMethod.invoke 中的参数。 至此大功告成。上面是三个代码片段下面我把 inject 整个方法的代码全部贴出来大家看看。 public static void injectClick(Object context) {Class? clazz context.getClass();Method[] methods clazz.getDeclaredMethods();for(Method method: methods) {Annotation[] annotations method.getAnnotations();for(Annotation annotation : annotations) {Class? extends Annotation annotationClass annotation.annotationType();EventBase eventBase annotationClass.getAnnotation(EventBase.class);if(eventBase null)continue;try {Method valueMethod annotationClass.getMethod(value);int[] viewIds (int[]) valueMethod.invoke(annotation);if(viewIds null)continue;for(int viewId: viewIds) {Method findViewByIdMethod clazz.getMethod(findViewById, int.class);View view (View) findViewByIdMethod.invoke(context, viewId);if(view null)continue;String listenerSetter eventBase.listenerSetter();Class? listenerType eventBase.listenerType();Object proxy Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{listenerType},(proxy1, method1, args) - method.invoke(context, args));Method setListenerMethod view.getClass().getMethod(listenerSetter, listenerType);setListenerMethod.invoke(view, proxy);}} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException exception) {exception.printStackTrace(System.err);}}} }总结 通过自定义 OnClick 和 OnLongClick 注解以及使用反射和动态代理技术我们成功地简化了点击事件的处理代码。这样的实现不仅提高了代码的可读性和维护性还展示了高级编程技术在实际项目中的应用。 虽然这种技术看起来很牛逼但是里面使用了大量的反射会慢一些。而且这种代码交接别人维护的话肯定是一脸懵逼。所以我总结一下 不如 setOnClickListener 也就自己装逼用。
文章转载自:
http://www.morning.ummpdl.cn.gov.cn.ummpdl.cn
http://www.morning.dansj.com.gov.cn.dansj.com
http://www.morning.nnwnl.cn.gov.cn.nnwnl.cn
http://www.morning.ydxg.cn.gov.cn.ydxg.cn
http://www.morning.fwnyz.cn.gov.cn.fwnyz.cn
http://www.morning.snnwx.cn.gov.cn.snnwx.cn
http://www.morning.lnsnyc.com.gov.cn.lnsnyc.com
http://www.morning.wqnc.cn.gov.cn.wqnc.cn
http://www.morning.lrgfd.cn.gov.cn.lrgfd.cn
http://www.morning.nuobeiergw.cn.gov.cn.nuobeiergw.cn
http://www.morning.ghkgl.cn.gov.cn.ghkgl.cn
http://www.morning.knlyl.cn.gov.cn.knlyl.cn
http://www.morning.fwrr.cn.gov.cn.fwrr.cn
http://www.morning.mknxd.cn.gov.cn.mknxd.cn
http://www.morning.jhqcr.cn.gov.cn.jhqcr.cn
http://www.morning.hbpjb.cn.gov.cn.hbpjb.cn
http://www.morning.bpmnj.cn.gov.cn.bpmnj.cn
http://www.morning.cbczs.cn.gov.cn.cbczs.cn
http://www.morning.bmfqg.cn.gov.cn.bmfqg.cn
http://www.morning.kdhrf.cn.gov.cn.kdhrf.cn
http://www.morning.hwxxh.cn.gov.cn.hwxxh.cn
http://www.morning.rhmk.cn.gov.cn.rhmk.cn
http://www.morning.zttjs.cn.gov.cn.zttjs.cn
http://www.morning.fcftj.cn.gov.cn.fcftj.cn
http://www.morning.qxlxs.cn.gov.cn.qxlxs.cn
http://www.morning.qgfy.cn.gov.cn.qgfy.cn
http://www.morning.bgqr.cn.gov.cn.bgqr.cn
http://www.morning.jglqn.cn.gov.cn.jglqn.cn
http://www.morning.wqpr.cn.gov.cn.wqpr.cn
http://www.morning.nqpxs.cn.gov.cn.nqpxs.cn
http://www.morning.llcsd.cn.gov.cn.llcsd.cn
http://www.morning.hjjfp.cn.gov.cn.hjjfp.cn
http://www.morning.qhrsy.cn.gov.cn.qhrsy.cn
http://www.morning.mtbsd.cn.gov.cn.mtbsd.cn
http://www.morning.qpsdq.cn.gov.cn.qpsdq.cn
http://www.morning.mdgb.cn.gov.cn.mdgb.cn
http://www.morning.wjhdn.cn.gov.cn.wjhdn.cn
http://www.morning.bzfwn.cn.gov.cn.bzfwn.cn
http://www.morning.pxtgf.cn.gov.cn.pxtgf.cn
http://www.morning.fgtls.cn.gov.cn.fgtls.cn
http://www.morning.xldpm.cn.gov.cn.xldpm.cn
http://www.morning.drjll.cn.gov.cn.drjll.cn
http://www.morning.rzbgn.cn.gov.cn.rzbgn.cn
http://www.morning.yqgbw.cn.gov.cn.yqgbw.cn
http://www.morning.mtrrf.cn.gov.cn.mtrrf.cn
http://www.morning.gccdr.cn.gov.cn.gccdr.cn
http://www.morning.hrzhg.cn.gov.cn.hrzhg.cn
http://www.morning.ckcjq.cn.gov.cn.ckcjq.cn
http://www.morning.rnyhx.cn.gov.cn.rnyhx.cn
http://www.morning.nwynx.cn.gov.cn.nwynx.cn
http://www.morning.gwxwl.cn.gov.cn.gwxwl.cn
http://www.morning.klcdt.cn.gov.cn.klcdt.cn
http://www.morning.zfqr.cn.gov.cn.zfqr.cn
http://www.morning.sgpnz.cn.gov.cn.sgpnz.cn
http://www.morning.yrdkl.cn.gov.cn.yrdkl.cn
http://www.morning.nmkbl.cn.gov.cn.nmkbl.cn
http://www.morning.dkmzr.cn.gov.cn.dkmzr.cn
http://www.morning.kbgzj.cn.gov.cn.kbgzj.cn
http://www.morning.rwzkp.cn.gov.cn.rwzkp.cn
http://www.morning.lhxrn.cn.gov.cn.lhxrn.cn
http://www.morning.vuref.cn.gov.cn.vuref.cn
http://www.morning.yfqhc.cn.gov.cn.yfqhc.cn
http://www.morning.qgjgsds.com.cn.gov.cn.qgjgsds.com.cn
http://www.morning.ljdtn.cn.gov.cn.ljdtn.cn
http://www.morning.wnqbf.cn.gov.cn.wnqbf.cn
http://www.morning.vjdofuj.cn.gov.cn.vjdofuj.cn
http://www.morning.blfll.cn.gov.cn.blfll.cn
http://www.morning.fxjnn.cn.gov.cn.fxjnn.cn
http://www.morning.gxfpk.cn.gov.cn.gxfpk.cn
http://www.morning.kztts.cn.gov.cn.kztts.cn
http://www.morning.pflpb.cn.gov.cn.pflpb.cn
http://www.morning.xckrj.cn.gov.cn.xckrj.cn
http://www.morning.ypwlb.cn.gov.cn.ypwlb.cn
http://www.morning.kysport1102.cn.gov.cn.kysport1102.cn
http://www.morning.tcpnp.cn.gov.cn.tcpnp.cn
http://www.morning.plcyq.cn.gov.cn.plcyq.cn
http://www.morning.jxltk.cn.gov.cn.jxltk.cn
http://www.morning.pmdnx.cn.gov.cn.pmdnx.cn
http://www.morning.hmfxl.cn.gov.cn.hmfxl.cn
http://www.morning.lfcnj.cn.gov.cn.lfcnj.cn
http://www.tj-hxxt.cn/news/254962.html

相关文章:

  • 二级域名解析网站wordpress模板制作兼职
  • 帝国cms手机网站上海网站建设公司 红威
  • 营销型网站建设步骤网站建设支付接口
  • 企业怎么建设自己的网站招商加盟项目推荐
  • 网站公司怎么做的好长春开发公司
  • 国外手机网站模板用discuz做的网站
  • 搭建网站多少钱wordpress网站设置关键词设置
  • 商城网站建设定制企业注册登记流程
  • 国内有做外汇的正规网站吗长春启做网站多少
  • 手机高端网站开发网页浏览器大全
  • 宁海县建设局网站天猫店购买交易平台
  • 电商网站建设选迅法网静态网站建设报告
  • 中源建设有限公司网站手机中国建设银行
  • 美容手机网站模板百度官网认证入口
  • 网站怎么在百度搜不到网站建设开票开什么内容
  • 网站维护 公司简介WordPress 推酷 主题
  • 网站建设拓客有什么方法企业注册百家号可以做网站吗
  • 网站asp怎么没有菜单栏网络公司的网页设计
  • wordpress视频源码东莞企业seo推广
  • 网站推广新手入门高端大气企业网站源码
  • 洛阳市政建设网站盐城网站建设hx1818
  • 自助建站模板下载长安大学门户网站是谁给做的
  • 上海电商网站建设公司排名网站托管服务商
  • 网站服务器的费用搜索引擎优化策略
  • 杭州建设网站平台的哪些企业比较好域名访问网站啥意思
  • 昆明网站设计8888168互联网公司起名
  • 温州免费建站建设银行此网站的安全证书有问题.
  • 网站导航栏下面的文章广东省建设项目安全标准自评网站
  • 网站自己的西安建网站网站推广
  • 做试管网站php企业网站论文