一个由AndroidAutoSize导致获取状态栏高度不准确的问题

1. 问题描述

公司的项目中引入了JessYan大佬的AndriodAutoSize框架,作为适配设计图尺寸的解决方案。

由于项目是作为带UI的SDK提供给第三方客户集成,在客户集成的过程中发现他们自身的APP在获取状态栏高度时,获取的高度值变小了。下面是集成方的代码:

java 复制代码
/**
 * context是Activity的实例
 */
public static int getstatusBarHeight(context context) {
    // 获得状态栏高度
    int resourceId = context.getResources().getIdentifier( name: "status_bar_height", defype: "dimen", defpackage: "android");
    return context.getResources().getDimensionPixelSize(resourceId);
}

我第一时间就怀疑可能是AndroidAutoSize框架导致的,然后我就写了个demo去尝试复现问题

2. 问题复现

模拟项目中AutoSize的初始化方法:

kotlin 复制代码
    AutoSizeConfig.getInstance().unitsManager  
        .setSupportDP(false)  
        .setSupportSP(false).supportSubunits = Subunits.PT

设置不支持DP和SP,使用子单位PT,然后在一个Activity中获取状态栏高度

kotlin 复制代码
class StatusBarActivity : AppCompatActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContentView(R.layout.activity_status_bar)  
  
        val resourceId: Int = resources.getIdentifier("status_bar_height", "dimen", "android")  
        if (resourceId > 0) {  
            val height = resources.getDimensionPixelSize(resourceId)  
            Log.i("Test", "status_bar_height: $height")  
            Log.i("Test", "status_bar_height: ${ScreenUtils.getStatusBarHeight()}")  
        }
    }
}

运行后的输出结果为:

status_bar_height:49 // 经过AutoSize适配过后的状态栏高度

status_bar_height:99 // 真实的状态栏高度

暂时先不管ScreenUtils.getStatusBarHeight()这个方法,只需要知道这个方法获取的状态栏高度是真实的高度即可,后面再解释原因。 接下来针对AndroidAutoSize的源码来定位问题

3. 问题分析

直接从源码入手,寻找问题根本原因。

首先,找初始化的位置

java 复制代码
AutoSizeConfig init(final Application application, boolean isBaseOnWidth, AutoAdaptStrategy strategy) {
    // 这里只放了针对我遇到问题的关键代码,其他源码可以直接在github中查看
    mActivityLifecycleCallbacks = new ActivityLifecycleCallbacksImpl(strategy == null ? new WrapperAutoAdaptStrategy(new DefaultAutoAdaptStrategy()) : strategy);
    application.registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks);
}

这里是初始化AutoSize的位置,具体调用该方法的地方在一个叫InitProviderContentProvider中,具体就不再展示了,不是解决本文中提到问题的重点。

先来看下ActivityLifecycleCallbacksImpl类,该类的部分源码如下:

java 复制代码
public class ActivityLifecycleCallbacksImpl implements Application.ActivityLifecycleCallbacks {

    private AutoAdaptStrategy mAutoAdaptStrategy;
    
    public ActivityLifecycleCallbacksImpl(AutoAdaptStrategy autoAdaptStrategy) {  
        mFragmentLifecycleCallbacks = new FragmentLifecycleCallbacksImpl(autoAdaptStrategy);  
        mAutoAdaptStrategy = autoAdaptStrategy;  
    }
    
    @Override  
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {  
        
        // 这里就是实际进行适配的位置  
        if (mAutoAdaptStrategy != null) {  
            mAutoAdaptStrategy.applyAdapt(activity, activity);  
        }
    }
    @Override  
    public void onActivityStarted(Activity activity) {  
        if (mAutoAdaptStrategy != null) {  
            mAutoAdaptStrategy.applyAdapt(activity, activity);  
        }  
    }
    /**  
     * 设置屏幕适配逻辑策略类  
     *  
     * @param autoAdaptStrategy {@link AutoAdaptStrategy}  
     */  
    public void setAutoAdaptStrategy(AutoAdaptStrategy autoAdaptStrategy) {  
        mAutoAdaptStrategy = autoAdaptStrategy;  
        mFragmentLifecycleCallbacks.setAutoAdaptStrategy(autoAdaptStrategy);  
    }
}
java 复制代码
public interface AutoAdaptStrategy {  
  
    /**  
     * 开始执行屏幕适配逻辑  
     *  
     * @param target 需要屏幕适配的对象 (可能是 {@link Activity} 或者 {@link Fragment})  
     * @param activity 需要拿到当前的 {@link Activity} 才能修改 {@link DisplayMetrics#density}  
     */  
    void applyAdapt(Object target, Activity activity);  
}

ActivityLifecycleCallbacksImpl类实现了Activity生命周期的回调事件,在ActivityonCreate()事件回调中实际调用了applyAdapt方法,进行尺寸的适配。AutoAdaptStrategy是一个接口,只定义了一个applayAdapt方法,这里可以看到采用了适配器模式来进行屏幕的适配逻辑。

再来看AutoAdaptStrategy的初始化,在AutoSizeConfiginit方法中,创建ActivityLifecycleCallbacksImpl对象时,构造方法传入了一个WrapperAutoAdaptStrategy对象。

java 复制代码
public class WrapperAutoAdaptStrategy implements AutoAdaptStrategy {  
    private final AutoAdaptStrategy mAutoAdaptStrategy;  
  
    public WrapperAutoAdaptStrategy(AutoAdaptStrategy autoAdaptStrategy) {  
        mAutoAdaptStrategy = autoAdaptStrategy;  
    }  
  
    @Override  
    public void applyAdapt(Object target, Activity activity) {  
        onAdaptListener onAdaptListener = AutoSizeConfig.getInstance().getOnAdaptListener();  
        if (onAdaptListener != null){  
            onAdaptListener.onAdaptBefore(target, activity);  
        }  
        if (mAutoAdaptStrategy != null) {  
            mAutoAdaptStrategy.applyAdapt(target, activity);  
        }  
        if (onAdaptListener != null){  
            onAdaptListener.onAdaptAfter(target, activity);  
        }  
    }  
}

该类的构造方法接受一个AutoAdaptStrategy对象,这里给出的是默认的DefaultAutoAdaptStrategy。这里的设计采用了装饰器模式 ,在实际的applyAdapt方法执行前后添加了两个事件回调,分别是适配前onAdaptBefore和适配后onAdaptAfter

再来看DefaultAutoAdaptStrategy类:

java 复制代码
public class DefaultAutoAdaptStrategy implements AutoAdaptStrategy {  

    // 部分代码没有展示,与本文问题关系不大
    @Override  
    public void applyAdapt(Object target, Activity activity) {  
        //如果 target 实现 CancelAdapt 接口表示放弃适配, 所有的适配效果都将失效  
        if (target instanceof CancelAdapt) {  
            LogUtils.w(String.format(Locale.ENGLISH, "%s canceled the adaptation!", target.getClass().getName()));  
            AutoSize.cancelAdapt(activity);  
            return;  
        }  

        //如果 target 实现 CustomAdapt 接口表示该 target 想自定义一些用于适配的参数, 从而改变最终的适配效果  
        if (target instanceof CustomAdapt) {  
            LogUtils.d(String.format(Locale.ENGLISH, "%s implemented by %s!", target.getClass().getName(), CustomAdapt.class.getName()));  
            AutoSize.autoConvertDensityOfCustomAdapt(activity, (CustomAdapt) target);  
        } else {  
            LogUtils.d(String.format(Locale.ENGLISH, "%s used the global configuration.", target.getClass().getName()));  
            AutoSize.autoConvertDensityOfGlobal(activity);  
        }
    }  
}

可以看到这里有三种情况,本文中遇到的问题是走了AutoSize.autoConvertDensityOfGlobal(activity)这行代码,其他两种情况是在全局适配的基础上针对某些特定的Activity执行适配或者不适配的操作,这里不再详细解析,github中有详细用法的解释。

我们继续看AutoSize.autoConvertDensityOfGlobal(activity)的执行,重点就在下面的代码里了:

java 复制代码
public final class AutoSize {
    /**  
     * 使用 AndroidAutoSize 初始化时设置的默认适配参数进行适配 (AndroidManifest 的 Meta 属性)  
     * @param activity {@link Activity}  
     */  
    public static void autoConvertDensityOfGlobal(Activity activity) {  
        // 默认以屏幕的宽度作为适配基准
        if (AutoSizeConfig.getInstance().isBaseOnWidth()) {  
            autoConvertDensityBaseOnWidth(activity, AutoSizeConfig.getInstance().getDesignWidthInDp());  
        } else {  
            autoConvertDensityBaseOnHeight(activity, AutoSizeConfig.getInstance().getDesignHeightInDp());  
        }  
    }
    
    /**  
     * 以宽度为基准进行适配  
     *  
     * @param activity {@link Activity}  
     * @param designWidthInDp 设计图的总宽度  
     */  
    public static void autoConvertDensityBaseOnWidth(Activity activity, float designWidthInDp) {  
        autoConvertDensity(activity, designWidthInDp, true);  
    }
    
    /**
     * sizeInDp表示设计图的宽度,以dp为单位
     **/
    public static void autoConvertDensity(Activity activity, float sizeInDp, boolean isBaseOnWidth) {
        // designWidth表示设计图的宽度,副单位的表示,如果没有设置,则取sizeInDp
        float subunitsDesignSize = isBaseOnWidth ? AutoSizeConfig.getInstance().getUnitsManager().getDesignWidth()  
: AutoSizeConfig.getInstance().getUnitsManager().getDesignHeight();  
        subunitsDesignSize = subunitsDesignSize > 0 ? subunitsDesignSize : sizeInDp;

        DisplayMetricsInfo displayMetricsInfo = mCache.get(key);
        if (displayMetricsInfo == null) {  
            if (isBaseOnWidth) {  
                // 计算适配后的density
                targetDensity = AutoSizeConfig.getInstance().getScreenWidth() * 1.0f / sizeInDp;  
            } else {  
                targetDensity = AutoSizeConfig.getInstance().getScreenHeight() * 1.0f / sizeInDp;  
            }  
            float scale = AutoSizeConfig.getInstance().isExcludeFontScale() ? 1 : AutoSizeConfig.getInstance().  
            getInitScaledDensity() * 1.0f / AutoSizeConfig.getInstance().getInitDensity();  
            targetScaledDensity = targetDensity * scale;  
            targetDensityDpi = (int) (targetDensity * 160);  

            if (isBaseOnWidth) {
                // 计算适配后的xdpi
                targetXdpi = AutoSizeConfig.getInstance().getScreenWidth() * 1.0f / subunitsDesignSize; 
            } else {  
                targetXdpi = AutoSizeConfig.getInstance().getScreenHeight() * 1.0f / subunitsDesignSize;  
            }
            // 放入缓存中
            mCache.put(key, new DisplayMetricsInfo(targetDensity, targetDensityDpi, targetScaledDensity, targetXdpi));  

            setDensity(activity, targetDensity, targetDensityDpi, targetScaledDensity, targetXdpi);
        }
}

常规情况下,基于尺寸的转换公式:px = dp * (dpi / 160),需要关注targetDensitytargetDensityDpi

本文中demo的初始化,是默认以屏幕的宽度作为基准,采用了副单位作为适配适配标准,那么后续会主要关注subunitsDesignSize的使用。下面继续看setDensity方法:

java 复制代码
        private static void setDensity(Activity activity, float density, int densityDpi, float scaledDensity, float xdpi) {
            // 忽略对MIUI兼容的代码
            // 针对Activity的displayMetrics进行适配
            DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();  
            setDensity(activityDisplayMetrics, density, densityDpi, scaledDensity, xdpi);
            // 针对Application的displayMetrics进行适配
            DisplayMetrics appDisplayMetrics = AutoSizeConfig.getInstance().getApplication().getResources().getDisplayMetrics();  
            setDensity(appDisplayMetrics, density, densityDpi, scaledDensity, xdpi);
        }
    
        private static void setDensity(DisplayMetrics displayMetrics, float density, int densityDpi, float scaledDensity, float xdpi) {  
            if (AutoSizeConfig.getInstance().getUnitsManager().isSupportDP()) {  
                displayMetrics.density = density;  
                displayMetrics.densityDpi = densityDpi;  
            }  
            if (AutoSizeConfig.getInstance().getUnitsManager().isSupportSP()) {  
                displayMetrics.scaledDensity = scaledDensity;  
            }  
            switch (AutoSizeConfig.getInstance().getUnitsManager().getSupportSubunits()) {  
                case NONE:  
                    break;  
                case PT:  
                    displayMetrics.xdpi = xdpi * 72f;  
                    break;  
                case IN:  
                    displayMetrics.xdpi = xdpi;  
                    break;  
                case MM:  
                    displayMetrics.xdpi = xdpi * 25.4f;  
                    break;  
                default:  
            }  
        }

可以看到,直接修改了activityResources中的displayMetrics,修改了displayMetricsdensitydensityDpi,这样就直接影响了最终px的转换值,保证了不同屏幕尺寸下适配同样的设计度尺寸。

本文中demo设置了supportDp=falsesupportSp=false,使用副单位PT,这是由于我们公司的设计图是以iOS的屏幕尺寸为标准进行设计的。那么修改的就是displayMetrics.xdpi

AndroidAutoSize的源码先分析这里,大概了解了该框架的运行原理,其实就是在修改ActivitydisplayMetrics属性值,从而影响最终px的计算结果,达到适配不同屏幕尺寸的目的。

接下来,我们来看一下获取状态栏高度的代码:

java 复制代码
package android.content.res;
// Resources.java
public int getDimensionPixelSize(@DimenRes int id) throws NotFoundException {  
    final TypedValue value = obtainTempTypedValue();  
    try {  
        final ResourcesImpl impl = mResourcesImpl;  
        impl.getValue(id, value, true);  
        if (value.type == TypedValue.TYPE_DIMENSION) {  
            return TypedValue.complexToDimensionPixelSize(value.data, impl.getDisplayMetrics());  
    }  
        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)  
        + " type #0x" + Integer.toHexString(value.type) + " is not valid");  
    } finally {  
        releaseTempTypedValue(value);  
    }  
}
java 复制代码
// android.util.TypedValue
public static int complexToDimensionPixelSize(int data, DisplayMetrics metrics) {  
    final float value = complexToFloat(data);  
    final float f = applyDimension(  
            (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,  
            value,  
            metrics);  
    final int res = (int) ((f >= 0) ? (f + 0.5f) : (f - 0.5f));  
    if (res != 0) return res;  
    if (value == 0) return 0;  
    if (value > 0) return 1;  
    return -1;  
}

public static float applyDimension(@ComplexDimensionUnit int unit, float value, DisplayMetrics metrics) {  
    switch (unit) {  
        case COMPLEX_UNIT_PX:  
    return value;  
        case COMPLEX_UNIT_DIP:  
    return value * metrics.density;  
        case COMPLEX_UNIT_SP:  
    return value * metrics.scaledDensity;  
        case COMPLEX_UNIT_PT:  
    return value * metrics.xdpi * (1.0f/72);  
        case COMPLEX_UNIT_IN:  
    return value * metrics.xdpi;  
        case COMPLEX_UNIT_MM:  
    return value * metrics.xdpi * (1.0f/25.4f);  
    }  
    return 0;  
}

首先通过resources.getIdentifier获取系统status_bar_height的资源值,然后通过调用resources.getDimensionPixelSize()获取该资源值对应的实际大小,该方法内调用了TypedValue.complexToDimensionPixelSize(),然后调用applyDimension()方法进行实际尺寸的转换。

这里会执行COMPLEX_UNIT_MM这个分支,可以看到它是使用metrics.xdpi进行计算的,那么由于AndroidAutoSize对该值做了修改,就会导致计算得到的值有偏差。

4. 解决方案

解决问题的思路是,能不能告诉AutoSize框架只针对某种Activity进行适配,而不是全局所有Activity都进行适配,这样可以避免影响到集成方的Activity

如何实现呢,由于AutoSize的主要适配逻辑都发生在DefaultAutoAdaptStrategyapplyAdapt方法中,那么我们能不能自己定义一个AutoAdaptStrategy来实现上面的解决思路呢?答案是可以的。

回到ActivityLifecycleCallbacksImpl这个类,其中有一个setAutoAdaptStrategy方法,接收一个AutoAdaptStrategy类型的参数,直接修改ActivityLifecycleCallbacksImplmAutoAdaptStrategy属性,mAutoAdaptStrategyapplyAdapt方法也是实际执行了适配操作。那我们可以把自定义实现的AutoAdaptStrategy实例设置进来。

再来看如何调用ActivityLifecycleCallbacksImplsetAutoAdaptStrategy方法:

java 复制代码
    public AutoSizeConfig setAutoAdaptStrategy(AutoAdaptStrategy autoAdaptStrategy) {  
        mActivityLifecycleCallbacks.setAutoAdaptStrategy(new WrapperAutoAdaptStrategy(autoAdaptStrategy));  
        return this;  
    }

AutoSizeConfig类中提供了一个方法来实现自定义的适配策略类,太棒了!

接下来实现我自己的适配策略类,这里直接展示新的AndroidAutoSize初始化的代码:

java 复制代码
    val myStrategy = object: DefaultAutoAdaptStrategy() {  
        override fun applyAdapt(target: Any?, activity: Activity?) {  
            Log.i("Test", "target: $target, activity: $activity")  
            if (target is IAutoSizeAdaptActivity) {
                super.applyAdapt(target, activity)  
            }  
        }  
    }  
    AutoSizeConfig.getInstance()  
        .setAutoAdaptStrategy(myStrategy)  
        .unitsManager  
        .setSupportDP(false)  
        .setSupportSP(false)  
        .supportSubunits = Subunits.PT  

新增一个接口IAutoSizeAdaptActivity,并让StatusBarActivity实现这个接口,标识该Activity需要进行适配:

kotlin 复制代码
interface IAutoSizeAdaptActivity {  
    // 不需要定义任何方法
}

class StatusBarActivity : AppCompatActivity(), IAutoSizeAdaptActivity {  
    override fun onResume() {  
        super.onResume()  
        val resourceId: Int = resources.getIdentifier("status_bar_height", "dimen", "android") 
        if (resourceId > 0) {  
            val height = resources.getDimensionPixelSize(resourceId)  
            Log.i("Test", "StatusBarActivity status_bar_height: $height")  
        }  
    }
}

我直接继承了AndroidAutoSizeDefaultAutoAdaptStrategy类,这样可以只针对实现了IAutoSizeAdaptActivity接口的Activity进行适配,也就是调用super.applyAdapt方法,执行DefaultAutoAdaptStrategy中的默认适配逻辑。实际项目中,IAutoSizeAdaptActivity也可以替换为一个通用的基类Activity,只要能覆盖所有需要适配的Activity即可。

到此为止,我以为问题解决了。。。然后,并没有,看下面的demo

写一个CustomerActivity模拟客户的使用场景,CustomerActivity不实现IAutoSizeAdaptActivity接口,添加一个按钮,点击后跳转到StatusBarActivity

kotlin 复制代码
class CustomerActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        findViewById<Button>(R.id.btn_jump).setOnClickListener {
            startActivity(Intent(this, StatusBarActivity::class.java))
        }
    }
    override fun onResume() {  
        super.onResume()  
        val resourceId: Int = resources.getIdentifier("status_bar_height", "dimen", "android") 
        if (resourceId > 0) {  
            val height = resources.getDimensionPixelSize(resourceId)  
            Log.i("Test", "CustomerActivity status_bar_height: $height")  
        }  
    }
}

运行Demo,默认进入CustomerActivity,点击跳转到StatusBarActivity,看控制台打印:

CustomerActivity status_bar_height:99

StatusBarActivity status_bar_height:49

目前来看,是没有问题的,当按返回键从StatusBarActivity回到CustomerActivity时,控制台打印了如下日志:

CustomerActivity status_bar_height:49

状态栏高度不对了,这是怎么回事?

经过一系列的源码分析,问题原因找到了。虽然不同的Activity持有的Resources对象不同,但是Resources对象内部的DisplayMetrics属性却是同一个对象,这就导致当AutoSize修改了StatusBarActivityDisplayMetrics时,应用内其他Activity的DisplayMetrics也都被更改了。

那还有没有其他解决方案呢?继续研究AutoSize的源码,发现有两个方法,一个是AutoSizeConfig.getInstance().restart(),一个是AutoSizeConfig.getInstance().stop(activity)stop()方法,可以停止AutoSize的适配,将Activity的DisplayMetrics恢复到初始状态,restart()方法可以重新启动AutoSize的适配。

基于我的项目是提供给客户的带UI SDK,那么一旦进入SDK的范围内,就不再出现集成方的Activity,那么我可以记录Activity栈内的IAutoSizeAdaptActivity的实例数量,当实例从0变为1时,调用AutoSize的restart()方法启动AutoSize的适配,当最后一个IAutoSizeAdaptActivity的实例finish的时候,调用AutoSize的stop()方法,停止AutoSize的适配,恢复到初始状态,这样就可以解决问题了。

  1. 修改IAutoSizeAdaptActivity,把它改为一个抽象类,让StatusBarActivity继承它。
  2. 新建一个AutoSizeActivityManager类,用于存放IAutoSizeAdaptActivity的实例,并控制AutoSize的启动和停止。
kotlin 复制代码
object AutoSizeActivityManager {  
    private val mStack: Stack<IAutoSizeAdaptActivity> = Stack()  
    
    fun addActivity(activity: IAutoSizeAdaptActivity) {  
        if (mStack.isEmpty()) {  
            AutoSizeConfig.getInstance().restart()  
        }  
        mStack.add(activity)  
    }  

    fun removeActivity(activity: IAutoSizeAdaptActivity) {  
        mStack.remove(activity)  
        if (mStack.isEmpty()) {  
            AutoSizeConfig.getInstance().stop(activity)  
        }  
    }  
}

abstract class IAutoSizeAdaptActivity: AppCompatActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        Log.i("Test", "onCreate, $this")  
        AutoSizeActivityManager.addActivity(this)  
    }  

    override fun finish() {  
        Log.i("Test", "finish, $this")  
        AutoSizeActivityManager.removeActivity(this)  
        super.finish()  
    }  
}

再次运行Demo程序,看控制台输出已经正常了:

CustomerActivity status_bar_height:99

StatusBarActivity status_bar_height:49

CustomerActivity status_bar_height:99

到此为止,问题真正解决了。

不过这个方案还不是完美的,因为这里我假定了一旦进入我的UI SDK的范围内,就不会再出现集成方的Activity。如果这个假设不成立,举个例子,CustomerActivity1 -> StatusBarActivity -> CustomerActivity2,当Activity栈中出现这样的调用顺序时,CustomerActivity2获取的状态栏高度也是被AutoSize适配过的。不过这种情况不多见,先作为一个遗留问题吧,如果大家有更好的处理方案,也请在留言区一起讨论。

6. 其他

上面留了一个小尾巴,就是ScreenUtils.getStatusBarHeight()获取到的是真实的系统状态栏高度,是为什么呢? ScreenUtilsAutoSize提供的一个工具类,还是看源码:

java 复制代码
public static int getStatusBarHeight() {  
    int result = 0;  
    try {  
        int resourceId = Resources.getSystem().getIdentifier("status_bar_height", "dimen", "android");  
        if (resourceId > 0) {  
            result = Resources.getSystem().getDimensionPixelSize(resourceId);  
        }  
    } catch (Resources.NotFoundException e) {  
        e.printStackTrace();  
    }  
    return result;  
}

原来跟我们写的代码差不多,唯一的差别处就是,他的resources用的是Resources.getSystem(),这又是个啥呢?

java 复制代码
/**  
* Return a global shared Resources object that provides access to only  
* system resources (no application resources), is not configured for the  
* current screen (can not use dimension units, does not change based on  
* orientation, etc), and is not affected by Runtime Resource Overlay.  
*/  
public static Resources getSystem() {  
    synchronized (sSync) {  
        Resources ret = mSystem;  
        if (ret == null) {  
            ret = new Resources();  
            mSystem = ret;  
        }  
    return ret;  
    }  
}

Resources是Android系统源码,在android/content/res目录下。getSystem方法返回的是mSystem实例,这个实例是一个全局共享的Resources实例,只用来访问系统资源,它并不是applicationresources对象,它不是针对具体某一个Activity的,也不会被修改,哪怕是AutoSize也没法修改它。

原来如此,是AutoSize也动不了的东西。以后获取系统状态栏高度,可以使用这个方法。

5. 总结

当自己开发SDK给第三方集成时,需要注意以下两点

  1. 尽量避免在自己开发的SDK中引入第三方开源的SDK。由于我们公司的项目是提供的带UI的SDK,所以难免会引入一些第三方的开源框架,那么这种情况下也要注意一定要选一些业内非常热门的开源框架,否则容易和集成方产生冲突
  2. 警惕在自己开发的SDK中引入包含全局修改的开源框架。如果必须得引入,一定要注意控制影响范围,否则一旦到了客户集成时发现问题,会显得你很不专业

本文到这里就结束啦,第一次在掘金写技术文章,主要还是记录自己分析问题和解决问题的过程,如果刚好能帮到你,那真是我莫大的荣幸,期待下次再见。

相关推荐
雨白8 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹9 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空11 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭12 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日13 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安13 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑13 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟17 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡18 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0018 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体