资料来源
https://blog.csdn.net/sinat_38259539/article/details/71799078
反射练习
基本思路
把活动/碎片A的引用存入对象B
点击按钮的时候加载这个对象B,从对象中取出引用,通过反射解析成活动/碎片并启动
主布局是一个FramLayout和两个按钮,分别测试添加活动和碎片
1.项目文件及结构
基本的实现
首先是MyApp,包含一个String字段和一个Class字段
然后在MainActivity中初始化一个MyApp List,这个list必须是活动内全局的.
list=new ArrayList<>(); list.add(new MyApp("com.example.reflextest.SecondActivity", SecondActivity.class)); list.add(new MyApp("com.example.reflextest.BlankFragment", BlankFragment.class));
接下来是初始化按钮控件
Button bActivity=findViewById(R.id.b_start_activity); Button bFragment=findViewById(R.id.b_add_fragment);
最后就是设置点击监听,因为认为把所有情况统一处理,所以活动和碎片的点击判断也放在了一起
同样的思路
先获取Class,再通过Class.newInstance()获取到Object实例,然后通过instanceof字段,判断是碎片还是活动,再强制转换成对应的类别,按照分开的方式启动活动
有个问题就是Class的获取方式
这个是直接获取Class
@Override
public void onClick(View view) {
try {
Class purpose=list.get(0).getPurpose();
Object obj=purpose.newInstance();
if (obj instanceof Fragment){
Fragment fragment=(Fragment) obj;
Log.i(TAG, "onClick: fragment="+fragment.toString());
FragmentTransaction transaction=getSupportFragmentManager().beginTransaction();
transaction.add(R.id.layout_container,fragment);
transaction.commit();
}else if (obj instanceof AppCompatActivity){
AppCompatActivity activity=(AppCompatActivity)obj;
Log.i(TAG, "onClick: activity="+activity.toString());
Intent intent=new Intent(view.getContext(),activity.getClass());
startActivity(intent);
}else{
Log.i(TAG, "onClick: obj null");
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
这个是通过Class.forName()获取
@Override
public void onClick(View view) {
try {
Class purpose=Class.forName(list.get(1).getName());
Object obj=purpose.newInstance();
if (obj instanceof Fragment){
Fragment fragment=(Fragment) obj;
Log.i(TAG, "onClick: fragment="+fragment.toString());
FragmentTransaction transaction=getSupportFragmentManager().beginTransaction();
transaction.add(R.id.layout_container,fragment);
transaction.commit();
}else if (obj instanceof AppCompatActivity){
AppCompatActivity activity=(AppCompatActivity)obj;
Log.i(TAG, "onClick: activity="+activity.toString());
Intent intent=new Intent(view.getContext(),activity.getClass());
startActivity(intent);
}else{
Log.i(TAG, "onClick: obj null");
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
对比下就会发现,Class.forName(String s),要多抛出一个告警,另外,就是存储s的时候,必须要把包路径也包含进去
对比下初始化的过程.Class变量的获取就要简单的多,找到变量名,加.class即可
但是Class.forName(String s)也有优势,字符串可以从配置文件中读取,而不必仅限于程序中已经存在的类名,这点更灵活
new MyApp("com.example.reflextest.BlankFragment", BlankFragment.class)
填坑
使用LitePal时要注意,Class变量不能储存,会引起告警
Caused by: org.litepal.exceptions.LitePalSupportException: Can not make a java.lang.Class constructor accessible