Android知识Android开发Android技术知识

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

2017-02-13  本文已影响888人  lovejjfg

当项目工程越来越大之后,大家都会觉得维护起来越来越吃力,如果测试或者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 ----

上一篇下一篇

猜你喜欢

热点阅读