java反射的学习笔记

资料来源

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

猜你喜欢

转载自blog.csdn.net/rungby/article/details/80418785