butterknife架构核心

本文介绍了一种利用Java注解处理器APT自动生成辅助类的方法,通过解析ViewInjector注解,自动生成控件注入代码,简化Activity中的视图绑定操作。

反射:

Class.forName("com.mysql.jdbc.Driver");

在编写代码,编译的时候,这个类没有,但是在运行的时候,这个Driver.class类有。

Mirror模块
让java源文件在编译的时候,可以访问

APT 命令行工具
1.编译过程中,需要获取哪些类的信息?
2.这些类的信息在哪里获取?

APT会访问AnnotationProcessor类,获取访问规则,然后访问符合规则的A类,访问到了A类的属性,方法集合,这些信息又会传给Process处理。
这里写图片描述

核心类代码
1、ViewInjectHandler.java
把RoundEnvironment类整理出一个Map

public class ViewInjectHandler implements AnnotationHandler {
  ProcessingEnvironment mProcessingEnv;
  @Override
  public void attachProcessingEnv(ProcessingEnvironment processingEnv) {
   mProcessingEnv = processingEnv;
  }

@Override
public Map<String,List<VariableElement>> handleAnnotation(RoundEnvironment roundEnv){
  Map<String, List<VariableElement>> annotationMap = new HashMap<String, List<VariableElement>>();
  //获取使用ViewInjector注解的所有元素
  Set<? extends Element> elementSet = roundEnv.getElementsAnnotatedWith(ViewInjector);
  for(Element element : elementSet){
    //注解的字段
    VariableElement varElement = (VariableElement)element;
    //获取某个字段所属的类的完整路径
    String className = getParentClassName(varElement);
    //获取这个类上所有带有ViewInjector注解的字段
    List<VariableElement> cacheElements = annotationMap.get(className);
    if (cacheElements == null) {
      cacheElements = new LinkedList<VariableElement>();
   }
   //将元素添加到该类型对应的字段列表中
   cacheElements.add(varElement);
   //以类的路径为key,字段列表为value,存入map
   //这里是将所在字段按所属的类型进行分类
   annotationMap.put(className, cacheElements); 
  }
}

/**
*获取某个字段所属的类的完整路径
*/
private String getParentClassName(VariableElement varElement) {
  //获取该元素所在的类型,例如某个View是某个Activity的字段,这里就是获取这个Activity的类型
  TypeElement typeElement = (TypeElement)varElement.getEnclosingElement();
  //获取typeElement的包名
  String packageName = AnnotationUtil.getPackageName(mProcessingEnv, typeElement);
  //类型的完整路径名,比如某个Activity的完整路径
  return packageName + "." + typeElement.getSimpleName().toString();
  }
}

2、ViewInjectorProcessor.java
符合规则的类在这里处理

//指定APT工具访问规则
@SupportedAnnotationTypes("com.jasonknife.annotation.ViewInjector")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class ViewInjectorProcessor extends AbstractProcessor {

public List<AnnotationHandler> mHandlers = new ArrayList<AnnotationHandler>();
 Map<String,List<VariableElement>> map = new HashMap<String,List<VariableElement>>();
AdapterWriter mWriter;

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
  super.init(processingEnv);
  registerHandlers();
  //2.根据map生成辅助类
  mWriter = new DefaultAdapterWriter(processingEnv);

}

private void registerHandlers(){
  mHandlers.add(new ViewInjectHandler());
}

  //符合规则的类信息,在这里处理
  @Override
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
   //1.roundEnv->整理出Map<String, List<VariableElement>> (key->完整类名,value->属性集合)
   for(AnnotationHandler handler : mHandlers){
     handler.attachProcessingEnv(processingEnv);
 map.putAll(handler.handleAnnotation(roundEnv));
   }
   mWriter.generate(map);
   return true;
  }
}

3、生成辅助类的Writer:AbstractWriter.java

public abstract class AbstractWriter implements AdapterWriter {
  private ProcessingEnvironment mProcessingEnv;
  private Filer mFiler;
  public AbstractWriter(ProcessingEnvironment env) {
  this.mProcessingEnv = env;
  this.mFiler = this.mProcessingEnv.getFiler();
  }

  @Override
  public void generate(Map<String,List<VariableElement>> map) {
  //模板方法
  Iterator<Entry<String, List<VariableElement>>> entry = map.entrySet().iterator();
  while(iterator.hasNext()){
    Entry<String,List<VariableElement>> entry = iterator.next();
    //属性集合
    List<VariableElement> cacheElements = entry.getValue();
    if(cacheElements == null || cacheElements.size() == 0) {
    continue;
   }
   InjectInfo info = createInjectInfo(cacheElements.get(0));
   //创建一个Java源文件
   Writer writer = null;
   try{
     JavaFileObject javaFileObject = mFiler.createSourceFile(info.getFullClassName());
     writer = javaFileObject.openWriter();
     //头部,模板方法只控制算法的骨架,具体的交给子类实现
     generateImport(writer,info);
     for (VariableElement variableElement : cacheElements) {
     //属性部分
     writeField(writer,variableElement,info);
     }
     //尾部
     writeEnd(writer);
   }catch(IOException e){
     e.printStackTrace();
   }finally{
     IOUtil.closeQuitly(writer);
   }
  }
}

private InjectInfo createInjectInfo(VariableElement variableElement) {
//属性所属的类
TypeElement typeElement = (TypeElement)variableElement.getEnclosingElement();
String packageName = AnnotationUtil.getPackageName(mProcessingEnv,variableElement);
String className = typeElement.getSimpleName().toString();
return new InjectInfo(packageName,className);
}

/**
*生成头部
*/
protected abstract void generateImport(Writer writer,InjectInfo info) throws IOException;

/**
*生成尾部
*/
protected abstract void writeField(Writer writer,VariableElement element,InjectInfo info);

/**
*产生结尾部分
*/
protected abstract void writeEnd(Writer writer) throws IOException;

/**
*注入信息
*/
 class InjectInfo{
   public String packageName;
   public String className;
   //辅助类的类名
   public String newClassName;

   public InjectInfo(String packageName,String className) {
   this.packageName = packageName;
   this.className = className ;
   this.newClassName = className + JsonKnife.SUEFIX;
  }

  public String getFullClassName() {
    return this.packageName +"." +this.newClassName;
   }
  }
}

4、具体生成辅助类的子类:DefaultAdapterWriter.java

public class DefaultAdapterWriter extends AbstractWriter {
  public DefaultAdapterWriter(ProcessingEnvironment processingEnv) {
  super(processingEnv);
  }

@Override
protected void generateImport(Writer writer, InjectInfo info) throws IOException {
  writer.write("package "+info.packageName +";");
  writer.write("\n\n");
  writer.write("import com.jasonknife.adapter.InjectAdapter;");
  writer.write("\n");
  writer.write("import com.jasonknife.util.ViewFinder;");
  writer.write("\n\n\n");
  writer.write("/*This Class is generated by JasonKnife, do not modify!*/");
  writer.write("\n");
  writer.write("public class "+info.newClassName+" implements InjectAdapter<"+info.);
  writer.write("\n\n");
  writer.write("public void injects("+info.className+" target) {");
  writer.write("\n");
  }

@Override
protected void writeField(Writer writer, VariableElement element, InjectInfo info) throw IOException {
  ViewInjector viewInjector = element.getAnnotation(ViewInjector.class);
  int id = viewInjector.value();
  String fieldName = element.getSimpleName().toString();
  writer.write("target."+fieldName+" = ViewFinder.findViewById(target, "+id+");");
  writer.write("\n");
}

@Override
protected void writeEnd(Writer writer)throws IOException {
  writer.write("   }");
  writer.write("\n\n");
  writer.write("}");
}

}

得到辅助类MainActivity$InjectAdapter.java
这个类里面的injects方法才是给控件赋值的真正方法

public class MainActivity$InjectAdapter implements InjectAdapter {
  public void injects(MainActivity target) {
    target.text = ViewFinder.findViewById(target,2131099648);
    target.btn = ViewFinder.findViewById(target,2131099649);
  }
}

编写注入类:

public final class JsonKnife {
  public static final String SUEFIX ="$InjectAdapter";
  public static void inject(Activity activity){
     InjectAdapter<Activity> adapter = getViewAdapter(activity.getClass());
     adapter.injects(activity);
  }

/**
*获取辅助类实例
*/
private static <T> InjectAdapter<T> getViewAdapter(Class<?> clazz) {
  InjectAdapter<T> adapter = null;
  String adapterClsName = clazz.getName() + SUEFIX;
  try{
    Class<?> adapterClazz = Class.forName(adapterClsName);
    adapter = adapterClazz.newInstance();
  }catch(Exception e){
    e.printStackTrace();
  }
  //NullAdapter 空对象模式
  return adapter == null ? new NullAdapter : adapter;
}
}

使用方法

public class MainActivity extends Activity implements OnClickListener {

  @ViewInject(R.id.text)
  protected TextView text;
  @ViewInject(R.id.button)
  protected Button btn;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
   JsonKnife.inject(this);
   btn.setOnClickListener(this);
 }

 public void onClick(View v){
  Log.d("json","按钮不为空,注入成功...");
 }

}
【轴承故障诊断】基于融合鱼鹰和柯西变异的麻雀优化算法OCSSA-VMD-CNN-BILSTM轴承诊断研究【西储大学数据】(Matlab代码实现)内容概要:本文提出了一种基于融合鱼鹰和柯西变异的麻雀优化算法(OCSSA)优化变分模态分解(VMD)参数,并结合卷积神经网络(CNN)与双向长短期记忆网络(BiLSTM)的轴承故障诊断模型。该方法利用西储大学公开的轴承数据集进行验证,通过OCSSA算法优化VMD的分解层数K和惩罚因子α,有效提升信号分解精度,抑制模态混叠;随后利用CNN提取故障特征的空间信息,BiLSTM捕捉时间序列的动态特征,最终实现高精度的轴承故障分类。整个诊断流程充分结合了信号预处理、智能优化与深度学习的优势,显著提升了复杂工况下轴承故障诊断的准确性与鲁棒性。; 适合人群:具备一定信号处理、机器学习及MATLAB编程基础的研究生、科研人员及从事工业设备故障诊断的工程技术人员。; 使用场景及目标:①应用于旋转机械设备的智能运维与故障预警系统;②为轴承等关键部件的早期故障识别提供高精度诊断方案;③推动智能优化算法与深度学习在工业信号处理领域的融合研究。; 阅读建议:建议读者结合MATLAB代码实现,深入理解OCSSA优化机制、VMD参数选择策略以及CNN-BiLSTM网络结构的设计逻辑,通过复现实验掌握完整诊断流程,并可进一步尝试迁移至其他设备的故障诊断任务中进行验证与优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值