Android保养科

1,921 阅读4分钟

1.日常小病

1.1.郁闷的报错

1.1.1.新版本AS添加三方仓库异常(4.2之后可能更早)

  • 报错信息:Build was configured to prefer settings repositories over project repositories but repository
  • 解决方案:谷歌让新的三方库挪位置~~~所以新的三方库配置要放到setting.gradle中,如下:

setting.png

1.1.2.Gradle仓库报不安全信息

  • 报错信息: Using insecure protocols with repositories.....
  • 解决方案:添加标签allowInsecureProtocol = true,如下
maven {
    allowInsecureProtocol = true
    url '---你的地址--'
}

1.1.3.导入UI妹子给的SVG报错

  • 报错信息:SVG Width (0) and height (0) cannot be <= 0
  • 解决方案:在(app)build.gradledefaultConfig标签下添加如下配置
defaultConfig {
    vectorDrawables.useSupportLibrary = true
}

1.1.4.在Library用引入.aar包,主工程打正式包错误?

  1. 在主工程的根目录创建文件夹LocalLib
  2. LocalLib创建build.gradle文件,同时把.aar包也复制到LocalLib文件夹中
  3. build.gradle添加如下代码:
configurations.maybeCreate("default")
artifacts.add("default",file('你的aar名称.aar'))

4. 把LocalLib以库的形式添加到项目中

include ':LocalLib'

5. 在你的Library引用该库

implementation project(path: ':LocalLib')

1.1.5.导入第三方SDK

导入第三方SDK最好直接把版本号写死,需要更新的时候自己去修改版本号。(反正今天由于 implementation'com.amap.api:3dmap:latest.integration'坑了我一个小时)

1.1.6.使用LitePal的一个坑

在映射实体里千万不要使用静态常量,否则签名包你会发现新大陆~~

1.2.诡异而又正常的事件

1.2.1.PDF解析(Android自带方法)

  • 解析出的图片模糊 分析:单位不统一,Page获取每页尺寸的单位是英镑 方案:使用resources.displayMetrics.densityDpi / 72 * 每页的尺寸

  • 解析出图片被拉伸 分析:默认不限制裁剪区域,会将PDF源文件铺满Bitmap 方案:关注一下PdfRendererrender方法的第二个参数,不要盲目传Null

1.2.2.签名文件没有MD5值

  • 问题原因:新版JDK不支持MD5(神仙打架,咱们遭殃)
  • 解决方案1:
  1. 下载jdk1.8.0_201(我下载的这个版本)
  2. 配置环境变量
  3. 重新运行keytool -v -list -keystore [你的签名文件完全路径]
  • 解决方案2:
  1. 前往微信开放平台下载签名工具
  2. 安装后输入需要获取签名的包名(需要获取签名的APP和签名工具APP要安装在同一手机上)

1.2.3.特殊情况Fragment重叠

  • 问题原因:在Activity异常重建的时候,会走正常的生命周期,同时会自动恢复之前所依附的Fragment,这就会造成有重复的Fragment出现
  • 解决方案:复用重建的Fragment
//1.在AddFragment的时候添加一个Tag
mFragmentTransaction.add(R.id.frameLayout, fragment, "对应唯一的Tag")
//2.在onCreate中进行Fragment复用
override fun onCreate(savedInstanceState: Bundle?) {
    if (savedInstanceState != null) {
        //查询可复用的Fragment,判空后直接复用
        val fragment = supportFragmentManager.findFragmentByTag()
    }
}

1.2.4.静态桌面快捷图标

  • 问题描述:创建好静态桌面图标后,点击图标打开对应Activity。返回直接返回到桌面。
  • 解决方案:多添加一个intent标签,先打开主页面,然后在跳转对应快捷图标的Activity。如下:
<shortcut
    android:enabled="true"
    android:icon="@drawable/ic_collections_black_24dp"
    android:shortcutDisabledMessage="@string/layout_collect"
    android:shortcutId="collection_id"
    android:shortcutLongLabel="@string/layout_collect"
    android:shortcutShortLabel="@string/layout_collect">
    //多加一个Intent标签就会先打开MainActivity,然后打开目标Activity
    <intent
        android:action="android.intent.action.VIEW"
        android:targetClass="你的MainActivity(完整路径)"
        android:targetPackage="你的包名" />
    <intent
        android:action="android.intent.action.VIEW"
        android:targetClass="点击快捷方式需要打开的Activtiy(完整路径)"
        android:targetPackage="你的包名" />
</shortcut>

1.2.5.Paint设置透明度不起作用

  • 问题原因:查看源码发现在设置颜色的时候对mColor这个参数进行直接赋值,而设置透明度是读取了mColor这个参数的RGB后才赋值
  • 解决方案:先设置颜色然后设置透明度,就像这样:
//设置颜色
mTextPaint!!.color = Color.WHITE
//设置透明度(0~255)
mTextPaint!!.alpha = 100

1.2.6.Material Tablayout在平板上无法铺满

  • 问题描述:把Tablayout的宽度设置为match_parent,tabMode属性设置为fixed的情况下。在手机中正常铺满显示,而在平板中却无法铺满,只是居中显示。
  • 解决方法:添加如下标签(基于material:1.2.1)
android:layout_width="match_parent"
app:tabMode="fixed"
app:tabGravity="fill"

1.2.7 图片保存到相册,PictureSelect框架无法显示

这个问题是发生在荣耀9(Android9.0)中,在手机系统相册可以看到,但是在框架里没有。经查询原因是缺少了通知。目前不清楚是机型问题,还是Android版本问题,在Android10以上不需要这条通知也没问题。

context.sendBroadcast(Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://$文件的完整路径")))

1.2.8 应用在后台情况下弹出DialogFragment崩溃问题

  • 问题描述: 当APP在后台运行,此时如果弹出DialogFragment,会发生崩溃,异常信息:java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
  • 解决方案: 用如下代码弹出DialogFragment
public void showAllowingStateLoss(FragmentManager manager, String tag) {
    try {
        Field dismissed = DialogFragment.class.getDeclaredField("mDismissed");
        dismissed.setAccessible(true);
        dismissed.set(this, false);

        Field shown = DialogFragment.class.getDeclaredField("mShownByMe");
        shown.setAccessible(true);
        shown.set(this, true);

        FragmentTransaction ft = manager.beginTransaction();
        ft.add(this, tag);
        ft.commitAllowingStateLoss();
    } catch (NoSuchFieldException | IllegalAccessException e) {
        Log.e(TAG, "showAllowingStateLoss: " + e.getMessage());
    }
}

2.版本带来的新鲜感

2.1.Android 7.0

2.1.1.Android7.0分屏生命周期搞心态

分屏会走生命周期,特定的应用需要。延迟适配可以在清单文件如下配置:

android:resizeableActivity="false"

2.2.Android 8.0

2.2.1.前台Service

  1. 添加权限<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  2. 在服务的onCreate()添加通知
class SimpleService : Service() {
    override fun onCreate() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notification: Notification =Notification.Builder(this, "0-0")
                .setContentTitle("Title")
                .setContentText("Content")
                .setSmallIcon(R.mipmap.ic_launcher)
                .build()
            val notificationChannel =NotificationChannel("0-0", "CHANNEL_ONE_NAME", NotificationManager.IMPORTANCE_MIN)
            val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            manager.createNotificationChannel(notificationChannel)
            startForeground(1, notification)
        }
    }
}

2.3.Android 9.0

2.3.1.网络请求问题

  • 方案1:设置请求方式为https
  • 方案2:做如下配置 在res -> xml目录下创建netword_security文件
<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:android="http://schemas.android.com/apk/res/android">
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

在清单文件application标签下添加配置

<application
    ...
    android:networkSecurityConfig="@xml/netword_security""
    ...
    >
    <activity
        ...
    </activity>
</application>

2.4.Android 10.0

2.4.1.Android10.0快捷适配

想适配但是没时间...那就偷懒吧!清单文件如下配置:

android:requestLegacyExternalStorage="true"

3.日常保养

3.1.小技巧

3.1.1.TextView Medium字重(终究是被IOS支配)

设置如下属性,比较接近Medium字重效果...

TextView.getPaint().setFakeBoldText(true);

3.1.2.播放短暂的音频

播放类似按键音、翻页音的时候选择SoundPool速度更快

3.1.3.TextView内容自动滚动到最后一行(可滑动的TextView)

话不多说,直接上代码。(主要好像也没啥可说的~~~)

private val mRect = Rect()
private val mStringBuild = StringBuilder()

private fun addMessage(msg){
    //添加内容
    mStringBuild.appendLine(msg)
    mTextView.text = mStringBuild
    //计算内容高度
    var contentHeight = 0
    for (i in 0 until mTextView.lineCount) {
        mRect.setEmpty()
        mTextView.getLineBounds(i, mRect)
        contentHeight += mRect.height()
    }
    //TextView高度(如果设置了Padding,记得减去)
    val textViewDisplayHeight = mTextView.height
    if (contentHeight > textViewDisplayHeight) {
        //滑动差值
        mTextView.scrollY = (contentHeight - textViewDisplayHeight)
    }
}

3.1.4.多环境情况配置变量(显著的就是接口)

关键标签buildConfigField() 配置对应环境变量(配置完成后别忘记 Make Project)

buildTypes {
    release {
        minifyEnabled false
        buildConfigField "String", "SERVICE_URL", "\"对应环境的内容\""
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        signingConfig signingConfigs.release
    }
    debug {
        buildConfigField "String", "SERVICE_URL", "\"对应环境的内容\""
    }
}

在需要的位置调用BuildConfig.SERVICE_URL即可

3.1.5.自定义生成APK名称

在Appbuild.gradleandroid标签最后添加如下内容

def getTime() {
    return new Date().format("yyyyMMdd_HH-mm", TimeZone.getDefault())
}
android{
    //-------------我是省略号-------------
    buildTypes {
    //-------------我是省略号-------------
    }
    //-------------我是省略号-------------

    android.applicationVariants.all {
        variant ->
            variant.outputs.all {
                if ('debug' == variant.buildType.name) {
                    outputFileName = "debug.apk"
                }
                if ('release' == variant.buildType.name) {
                    outputFileName = "release-v${variant.versionName}-${getTime()}.apk"
                }
        }
    }
}

3.2.特殊控件

3.2.1.TextClock快速实现数字时钟,具体请查看

3.3.便捷工具