Replugin 宿主嵌入插件 Fragment

本文探讨在Replugin框架下,如何处理宿主嵌入插件Fragment时遇到的getActivity()为空及ViewModel生命周期问题。通过创建自定义FragmentActivity,代理生命周期事件,确保在不同支持库版本下正确运行。
摘要由CSDN通过智能技术生成

业务场景:在插件A 里面,我们想嵌入插件B 的视图。
1,先把插件B 的 Fragment 改造成 View,这样拿到 View 可以直接放到插件A 里面。
2,宿主里面依赖 support 包,其他插件全部不依赖 support 包(provided)。这样各个插件的 Fragment 可以通过反射相互填充了。
3,在插件A 反射调用插件B 的 Fragment 生命周期。
第一种方案,是最直接的,也是问题最少的。
第二种方案,也比较简单,不过需要注意 support 包的版本要统一,还有注意主题 Theme。
第三种方案,需要适配。

很多时候,我们碰到的业务场景是把一个插件的 Activity 内嵌到另一个插件的 Tab。正常我们把 Activity 改造成 View ,这样问题最少。但是有时候我们 Activity 用的是 MVVM,使用了 ViewModel,这样改造了,肯定会报错的。因为宿主和插件的 FragmentActivity 不是一个类的。这时候要么大改代码。要么考虑2,3两种方案了。

而如果这时候,我们不想发主版本,宿主和插件 support 包版本又不一致。
如果宿主的版本是比较大的,还可以直接升级下插件的 support 包就行了。
而如果宿主的比较小,或者不全,这样可以考虑第三种方案了。

本文重点讲第三种方案:

单纯的 Fragment 代理,挺简单的。主要就是把插件 Fragment onCreateView 创建的 View 作为返回值就好了,其他生命周期再代理一下。
以下 v4 包源码,都是基于 28.0.0 版本。

1,先解决 getActivity() 为空的问题
public class Fragment {
   
	FragmentHostCallback mHost;
    public final FragmentActivity getActivity() {
   
    	// 看到 getActivity(),注意 mHost 不能为空。
        return this.mHost == null ? null : (FragmentActivity)this.mHost.getActivity();
    }
}

public class FragmentActivity extends SupportActivity {
   
	// 注意到 FragmentActivity 初始化就会创建 FragmentController,里面就有一个 mHost
	final FragmentController mFragments = FragmentController.createController(new FragmentActivity.HostCallbacks());
}

public class FragmentController {
   
    private final FragmentHostCallback<?> mHost;
}

从源码,我们可以考虑把 FragmentActivity 的 mFragments.mHost 赋值给 Fragment 就行了。(最后会附带实现源码)

2,ViewModel 的生命周期怎么办?

本身要用到 ViewModel 就得适配 getActivity(),不能返回空。

// 我们正常利用 ViewModelProviders 创建 VM
mViewModel = ViewModelProviders.of(this).get(UserInfoBarViewModel.class);
public class ViewModelProviders {
   
    public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
   
    	// 注意 checkActivity checkApplication,会检查
        Application application = checkApplication(checkActivity(fragment));
        if (factory == null) {
   
            factory = AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(ViewModelStores.of(fragment), (Factory)factory);
    }
    private static Activity checkActivity(Fragment fragment) {
   
    	// 这里会判断 getActivity() 不能为空,否则报错。
        Activity activity = fragment.getActivity();
        if (activity == null) {
   
            throw new IllegalStateException("Can't create ViewModelProvider for detached fragment");
        } else {
   
            return activity;
        }
    }
}

VM 生命周期的实现就是注册监听,相关类主要就是 LiveData,Lifecycle,LifecycleRegistry。

// 正常我们监听某个属性变化,都是 LiveData.observe。
public abstract class LiveData<T> {
   
	// LifecycleOwner 就是 FragmentActivity 或者 Fragment。
    public void observe(LifecycleOwner owner, Observer<T> observer) {
   
        if (owner.getLifecycle().getCurrentState() != State.DESTROYED) {
   
            LiveData<T>.LifecycleBoundObserver wrapper = new LiveData.LifecycleBoundObserver(owner, observer);
            LiveData<T>.ObserverWrapper existing = (LiveData.ObserverWrapper)this.mObservers.putIfAbsent(observer, wrapper);
            if (existing != null && !existing.isAttachedTo(owner)) {
   
                throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
            } else if (existing == null) {
   
                owner.getLifecycle().addObserver(wrapper);
            }
        }
    }
}
public class Fragment implements LifecycleOwner {
   
	LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
	public Lifecycle getLifecycle() {
   
        return this.mLifecycleRegistry;
    }
}
public class FragmentActivity extends SupportActivity implements LifecycleOwner {
   
	private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    public Lifecycle getLifecycle() {
   
        return this.mLifecycleRegistry;
    }
}

不管是 Fragment 还是 FragmentActivity,getLifecycle() 都是 LifecycleRegistry。

// 接着来看怎么调用 LifecycleRegistry 的。
public class Fragment {
   
    void performCreate(Bundle savedInstanceState) {
   
        this.onCreate(savedInstanceState);
        ......
        // 都是通过调用 LifecycleRegistry.handleLifecycleEvent 方法来通知生命周期变化的
        this.mLifecycleRegistry.handleLifecycleEvent(Event.ON_CREATE);
    }
    void performResume() {
   
        this.onResume();
        ......
        this.mLifecycleRegistry.handleLifecycleEvent(Event.ON_RESUME);
    }
}

从源码,可以看出我们自己代理调用 mLifecycleRegistry.handleLifecycleEvent(Event) 就可以切换生命周期了。

3,总结:

1,自己创建一个 FragmentActivity。(因为2个插件的 ClassLoader 不一样,导致插件之间 FragmentActivity 就不一样了。)
2,把 FragmentActivity 的 mFragments.mHost 赋值给 Fragment.mHost。这样使得 getActivity() 不为空了。
3,把 Fragment 的 mLifecycleRegistry 赋值给 FragmentActivity,mLi

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值