Android 小问题 解决汇总

作者: zcwfeng | 来源:发表于2021-09-24 11:23 被阅读0次

    更新提示:
    <更新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

    【持续更新,欢迎关注】

    相关文章

      网友评论

        本文标题:Android 小问题 解决汇总

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