使用Espresso检测当前显示Fragment遇getFragments()方法缺失问题
这个报错的原因很明确:FragmentManager.getFragments()是Android 8.0(API 26)才新增的系统API,而你的三星Galaxy S8运行的是Android 7(API 24),系统自带的android.app.FragmentManager并没有这个方法,所以抛出了NoSuchMethodError。
下面给你几个可行的解决思路,按推荐程度排序:
1. 迁移到AndroidX/Support Library的Fragment体系(最推荐)
如果你还在使用原生的android.app.Fragment,强烈建议切换到androidx.fragment.app.Fragment(或者旧版的android.support.v4.app.Fragment)。这套兼容库实现了自己的FragmentManager,它的getFragments()方法在所有支持的Android版本上都能正常工作,不受系统API版本限制。
修改你的辅助函数如下:
import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import java.util.List; public static Fragment getVisibleFragment(FragmentActivity activity) { FragmentManager fragmentManager = activity.getSupportFragmentManager(); List<Fragment> fragments = fragmentManager.getFragments(); if (fragments != null) { for (Fragment fragment : fragments) { if (fragment != null && fragment.isVisible()) { return fragment; } } } return null; }
注意:你的Activity需要继承AppCompatActivity或者FragmentActivity,这样才能调用getSupportFragmentManager()获取兼容库的Fragment管理器。
2. 手动维护当前显示的Fragment(最稳定)
如果暂时不想迁移兼容库,可以在你的Activity里手动跟踪当前显示的Fragment。这种方法完全不依赖系统私有API,兼容性拉满。
比如在你的主Activity中添加以下逻辑:
import android.app.Activity; import android.app.Fragment; public class MainActivity extends Activity { private Fragment currentVisibleFragment; // 封装你的Fragment切换方法 public void switchFragment(Fragment targetFragment) { getFragmentManager().beginTransaction() .replace(R.id.fragment_container, targetFragment) .commit(); // 更新当前显示的Fragment currentVisibleFragment = targetFragment; } // 给测试提供获取当前Fragment的方法 public Fragment getCurrentVisibleFragment() { return currentVisibleFragment; } }
之后在测试代码里,直接调用activity.getCurrentVisibleFragment()就能拿到当前显示的Fragment,不需要再遍历FragmentManager的列表。
3. 反射获取私有Fragment列表(临时救急,不推荐)
如果上面两种方案都没法快速实现,可以用反射读取原生FragmentManager内部的私有字段来获取Fragment列表。不过要注意:反射依赖系统内部实现,不同厂商ROM可能修改字段名,稳定性差,只适合临时解决问题。
修改后的辅助函数:
import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import java.lang.reflect.Field; import java.util.List; public static Fragment getVisibleFragment(Activity activity) { FragmentManager fragmentManager = activity.getFragmentManager(); try { // 反射获取FragmentManager内部存储已添加Fragment的mAdded字段 Field mAddedField = FragmentManager.class.getDeclaredField("mAdded"); mAddedField.setAccessible(true); @SuppressWarnings("unchecked") List<Fragment> fragments = (List<Fragment>) mAddedField.get(fragmentManager); if (fragments != null) { for (Fragment fragment : fragments) { if (fragment != null && fragment.isVisible()) { return fragment; } } } } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } return null; }
内容的提问来源于stack exchange,提问作者Adam Varhegyi

