正文
在Android中,页面跳转的实现很简单,无非就是下面的两行代码。
Intent intent = new Intent(MainActivity.this, TargetActivity.class);
startActivity(intent);
所谓导航页面,也就是多个承载页面跳转功能的控件的集合罢了,就像这样:
点击其中的任意一项,都能跳转到一个新的页面。要实现这样的功能,很简单吧!使用列表让数据按需显示,然后为Item设置点击事件不就行了吗?
navAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
Intent intent = new Intent(MainActivity.this, TargetActivity.class);
startActivity(intent);
}
});
啊,不对,不同的页面显示的数据不一样。还需要传入一个tag,让目标页面根据这个tag加载不同的数据。
navAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
Intent intent = new Intent(MainActivity.this, TargetActivity.class);
intent.putExtra("tag","xxx");
startActivity(intent);
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_target);
String tag = getIntent().getStringExtra("tag");
switch (tag) {
//根据tag做不同的处理...
}
}
这是导航时比较常见的一种情况,也就是目标页面的整体布局、功能逻辑基本相同,只有数据或较少功能存在差异,页面可以复用的情况。
那么问题来了,当目标页面差异较大,不可复用时,应该怎么处理呢?
啊这,不是一样的套路吗?无非就是跳转之前先判断,再跳转呗。
navAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
Intent intent = new Intent();
switch (data.get(position).getTitle()) {
case "主机":
intent.setClass(MainActivity.this, TargetActivity.class);
break;
case "游戏":
intent.setClass(MainActivity.this, AnotherActivity.class);
break;
default:
break;
}
startActivity(intent);
}
});
这才写了两个跳转,就已经感觉到代码十分难看了。如果有数十个跳转,试问谁会想写这么一长串的switch块呢?需求再给你改一改,还不得当场去世。
那么问题又来了,这里的跳转逻辑其实是一致的,就是先判断,再跳转,那就不能整理成一个便于管理的方法呢?答案是,可以。这里就要请出我们本文的主角——反射机制了。
众所周知,JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。
所以如果我把跳转的逻辑封装成一个个命名规范的方法,然后在跳转判断时,借助反射机制调用相应的方法不就可以了吗?就像这样:
1、首先,我们要定制一个协议,或者说规则来约束命名。
2、创建一个SkipHelper类,将跳转各个页面的方法按规则定义。
public class SkipHelper {
public static void SkipToTargetPage(Context context) {
Intent intent = new Intent(context, TargetActivity.class);
context.startActivity(intent);
}
public static void SkipToAnotherPage(Context context) {
Intent intent = new Intent(context, AnotherActivity.class);
context.startActivity(intent);
}
}
3、与后端开发人员协调,为数据添加一个新字段pageUrl,这是我们获取对应方法的关键,它的传值必须符合规则。
public class NavBean {
private String title;
private int imgResId;
//新增此字段
private String pageUrl;
}
4、修改跳转的方法。首先获取到数据的pageUrl属性,然后根据规则组装成对应的方法名,最后使用反射机制获取方法并调用。
navAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(@NonNull BaseQuickAdapter<?, ?> adapter, @NonNull View view, int position) {
String methodName = "SkipTo" + data.get(position).getUrl() + "Page";
try {
//反射获取对应跳转方法
Method method = SkipHelper.class.getMethod(methodName, Context.class);
//执行方法
method.invoke(null, MainActivity.this);
} catch (Exception e) {
e.printStackTrace();
}
}
});
5、调整数据,测试成果。
private void initData() {
data.add(new NavBean("主机", R.drawable.ic_game2,"Target"));
data.add(new NavBean("游戏", R.drawable.ic_game,"Target"));
data.add(new NavBean("音乐", R.drawable.ic_music,"Target"));
data.add(new NavBean("绘画", R.drawable.ic_draw,"Another"));
data.add(new NavBean("运动", R.drawable.ic_sport,"Another"));
data.add(new NavBean("视频", R.drawable.ic_video,"Another"));
data.add(new NavBean("电影", R.drawable.ic_movie,"Another"));
data.add(new NavBean("知识", R.drawable.ic_know,"Another"));
}
结语
关于反射,这应该是自我学Java以来,除了加载数据库以外,真正意义上学习和使用了反射机制。啊,这么久了,总算拨云见日,真是太逊了。
关于规则。文中定义的规则看似可有可无,但在实际开发中还是比较重要的,由于业务上跳转到的页面可能不是Android原生页面,还有可能是Web页面、H5页面等等,在处理时会更为复杂,因此规则的定义不可小觑。