Android 手机兼容Android 知识

Android 小问题 解决汇总

2021-09-24  本文已影响0人  zcwfeng

更新提示:
<更新19,关于新硬件支撑刷新率90Hz,120Hz fps>
<更新20,沉浸式和fitSystemWindows 配合解决方案>
<更新21,加速Android Studio 编译的插件>

1. IllegalStateException: Can not perform this action after onSaveInstanceState

Fatal Exception: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at androidx.fragment.app.FragmentManager.checkStateLoss(FragmentManager.java:1844)
at androidx.fragment.app.FragmentManager.enqueueAction(FragmentManager.java:1884)
at androidx.fragment.app.BackStackRecord.commitInternal(BackStackRecord.java:329)
at androidx.fragment.app.BackStackRecord.commit(BackStackRecord.java:294)
at com.amfun.home.fragment.HomeFragment.initView(HomeFragment.java:124)
at com.amfun.common.mvvm.BaseFragment.onCreateView(BaseFragment.java:79)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963)

可能的原因之一:

Fragment 在显示或者隐藏,移除是出现Can not perform this action after onSaveInstanceState #解决办法:onSaveInstanceState方法是在该Activity即将被销毁前调用,来保存Activity数据的,如果在保存玩状态后 再给它添加Fragment就会出错。解决办法就是把commit()方法替换成 commitAllowingStateLoss()

可能的原因之二:Activity被系统回收之后,重建时恢复缓存的Fragment的原因 #解决办法之一:在Activity 回收时 onSaveInstanceState 中不缓存Fragment ,在OnCreate 中移除缓存相应Fragment数据,代码如下

    private static final String BUNDLE_FRAGMENTS_KEY = "android:support:fragments";
   
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        if (savedInstanceState != null && this.clearFragmentsTag()) {
            //重建时清除 fragment的状态
            savedInstanceState.remove(BUNDLE_FRAGMENTS_KEY);
        }
        super.onCreate(savedInstanceState);
    }
 
 
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (outState != null && this.clearFragmentsTag()) {
            //销毁时不保存fragment的状态
            outState.remove(BUNDLE_FRAGMENTS_KEY);
        }
    }
 
    protected boolean clearFragmentsTag() {
        return true;
    }

2. File not found ,或者读取相册缓慢

Android 10 的权限兼容问题
描述更清晰,在做相册视频选择的时候,列表获取失败anr,获取置顶视频文件找不到的情况
检查其他应用,微博,小红书,抖音都正常,用的第三方库也是正常。那么这个时候考虑系统权限等兼容

解决,在Application中加入android:requestLegacyExternalStorage="true" 类似我们要访问指定安全域名android:networkSecurityConfig

<application
       
        android:networkSecurityConfig="@xml/network_security_config"
        android:requestLegacyExternalStorage="true"

3. 关于启动Activity和退出Activity的动画添加,我先换叫Controller,为了和iOS保持一致

你可能也遇到过,不懂得系统的设计师,非要和iOS保持一致,不得已自己覆盖系统启动Activity的动画。
这是一个简单问题,但是又比较烦。

我这里就简单的记录一下,通用主题的方案,不再用代码一个一个侵入代码Base类。如果设计师花样频出,你就没办法,用base类封装吧。

主题添加,动画添加,网上的你还有调试,根据这个不需要太多调试,尤其是csdn没法看

「slide_in_right_anim.xml」从右侧启动进入 《-

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="300"
        android:fromXDelta="50%p"
        android:toXDelta="0" />
    <alpha
        android:duration="300"
        android:fromAlpha="1.0"
        android:toAlpha="1.0" />
</set>

「slide_out_left_anim.xml」从右侧滑动退出。 -》

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="300"
        android:fromXDelta="0"
        android:toXDelta="100%p" />
    <alpha
        android:duration="300"
        android:fromAlpha="1.0"
        android:toAlpha="1.0" />
</set>

满足那个经验不足的设计需求,非资质设计师。

ps:警告特殊情况会因为这个影响你的性能。

4. ViewPager 需求不要滑动,但是可能会闪动,解决问题

通常禁止滑动的需求,如果有显示隐藏动态Gone掉也会有问题,所以会禁止滑动。

public class CustomViewPager extends ViewPager {
    private boolean isCanScroll = true;

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomViewPager(Context context) {
        super(context);
    }

    public void setCanScroll(boolean isCanScroll) {
        this.isCanScroll = isCanScroll;
    }

    @Override
    public boolean onTouchEvent(MotionEvent arg0) {
        if (isCanScroll) {
            return super.onTouchEvent(arg0);
        } else {
            return false;
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) {
        if (isCanScroll) {
            return super.onInterceptTouchEvent(arg0);
        } else {
            return false;
        }
    }


    @Override
    public void setCurrentItem(int item, boolean smoothScroll) {

        super.setCurrentItem(item, smoothScroll);
    }

    @Override
    public void setCurrentItem(int item) {

        super.setCurrentItem(item, false);
    }
}

5. 关于息屏,常用简单解决。

场景是在 Activity中,进行播放等活动,超出系统设置最大息屏时间,保持亮屏播放
onCreate 函数添加

 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

6. Recyclerview 嵌套时, item点击事件处理,子Recyclerview不响应父Recyclerview的点击 ----CymChad 的Kotlin版本的BaseQuickAdapter

参考:https://github.com/cymchad/baserecyclerviewadapterhelper/issues/2516 这个文章解决一些你可能有的问题。

明确一个点击问题,就是需要现在外层adapter,把item的点击需要的事件加入

init {
        addChildClickViewIds(R.id.iv_nice_head)
        addChildClickViewIds(R.id.player_container)
        addChildClickViewIds(R.id.prepare_view)
    }

然后在adapter调用

mHomeListAdapter.setOnItemChildClickListener((adapter, view12, position) -> {
  if (view12.getId() == R.id.iv_nice_head) {
  ...
  }
...
}

7. chrome 无法直接播放m3u8视频。

安装插件
native-hls-playback
去chrome商店搜索


11.12.59.png

8. 代码注释乱,structure里面查找代码困难

参考了SmartRefreshlayout的注视,了解了这个奇技淫巧
包装了代码块后,直接不用看代码,就能知道折叠部分的功能

 //<editor-fold desc="功能属性">
.......code.....
  //</editor-fold>

9. E/RecyclerView: No layout manager attached; skipping layout

有时候我们写代码或者提交冲突,导致疏忽,这个只能解决一般性问题。

  //必须先设置LayoutManager
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);

10.Firebase uploadCrashlyticsMappingFileRelease 失败 解决方法

会出现莫名其妙的打包失败现象,打包失败,关闭自动上传

buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled true
            //zipAlignEnabled 优化
            zipAlignEnabled true
            // 设置是否要自动上传
            firebaseCrashlytics {
                mappingFileUploadEnabled false
            }
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }

        debug {
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            minifyEnabled false
            versionNameSuffix "_debug"
        }
    }

11. Facebook 推广应用,在Android上面的测试问题

这个问题其实,以前遇到过,但是,最近又遇到这种问题验证,慌了一下。

》1 广告推官人员,给你一个测试链接,就是一个短链接,内容是自己定义的协议。
需要在浏览器打开,然后跳转到Facebook的app内部。这个时候问题出现了,我看不到fb 的官网广告测试怎么办。
到浏览器打开,这个链接,登陆,然后点击,显示广告,到fb 的app看,这个时候有广告。因为fb在手机上的缓存做的太严重了,导致会出现刷新一次广告,下次就没有了的问题。借助浏览器,容易清理缓存的机制,可以作为广告工具辅助测试。

》2 发现点击广告----〉跳转到GooglePlay下载,安装后ApplinkData回掉是空的。
那么问题解决:
需要按照步骤来,清理浏览器缓存,杀死fb的应用进程。到pc浏览器,打开广告推广发给你的链接测试,pc浏览器点击显示广告,到fb的app查看广告,---->点下载-----》重点来了,这个时候是在fb的app内部弹出GooglePlay,《----这样才会被Deeplink标记,下载打开,才会出现ApplindData回调数据。解析数据完成业务。

说了这么多,这个ApplinkData是干什么的,就是花钱投广告,通过广告下载GooglePlay的应用,应用内你知道是Deeplink方式过来的,后台统计数据,用来分桶测试,还有测试应用的市场效果。

12. 手上没有足够分辨率手机测试怎么办,可以借助adb工具实现

通常我们测试分辨率,需要用各种手机,其实没有那么麻烦

进入adb

默认的分辨率查看

wm size
$ wm size 1920x1280 (小写的x)修改分辨率

查看dpi

wm density

修改dpi

wm density 240 修改dpi

重置

$ wm size reset
$ wm density reset

12. DialogFragment 或者一些弹窗中,需要滑动关闭的时候

算不上问题和bug,但是是个小的细节。尤其是产品要求和iOS的效果一致

view.setOnTouchListener((v, event) -> {
            float y = event.getRawY();
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    lastY = event.getRawY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    offsetY = y - lastY;
                    if (offsetY > 0) {
                        ViewHelper.setTranslationY(view, offsetY);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    if (offsetY > 0) {
                        if (offsetY < view.getHeight() / 3) {
                            ViewHelper.setTranslationY(view, 0f);
                        } else {
                            dismiss();
                        }
                    }
                    break;
                default:
                    break;

            }
            return true;
        });

13. network 获取网络信息,Android个种改系统源码,不兼容

问题:

错误的获取

 ConnectivityManager connectionManager = (ConnectivityManager) RouteForMeApplication.getInstance()
            .getSystemService(Context.CONNECTIVITY_SERVICE);
    if (connectionManager == null) return false;
    boolean networkAvailable = connectionManager.getActiveNetworkInfo() != null
            && connectionManager.getActiveNetworkInfo().isConnected();
    return networkAvailable;

Kotlin 修正,更改调用api



class NetworkUtilsKt {

    private var isAvailable = false
    private val context = BaseApplication.getInstance().applicationContext
    private var macAddress: String = ""
    private var ipAddresses: String = ""
    /**
     * 判断是否有网络
     *
     * @return
     */
    fun isNetworkConnected(): Boolean {
        return isAvailable
    }

    fun getMacAddress(): String{
        return macAddress
    }

    fun getIpAddress(): String{
        return ipAddresses
    }

    /**
     * 将ip的整数形式转换成ip形式
     *
     * @param ipInt
     * @return
     */
    private fun int2ip(ipInt: Int): String{
        val sb = StringBuilder()
        sb.append(ipInt and 0xFF).append(".")
        sb.append(ipInt shr 8 and 0xFF).append(".")
        sb.append(ipInt shr 16 and 0xFF).append(".")
        sb.append(ipInt shr 24 and 0xFF)
        return sb.toString()
    }

    private fun convertToMac(mac: ByteArray?): String {
        var str: String = ""
        try {
            val sb = java.lang.StringBuilder()
            for (i in mac?.indices!!) {
                val b = mac[i]
                var value = 0
                when {
                    b in 0..16 -> {
                        value = b.toInt()
                        sb.append("0" + Integer.toHexString(value))
                    }
                    b > 16 -> {
                        value = b.toInt()
                        sb.append(Integer.toHexString(value))
                    }
                    else -> {
                        value = 256 + b
                        sb.append(Integer.toHexString(value))
                    }
                }
                if (i != mac.size - 1) {
                    sb.append(":")
                }
            }
            str = sb.toString()
            if (str.startsWith("0:")) {
                str= "0$str"
            }
        } catch (e: Exception) {
            KLog.e(Constant.DebugKeyInfo.filter_exception, e.toString())
        }
        return str
    }

    init {

        val connectivityManager = context
            .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val request = NetworkRequest.Builder().build()
        connectivityManager.registerNetworkCallback(request,object : ConnectivityManager.NetworkCallback(){
            override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {}


            override fun onCapabilitiesChanged(
                network: Network,
                networkCapabilities: NetworkCapabilities
            ) {
                KLog.i(Constant.DebugKeyInfo.filter_exception, "net status change! 网络连接改变")
                parseNetworkCapabilities(networkCapabilities)
            }

            override fun onLost(network: Network) {}

            override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {}

            override fun onUnavailable() {
                isAvailable = false
            }

            override fun onLosing(network: Network, maxMsToLive: Int) {}

            override fun onAvailable(network: Network) {
                connectivityManager.getNetworkCapabilities(network)?.also {
                    parseNetworkCapabilities(it)
                }
                isAvailable = true
            }
        })
    }

    @SuppressLint("HardwareIds")
    private fun parseNetworkCapabilities(networkCapabilities: NetworkCapabilities){

        try {

            var networkType = "eth0"
            // 表明此网络连接成功验证
            if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
                if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
                    networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI_AWARE)) {
                    // 使用WI-FI
                    val wifi = context.applicationContext
                        .getSystemService(Context.WIFI_SERVICE) as WifiManager
                    ipAddresses = int2ip(wifi.connectionInfo.ipAddress)
                    networkType = "wlan0"

                } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
                    || networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)){
                    // 使用蜂窝网络
                    // 使用有线网络
                    networkType = "eth0"
                }
            }
            val en: Enumeration<NetworkInterface> =
                NetworkInterface.getNetworkInterfaces()
            while (en.hasMoreElements()) {
                val networkInterface: NetworkInterface = en.nextElement()
                if (networkInterface.displayName.toLowerCase(Locale.getDefault()) ==  networkType){
                    val enumeration: Enumeration<InetAddress> = networkInterface.inetAddresses
                    while (enumeration.hasMoreElements()) {
                        val netAddress: InetAddress = enumeration.nextElement()
                        if (!netAddress.isLoopbackAddress && netAddress is Inet4Address) {
                            ipAddresses = netAddress.hostAddress.toString()
                            macAddress = convertToMac(networkInterface.hardwareAddress)
                            break
                        }
                    }
                }

            }
        } catch (ex: SocketException) {
            KLog.e(Constant.DebugKeyInfo.filter_exception, ex.toString())
        }
    }

    companion object{
        val proxy = NetworkUtilsKt()
    }
}

14. tryGetViewHolderForPositionByDeadline

bug 未能解决

15. Cannot call this method while RecyclerView is computing a layout or scrolling

bug 未能解决

16. 解决获取View位置的问题

  1. 在FragmentActivity中获取
    onWindowFocusChanged()

从字面上就可以知道,这个方法是在窗口焦点发生变化时被调用。
启动一个activity(要注意如果该手机或模拟器处于锁屏状态时,这时只走onCreate()、onStart()、onResume(),不会再走onWindowFocusChanged()
按下home键,再回到activity
从当前activty回到上一个activity
结合activity/fragment生命周期,能得到很多
所以用的频率并不多。

  1. Activity 内部的Fragment想要拿到View的位置在onCreate等拿到的通常都是0
    所以需要在ViewTreeObserver 中获取
 mBinding.bisPlaceholder.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mBinding.bisPlaceholder.getLocationOnScreen(location);
                KLog.e("zcw_", "location:" + location[0] + "," + location[1]);
            }
        });
  1. 我们有几种获取的方式
    第一种:
int location[] = new int[2];
getLocationOnScreen(@Size(2) int[] outLocation) 
或者直接
getLocationInWindow(@Size(2) int[] outLocation) 

用过C++的,应该都熟悉这种套路
第二种:

 Rect rect = new Rect();
 boolean getGlobalVisibleRect(Rect r) 
还有
 boolean getLocalVisibleRect(Rect r)

如上,都是输出到定义的对象中

17 E/DecorView: mWindow.mActivityCurrentConfig is null

这可能是设备问题,可以忽略它。 我已经搜索了几个小时,此时只要错误不会使设备崩溃,您就可以忽略它

18 RecyclerView.setHasFixedSize(true)

setHasFixedSize === true 导致notifyItem系列方法不起作用,
可以用notifyDataSet 刷新。具体api看。提一句

19 关于新硬件支撑刷新率90Hz,120Hz fps

最近遇到同事吐槽,太慢,看到其他家应用都是120Hz fps。所以网上找到了解决方案。
我略微改动

Java 版本

      /*
        M 是 6.0,6.0修改了新的api,并且就已经支持修改window的刷新率了。
        但是6.0那会儿,也没什么手机支持高刷新率吧,所以也没什么人注意它。
        我更倾向于直接判断 O,也就是 Android 8.0,我觉得这个时候支持高刷新率的手机已经开始了。
        */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // 获取系统window支持的模式
            Display.Mode[] modes = getWindow().getWindowManager().getDefaultDisplay().getSupportedModes();

            Display.Mode fpsMode = null;
            for (Display.Mode mode : modes) {
                float fps = mode.getRefreshRate();
                KLog.e("amfun_fps",fps);
                if(fps >= 90){
                    fpsMode = mode;
                    break;
                }
            }

            if(fpsMode != null) {
                WindowManager.LayoutParams layoutParams= getWindow().getAttributes();
                if(layoutParams != null) {
                    layoutParams.preferredDisplayModeId = fpsMode.getModeId();
                }
                getWindow().setAttributes(layoutParams);
            }
        }

Kotlin 版本

/* 
        M 是 6.0,6.0修改了新的api,并且就已经支持修改window的刷新率了。
        但是6.0那会儿,也没什么手机支持高刷新率吧,所以也没什么人注意它。
        我更倾向于直接判断 O,也就是 Android 8.0,我觉得这个时候支持高刷新率的手机已经开始了。
        */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            // 获取系统window支持的模式
            val modes = window.windowManager.defaultDisplay.supportedModes
            // 对获取的模式,基于刷新率的大小进行排序,从小到大排序
            modes.sortBy {
                it.refreshRate
            }

            window.let {
                val lp = it.attributes
                // 取出最大的那一个刷新率,直接设置给window
                lp.preferredDisplayModeId = modes.last().modeId
                it.attributes = lp
            }
        }

在 Activity的onCreate之前调用

关于适配Android 11 的setFrame,我没有找到合适的设置位置和具体如何使用

参考:google android doc

20. fitsSystemWindows和设置沉浸式,对当前布局的insets做一些处理

问题原因:最近在看Compose开源项目,发现每个项目中都在开头用了fitsSystemWindows 等等。所以想起来以前一些沉浸式问题,总结下。

下面两个的区别
1. android:fitsSystemWindows + FragmentLayout
2. android:fitsSystemWindows + CoordinaryLayout

CoordinatorLayout 做了这些事:
        setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

对当前布局的insets做一些处理,并且调用了上面一行代码

fitsSystemWindows 的配合

FragmentLayout 方案 , 因为这里没有像ConstrantLayout 内部的处理inset,所以我们代码要特殊处理下
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/root_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="false"
        android:background="#ff66ff">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/photo"
            android:fitsSystemWindows="true"
            />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button"/>
    </FrameLayout>

用了心的api你会发现,这里很多代码过时了

 window.statusBarColor = Color.TRANSPARENT
// FrameLayout + android:fitsSystemWindows
        val frameLayout = findViewById<FrameLayout>(R.id.root_layout)
        frameLayout.systemUiVisibility = (SYSTEM_UI_FLAG_LAYOUT_STABLE
                or SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
//setOnApplyWindowInsetsListener ()函数去监听WindowInsets发生变化
        val button = findViewById<Button>(R.id.button)
        ViewCompat.setOnApplyWindowInsetsListener(button) { view, insets ->
            val params = view.layoutParams as FrameLayout.LayoutParams
            params.topMargin = insets.systemWindowInsetTop
            insets
        }
    }
ConstraintLayout 的方式似乎代码少些

window.statusBarColor = Color.TRANSPARENT

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff66ff"
    android:fitsSystemWindows="true">

    <com.google.android.material.appbar.CollapsingToolbarLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            android:scaleType="centerCrop"
            android:src="@drawable/photo" />
    </com.google.android.material.appbar.CollapsingToolbarLayout>

    <Button
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />
</androidx.constraintlayout.widget.ConstraintLayout>

完全使用主题解决也许是一个方案,但是复杂的项目问题,并不是唯一好的解决方式

<style name="AppTheme_light_immersive" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowTranslucentStatus">true</item>
        <item name="android:windowTranslucentNavigation">true</item>
        <item name="android:windowNoTitle">true</item>
    </style>

但是在6.0 可能需要代码适配

Window window = activity.getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
        | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
window.setNavigationBarColor(Color.TRANSPARENT);

参考:1 , 2

21. 加速编译的AS 插件,不一定完全有用

RocketXPlugin

22. 老项目升级gradle,涉及到编译不通过问题

排查:

  1. 老规矩,project的gradle 插件升级. gradle-wrapper.properties 的 版本 distributionUrl 升级
  2. 编译排查,各种第三方库,是否有脚本语法错误
  3. 兼容性,通常情况,是第三方工具库导致,无非数据库,图片库,语音库等。
    我这里提一下greendao 必须3.3.0之上。

参考存储文档: https://developer.android.google.cn/training/data-storage?hl=zh-cn

【持续更新,欢迎关注】

上一篇下一篇

猜你喜欢

热点阅读