一个由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中引入包含全局修改的开源框架。如果必须得引入,一定要注意控制影响范围,否则一旦到了客户集成时发现问题,会显得你很不专业

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

相关推荐
丘狸尾33 分钟前
[cisco 模拟器] ftp服务器配置
android·运维·服务器
van叶~3 小时前
探索未来编程:仓颉语言的优雅设计与无限可能
android·java·数据库·仓颉
Crossoads6 小时前
【汇编语言】端口 —— 「从端口到时间:一文了解CMOS RAM与汇编指令的交汇」
android·java·汇编·深度学习·网络协议·机器学习·汇编语言
li_liuliu8 小时前
Android4.4 在系统中添加自己的System Service
android
C4rpeDime10 小时前
自建MD5解密平台-续
android
鲤籽鲲11 小时前
C# Random 随机数 全面解析
android·java·c#
m0_5485147715 小时前
2024.12.10——攻防世界Web_php_include
android·前端·php
凤邪摩羯15 小时前
Android-性能优化-03-启动优化-启动耗时
android
凤邪摩羯15 小时前
Android-性能优化-02-内存优化-LeakCanary原理解析
android
喀什酱豆腐16 小时前
Handle
android