美文网首页Android知识Android开发Android技术知识
Android开发小工具-摇一摇显示当前页面信息

Android开发小工具-摇一摇显示当前页面信息

作者: lovejjfg | 来源:发表于2017-02-13 15:02 被阅读888次

    当项目工程越来越大之后,大家都会觉得维护起来越来越吃力,如果测试或者UI拿着手机或者截图说这个页面和它的设想有点出入,告诉你是不是他们的姿势不对,哈哈,别想啦,他们是说你的页面有bug了。

    如果恰巧这些都是你写的,那么很好的,你可以分分钟找到指定的页面,发现指定的问题,然后帅气的解决。

    但是,在很多时候,由于历史遗留等等一系列原因,可能你都不知道这是什么时候写的页面,敲的代码了,但是既然问题都提给你了,你总不能说这个不是我写的,找我们老大吧(这样估计会没有年终奖的啦)。

    扯了这么多,接下来说说怎么解决相关的问题呢?其实之前公司就已经考虑到这个问题,做了一个调试摇一摇的功能,但是当时那个功能做的十分的简陋,只能摇一摇显示当前的Activity,如果你的 Activity 上面有事嵌套着 Fragment 的话,那么不好意思,不会显示对应 Fragment 的信息,更别说如果一个 Activity 上面包含了多个 Fragment 的情况。

    fragment.jpg

    例如图一中,是在 Activity 中上半部分嵌套了一个 Fragment1 ,下半部分又加载了 Fragment2 ,在 Fragment2 中是由三个 Fragment 组成的。

    fragment-弹窗.jpg

    需求明确之后,那么就一步一步来完成对应的功能就好啦,结合上面的巴拉巴拉的一堆话,大致需要有以下功能:

    1、摇一摇的功能
    2、获取当前top的 Activity
    3、获取当前 Activity 中显示的 Fragment
    4、弹窗显示
    5、特殊情况处理

    接下来就一个一个开始撸吧。

    摇一摇功能

    获取当前top的 Activity

    这个功能很好实现啦,不管是 Google 还是百度,都能很快的找到想要的代码。相关思路就是获取系统的 SensorManager ,然后注册 SensorManager 的加速度监听器,当加速度大于预设值就响应相关事件。这里只需要注意监听的时机和解除监听的时机。

    public void onStart() {
        //获取 SensorManager 负责管理传感器
        mSensorManager = ((SensorManager) context.getSystemService(Context.SENSOR_SERVICE));
        if (isEnable && mSensorManager != null) {
            //获取加速度传感器
            Sensor mAccelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            if (mAccelerometerSensor != null) {
                mSensorManager.registerListener(this, mAccelerometerSensor, SensorManager.SENSOR_DELAY_UI);
            }
        }
    }
    
    
    public void onPause() {
        if (mSensorManager != null) {
            mSensorManager.unregisterListener(this);
        }
    }
    

    其实到这里,第二个问题 获取当前top的Activity 也解决了。

    获取当前 Activity 中显示的 Fragment

    获取当前 Activity 中显示的 Fragment,其实就是说获取到 Activity 中所有的 Fragment ,这个呢,就是使用 FragmentManagermanager.getFragments() 方法就好啦,然后在这些 Fragment 中获取到当前正在显示的 Fragment 。这里 Fragment 是否显示是由以下两个方法来判断的:f.isAdded()f.isHidden()。为什么不用一个就好了呢?因为添加 Fragment 可能是 replace() 也有可能是 hide() , show() 的方式,在 replace() 之后,通过 FragmentManager 还是可以获取到对应的 Fragment ,只是它的 isAdded() 将是 false,而且此时 isHidden() 也是 false,所以就会出问题啦! 这里还要考虑 Fragment 嵌套 Fragment 的情况,所以还需要使用到 f.getChildFragmentManager() 的方法递归查询一下。另外如果这里是使用 ViewPager 来模式管理 Fragment 的话,那么这里还需要判断 f.getUserVisibleHint()的返回情况。

    @Nullable
    private List<Fragment> getTopFragments() {
        if (manager == null) {
            return null;
        }
        List<Fragment> fragments = manager.getFragments();
        List<Fragment> topFragments = new ArrayList<>();
        if (fragments == null) {
            return null;
        }
        int size = fragments.size();
        for (int i = size - 1; i >= 0; i--) {
            Fragment f = fragments.get(i);
            if (f.isAdded() && !f.isHidden() && f.getUserVisibleHint()) {
                Fragment t = getTopFragment(f.getChildFragmentManager());//递归
                if (t != null) {
                    topFragments.add(t);
                } else {
                    topFragments.add(f);
                }
            }
    
        }
        return topFragments;
    }
    
    @Nullable
    private Fragment getTopFragment(FragmentManager manager) {
        List<Fragment> fragments = manager.getFragments();
        if (fragments == null) {
            return null;
        }
        int size = fragments.size();
        for (int i = size - 1; i >= 0; i--) {
            Fragment f = fragments.get(i);
             if (f.isAdded() && !f.isHidden() && f.getUserVisibleHint()) {
                Fragment tTopFragment = getTopFragment(f.getChildFragmentManager());
                return tTopFragment == null ? f : tTopFragment;
            }
        }
        return null;
    }
    

    弹出显示

    到这里,就可以拿到一个栈顶 Fragment 的集合了,比如说如果是两层嵌套(Activity -> parentFragment -> childFragment )的话,这个集合中就是 childFragment 。那么又怎么回溯上去获取到这么一个层级关系呢?简单说这个就是找爸爸的步骤啦。在 Fragment 中有一个 getParentFragment() 的方法,通过该方法,就可以将爸爸们全部找出来了。只是这里是倒序的(Activity -> childFragment -> parentFragment ),我们最终的效果需要是正序的,所以还需要反转一下集合。

    List<Fragment> topFragments = getTopFragments();
    if (topFragments == null) {
        sb.append(context.getClass().getSimpleName());
        dialog.setMessage(sb.toString());
        dialog.show();
        //只有Activity不包含Fragment
        return;
    }
    //从最top的Fragment回溯parent,到了root的时候结束。
    ArrayList<Fragment> names;
    for (Fragment topFragment : topFragments) {
        //Glide 使用Fragment来控制相关的request,不再考虑的范围内
        if (GLIDE_FRAGMENT.equals(topFragment.getClass().getName())) {
            continue;
        }
        //先添加Activity的名称
        sb.append(context.getClass().getSimpleName());
        names = new ArrayList<>();
        //倒序找ParentFragment
        while (topFragment != null) {
            names.add(0, topFragment);//反转顺序
            topFragment = topFragment.getParentFragment();
        }
        int length = names.size();
        for (int i = 0; i < length; i++) {
            Fragment name = names.get(i);
            sb.append("\n");
            for (int j = 0; j <= i; j++) {
                sb.append("    ");
            }
            sb.append(name.getClass().getSimpleName());
        }
        sb.append("\n\n");
    
    }
    if (sb.length() == 0) {
        sb.append(context.getClass().getSimpleName());
    }
    dialog.setMessage(sb.toString());
    dialog.show();
    

    特殊情况处理

    使用 Glide 加载图片的时候,它默认会添加一个没有页面的 SupportRequestManagerFragment 来获取相关生命处理相关的图片加载,所以它是需要我们过滤掉的。

    另外,如果某一个页面不需要或者相关功能和摇一摇是冲突的话,这里提供了一个 isEnable 的字段来控制当前页面是否支持摇一摇的功能。

    最后,就是我们如何方便调用相关的功能呢?这里对外提供了相关的方法:

    private ShakeHelper(Context context) {
        this.context = context;
        dialog = new AlertDialog.Builder(context).create();
        dialog.setOnDismissListener(this);
        sb = new StringBuilder();
        if (context instanceof FragmentActivity) {
            manager = ((FragmentActivity) context).getSupportFragmentManager();
        }
    }
    
    //摇一摇是否可用,默认可用
    public void setEnable(boolean enable) {
        isEnable = enable;
    }
    
    //获取摇一摇的实例
    public static ShakeHelper initShakeHelper(Context context) {
        return new ShakeHelper(context);
    }
    
    //回调Activity的onStart()
    public void onStart() {
        //获取 SensorManager 负责管理传感器
        mSensorManager = ((SensorManager) context.getSystemService(Context.SENSOR_SERVICE));
        if (isEnable && mSensorManager != null) {
            //获取加速度传感器
            Sensor mAccelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
            if (mAccelerometerSensor != null) {
                mSensorManager.registerListener(this, mAccelerometerSensor, SensorManager.SENSOR_DELAY_UI);
            }
        }
    }
    
    //回调Activity的onPause()
    public void onPause() {
        if (mSensorManager != null) {
            mSensorManager.unregisterListener(this);
        }
    }
    

    相关源码下载

    戳我

    ---- Edit By Joe At 2017 02 13 ----

    相关文章

      网友评论

        本文标题:Android开发小工具-摇一摇显示当前页面信息

        本文链接:https://www.haomeiwen.com/subject/bzdaittx.html