Android开发问题集锦(2023.09.20更新)

  1. 生成类库的jar文件
通常情况下,我们需要把一个类库打包成一个**Jar**文件,而不是**aar**文件,因此我们需要对app.gradle进行修改,如下所示:
task makeJar(type: Copy){
    delete 'build/libs/CrashCatcher.jar'
    from('build/intermediates/bundles/release/')
    into('build/libs')
    include('classes.jar')
    rename('classes.jar', 'CrashCatcher.jar')
}

makeJar.dependsOn(build)
配置好后,即可通过gradle生成我们想要的jar文件。
  1. 如何处理Linux不能启用AVD的问题?

First, install some packages and libs:
$ sudo apt-get install lib64stdc++6:i386
$ sudo apt-get install mesa-utils

Second, tweak some links:
$ cd YOURPATH/Android/Sdk/tools/lib64
$ mv libstdc++/ libstdc++.bak
$ ln -s /usr/lib64/libstdc++.so.6 libstdc++
Third, relaunch your AVD device and test it.

3.遇到异常【A problem occurred starting process 'command 'E:\Tools\sdk\ndk-bundle\toolchains\mips64el-linux-android-4.9\prebuilt\windows-x86_64\bin\mips64el-linux-android-strip''】处理办法 , windows下异常

处理办法:修改项目根目录的local.properties文件中ndk.dir的值,
如下,原值是:

ndk.dir=E\:\\Tools\\sdk\\ndk-bundle

修改为:

ndk.dir=E\:\\Tools\\sdk\\ndk-bundle.cmd

再次编辑即可正常,但是可能下次进入项目时还会报一样的错误,同样处理即可!

  1. 网络安全配置, 有时候我们可能会网络不可访问的时候,可以进行一下配置

在Manifest.xml中的Application节点中配置network_security_config:

android:networkSecurityConfig="@xml/network_security_config"

配置文件(network_security_config.xml)内容如下:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>
  1. Android 9.0的WebView打开URL页面,报错:ERR_CLEARTEXT_NOT_PERMITTED

需要在Manifest.xml中的Application节点中配置属性:

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:usesCleartextTraffic="true"
        ...>
        ...
    </application>
</manifest>
  1. 32位SO库与64位SO库不匹配时,又不能找到64位SO库,只能去掉64位SO库的引用,以免运行时报错,所以做一下处理
android {
      ........
       packagingOptions {
        exclude 'lib/arm64-v8a/*'
       }
        ........
}
  1. 处理Linux系统上出现的/dev/kvm权限问题

当我们想要运行模拟器的时候,出现以上问题,该怎么处理呢?首先我们先查看一下/dev/kvm所在权限组:

ls -l /dev/kvm

我们可能会得到类似于这样的结果:
crw-rw---- 1 root kvm 10, 232 2月 15 09:22 /dev/kvm
就结果而看,我们的/dev/kvm属于root用户的kvm组

怎么把当前用户加入kvm组呢?首先安装一个软件:

sudo apt install qemu-kvm

执行安装完成后,我们添加用户到组

sudo adduser UserName kvm

添加完成后即可,然后重启电脑!

  1. AndroidStudio就开始打开项目了,这个过程会比较缓慢,有时,AS会出现如下信息:


    提示信息

1). 在/etc/sysctl.conf 文件末尾中添加如下代码:

fs.inotify.max_user_watches = 524288

2). 然后在终端执行以下命令:

sudo sysctl -p --system

最后重启AS

  1. 如何获取手机的存储设备目录

Android N 提供了StorageManager类,并开放了StorageVolume类的部分方法,因此可以使用一下方法可以靠谱的获得相关路径和信息。

10.如何保存文件到手机并同步资源

看示例代码:

 /**
     * 保存到本地
     * @param fileName 文件名
     */
    @SuppressLint("Recycle")
    private fun saveToLocal(fileName: String, bitmap: Bitmap): Boolean {
        try {
            var newFileName = fileName
            var isOriginalExists = true
            val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null,
                    "${MediaStore.Images.Media.DISPLAY_NAME} like ?", arrayOf(fileName), null)
            if (cursor != null && cursor.count > 0) {
                if (cursor.moveToNext()) {
                    isOriginalExists = contentResolver.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                            "${MediaStore.Images.Media._ID}=?",
                            arrayOf(cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media._ID)).toString())) <= 0
                }
            }
            cursor?.close()
            if (isOriginalExists) newFileName = "${System.currentTimeMillis()}_$fileName"
            val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, ContentValues().apply {
                @Suppress("DEPRECATION")
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                    put(MediaStore.Images.Media.RELATIVE_PATH, "DCIM/Pictures")
                else {
                    val dir = when (Environment.MEDIA_MOUNTED) {
                        Environment.getExternalStorageState() ->
                            Environment.getExternalStorageDirectory().absolutePath
                        else -> cacheDir.absolutePath
                    }
                    put(MediaStore.Images.Media.DATA,
                            File("${dir}/DCIM/Pictures", newFileName).absolutePath)
                }
                put(MediaStore.Images.Media.DISPLAY_NAME, newFileName)
                put(MediaStore.Images.Media.DESCRIPTION, newFileName)
                put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
            })
            if (uri != null) {
                val oos = contentResolver.openOutputStream(uri)
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, oos)
                oos?.flush()
                oos?.close()
                return true
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }

11.如何解决错误: android studio 3 字节的 UTF-8 序列的字节 3 无效。(3 �ֽڵ� UTF-8 ���е��ֽ� 3 ��Ч��)

  1. 配置IDE file-coding 都为 UTF-8;
  2. 配置IDE vmOptions-Dfile.encoding=UTF-8;
  3. 配置 app.gradle
     compileOptions {
         encoding 'UTF-8' //设置为UTF-8
         .... //其他配置
     }
    

12.如何播放本地视频,且不黑屏。 推荐使用TextureView+MediaPlayer+Surface


  private var mTexture: TextureView? = null

  private var mPlayer: MediaPlayer? = null

  private var mSurface: Surface? = null

  private var mVideoUri: Uri? = null

  private var mListener: OnmPlayerStateChangedListener? = null

  constructor(context: Context) : super(context)

  constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

  constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
      context,
      attrs,
      defStyleAttr
  )

  constructor(
      context: Context,
      attrs: AttributeSet?,
      defStyleAttr: Int,
      defStyleRes: Int
  ) : super(context, attrs, defStyleAttr, defStyleRes)

  fun setOnPlayerStateChangedListener(listener: OnmPlayerStateChangedListener) {
      this.mListener = listener
  }

  var videoUri: Uri?
      get() = mVideoUri
      set(value) {
          mVideoUri = value
      }

  fun initializer(context: Context) {
      mTexture = TextureView(context).apply {
          layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
          surfaceTextureListener = this@CustomVideoView
      }
      addView(mTexture)
  }

  override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
      if (mVideoUri == null)
          throw Exception("请首先设置播放源")
      mSurface = Surface(surface)
      PlayerThread(mVideoUri!!).start()
      mListener?.onStarted()
  }

  override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {}

  override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
      onReleasemPlayer()
      mTexture = null
      mSurface = null
      return true
  }

  override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {}

  fun onReleasemPlayer() {
      try {
          if (mPlayer != null) {
              if (mPlayer?.isPlaying == true)
                  mPlayer?.pause()
              mPlayer?.stop()
              mPlayer?.release()
          }
          mPlayer = null
      } catch (e: Exception) {
          Log.e("CustomVideoView", e.message)
      } finally {
          mListener?.onReleased()
      }
  }

  /**
   * 使视频适配屏幕
   * @param textureWidth Texture宽度
   * @param textureHeight Texture高度
   */
  private fun stretchingVideoSize(textureWidth: Float, textureHeight: Float) {
      val matrix = Matrix()
      val videoWidth = mPlayer?.videoWidth ?: return
      val videoHeight = mPlayer?.videoHeight ?: return
      val scaleX = textureWidth / videoWidth
      val scaleY = textureHeight / videoHeight
      val originScaleX = videoWidth / textureWidth
      val originScaleY = videoHeight / textureHeight
      matrix.preScale(originScaleX, originScaleY)
      val maxScale = maxOf(scaleX, scaleY)
      matrix.preScale(maxScale, maxScale)
      mTexture?.setTransform(matrix)
      mTexture?.postInvalidate()
  }

  private inner class PlayerThread(private val uriSource: Uri) : Thread() {

      override fun run() {
          try {
              mPlayer = MediaPlayer().apply {
                  setDataSource(context, uriSource)
                  setSurface(mSurface)
                  setAudioAttributes(
                      AudioAttributes.Builder()
                          .setLegacyStreamType(AudioManager.STREAM_MUSIC)
                          .build()
                  )
                  setOnPreparedListener {
                      it?.start()
                      if (context is Activity) (context as Activity).runOnUiThread {
                          val textureWidth =
                              mTexture?.measuredWidth?.toFloat() ?: return@runOnUiThread
                          val textureHeight =
                              mTexture?.measuredHeight?.toFloat() ?: return@runOnUiThread
                          stretchingVideoSize(textureWidth, textureHeight)
                      }
                  }
                  setOnCompletionListener { mListener?.onCompleted() }
              }
              mPlayer?.prepare()
          } catch (e: Exception) {
              Log.e("CustomVideoView", "播放视频失败$e")
          }
      }
  }
  1. android界面置灰效果实现
        val paint = Paint()
        val cm = ColorMatrix()
        cm.setSaturation(0f)
        paint.colorFilter = ColorMatrixColorFilter(cm)
        window.decorView.setLayerType(View.LAYER_TYPE_HARDWARE, paint)
  1. WebView与Native交互,通过js方法获取的Html内容携带unicode字段,如何处理?
Gson().fromJson("html-unicode", String::class.java) //这样能去掉乱码

如果是Flutter又该如何处理?可以考虑在js中把数据URIComponentEncode(), 取出来用时,使用Flutter的Uri.componentDecode().trim(start|end, "")去掉头尾的双引号。

Enjoy yourself !

如果能帮到您,请点赞,谢谢!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容