如何在Fragment中访问复用MainActivity创建的API实例
完全可以在Fragment中复用MainActivity里初始化的customApi实例,不需要重复创建,以下是可直接落地的实现方案:
第一步:先调整MainActivity的封装
不要直接把customApi字段设为public暴露,推荐用公共get方法提供访问入口,避免外部随意修改实例:
public class MainActivity extends AppCompatActivity { // 字段私有,禁止外部直接修改 private CustomApi customApi; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); customApi = new CustomApi(this, key); } // 提供公共访问入口 public CustomApi getCustomApi() { return customApi; } }
方案1:直接获取宿主Activity实例(最简单,适合Fragment专属MainActivity的场景)
如果这个Fragment只会被挂载到MainActivity上,直接在Fragment的合适生命周期里获取宿主Activity,强转后拿实例即可:
public class ContentFragment extends Fragment { private CustomApi customApi; @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); // 校验宿主类型后再获取实例 if (requireActivity() instanceof MainActivity) { customApi = ((MainActivity) requireActivity()).getCustomApi(); // 拿到实例后可直接调用接口方法 // customApi.requestData(); } } }
注意:获取逻辑必须放在FragmentonAttach()之后的生命周期方法里执行,不要在构造函数、onCreate()之前调用,否则会因为Fragment未绑定Activity抛出空指针或异常。
方案2:接口契约解耦(推荐,适合Fragment可能复用的场景)
如果这个Fragment后续可能被挂载到其他Activity上,不要直接强转MainActivity,通过定义接口的方式解耦:
- 首先定义通用的Api提供接口
public interface CustomApiProvider { CustomApi getCustomApi(); }
- 让MainActivity实现这个接口
public class MainActivity extends AppCompatActivity implements CustomApiProvider { private CustomApi customApi; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); customApi = new CustomApi(this, key); } @Override public CustomApi getCustomApi() { return customApi; } }
- Fragment中通过接口获取实例,不需要感知宿主具体类型
public class ContentFragment extends Fragment { private CustomApi customApi; @Override public void onAttach(@NonNull Context context) { super.onAttach(context); if (context instanceof CustomApiProvider) { customApi = ((CustomApiProvider) context).getCustomApi(); } else { throw new RuntimeException("宿主Activity必须实现CustomApiProvider接口"); } } }
这种方案的好处是Fragment和具体Activity完全解耦,后续要把Fragment放到其他页面复用,只需要对应Activity实现CustomApiProvider接口即可,不需要修改Fragment内部逻辑,也更方便写单元测试。
可选方案:共享Activity级ViewModel
如果项目已经接入Jetpack ViewModel组件,可以把customApi实例存放在和Activity同作用域的ViewModel中,Fragment通过activityViewModels()拿到同一个ViewModel实例即可获取Api对象,这种方式天然能应对屏幕旋转等重建场景,生命周期更安全。
注意:除非明确需要多实例,否则不要在Fragment中重复new CustomApi对象,重复创建不仅会造成不必要的内存开销,如果CustomApi内部维护了请求队列、全局配置、长连接等逻辑,多实例还会引发状态错乱、资源泄漏等问题。
内容的提问来源于stack exchange,提问作者The Tissot

