Android源码桥梁模式---FragmentCompat

发现想要在Android源码中找到一个明显使用桥梁模式的模块还真的挺不容易的,但由于Android代码命名上面的规律,还是让我搜索到了。FragmentCompat是一个用于访问Fragment特征的帮助类,它在support v13开始以一种向后兼容的风格提出。它是如何向后兼容的呢?就是使用桥梁模式来向后兼容。它是一种简化了的桥梁模式,下面将简单介绍FragmentCompat与桥梁模式。

桥梁模式

意图

将对象的抽象与实现分隔开来,以使对象的抽象与实现相互独立地变化。

UML

此处输入图片的描述

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//抽象
abstract class AbsComponent{
private AbsComponentImpl impl;
public AbsComponentImpl getComponentImpl(){
return impl;
}
public AbsComponent(AbsComponentImpl impl){
this.impl = impl;
}
public abstract void operate();
}
//实现
abstract class AbsComponentImpl{
public abstract void operateImpl();
}
class ComponentImpl1 extends AbsComponentImpl{
public void operateImpl(){
System.out.println("operate implements");
}
}
class Component1 extends AbsComponent{
public Component1(AbsComponentImpl impl){
super(impl);
}
public void operate(){
//通过具体的实现部分(impl)来进行操作。
getComponentImpl().operateImpl();
}
}
public static AbsComponentImpl createImpl(int id){
// 根据id来创建不同的对象
switch(id){
case 1:
return new ComponentImpl1();
}
}
public static void main(String[] args){
Component1 com = new Component1(createImpl(1)); //此处就是将实现与抽象部分结合起来,大多采用工厂方法的方式创建实现部分
com.operate(); //里面是桥接到实现部分去操作的
}

上述代码中,有一个抽象组件以及组件实现,组件实现也是有一个抽象父类,想要实现组件实现,就去新创建一个子类。大部分时候,都是采用工厂方法模式去创建一个具体的组件实现对象。根据传入的参数来创建不同的实现。假如实现修改了,抽象部分并不需要改变,只需要创建一个对应的实现对象就可以了。同样抽象部分的变化,也完全不会影响到实现。这就是桥接模式的好处,几乎所有的窗口实现都是采用桥接模式的,窗口与窗口的具体实现(Linux Gnome窗口,Ubuntu窗口)通过桥接模式分隔开来,应用程序开发的时候只需要考虑窗口就可以了。

FragmentCompat

FragmentCompat的源码在android.support.v13.app中。它只有四个静态方法,首先介绍一下FragmentCompat相关接口功能:

  • setMenuVisibility(Fragment f,boolean visible)
    设置Fragment创建的菜单是否显示。会在合适的Android版本中调用f.setMenuVisibility(visible)。
  • setUserVisibleHint(Fragment f, boolean deferStart)
    设置Fragment是否显示给用户,这个可以用作Fragment延迟加载,也可以用作在ScrollView中未显示给用户的fragment隐藏起来。
  • requestPermissions(Fragment fragment, String[] permissions, int requestCode)
    请求对应的权限,关于在应用中请求权限是在Mashmallow出现的,从Mashmallow开始,Android重新设计了应用权限,在apk安装的时候不再显示所需要的权限,而是在应用中需要权限的时候再向用户请求。关于应用权限,这篇文章我觉得讲的很不错Android permissions最佳实践
  • shouldShowRequestPermissionRationale(Fragment fragment, String permission)
    判断是否应该显示请求权限的原因,让用户更好地了解该权限的使用。这个要在API23才能使用,之前的版本都是返回false。

FragmentCompat UML图

此处输入图片的描述

FragmentCompat的实现

FragmentCompat中的四个方法都是静态方法,它包含一个FragmentCompatImpl静态成员对象IMPL。其初始化如下:

1
2
3
4
5
6
7
8
9
10
11
12
static final FragmentCompatImpl IMPL;
static {
if (Build.VERSION.SDK_INT >= 23) {
IMPL = new MncFragmentCompatImpl();
} else if (android.os.Build.VERSION.SDK_INT >= 15) {
IMPL = new ICSMR1FragmentCompatImpl();
} else if (android.os.Build.VERSION.SDK_INT >= 14) {
IMPL = new ICSFragmentCompatImpl();
} else {
IMPL = new BaseFragmentCompatImpl();
}
}

实际上就是根据不同的sdk版本采用不同的实现。从上面的UML图也可以看出来,目前的实现方式都是新的SDK版本的实现继承旧的SDK版本的实现。

其实ICSFragmentCompatImpl,ICSMR1FragmentCompatImpl,MncFragmentCompatImpl内部的实现又是通过引用FragmentCompatICS,FragmentCompatICSMR1,FragmentCompat23来实现对应的功能的。如UML图所示,setMenuVisibility由FragmentCompatICS实现,setUserVisibleHint由FragmentCompatICSMR1实现,requestPermissions和shouldShowRequestPermissionRationale由FragmentCompat23实现。

桥梁模式在FragmentCompat的使用分析

FragmentCompat可以看作是桥梁模式的抽象部分,FragmentCompatImpl是它的实现部分。在FragmentCompat中,它的抽象只有一个,其实也没什么变化,它变化的部分主要还是在实现。Android在不同的SDK版本中都有不同的FragmentCompatImpl实现,在这里有点特殊的是它最新的实现都是通过继承之前的实现来完成的。FragmentCompat可以根据不同的SDK版本采用不同的实现。桥梁模式非常适合这种情况。

在另外一方面,在新的sdk出现的时候,有些功能有变化了(比如到了API23, Fragment有shouldShowRequestPermissionRationale方法了,shouldShowRequestPermissionRationale可以实现了),那只需要采用新的Impl就好了,并不会影响前面的实现部分。这样就达到了向后兼容的效果。


读书无嗜好,就能尽其多。不先泛览群书,则会无所适从或失之偏好,广然后深,博然后专。—鲁迅