Android 開發中遇到的 bug(12)

前言

記錄開發中遇到的 bug,不再讓自己重複地被同樣的 bug 折磨。

正文

1. The integer literal does not conform to the expected Int

時間:2020年04月05日17:34:05
問題描述:
在 xml 裏有一個 TextView 控件:

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textSize="40sp"
        android:textColor="@android:color/black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

在代碼裏,希望通過 TextViewsetBackgroundColor() 方法設置其背景爲綠色。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
       textView.setBackgroundColor(0xFF00FF00)
    }
}

但是,在 0xFF00FF00 下面會出現紅色的波浪線,提示信息:The integer literal does not conform to the expected Int.

解決辦法:

當我把光標放在報錯處,使用快捷鍵 ALT + Enter 後,提示我:Convert expression to Int。

執行這個操作後,代碼變爲:

textView.setBackgroundColor(0xFF00FF00.toInt())

爲什麼需要做一下轉換呢?
因爲 0xFF00FF00 賦值給一個變量時,是 Long 類型的:

val color: Long = 0xFF00FF00

在 Kotlin 中,我們需要顯式地進行類型轉換。而在 Java 中,卻不用這樣顯式轉換:

int color = 0xff00ff00;
textView.setBackgroundColor(0xff00ff00);

需要注意的是,下面這樣設置顏色是不會有效果的

textView.setBackgroundColor(0x00FF00)

參考:
Color Int of ARGB in Kotlin
Cannot use argb color int value in Kotlin?

2. 使用 ffmpeg 拼接同一個音樂多次失敗

時間:2020年05月12日17:34:05
開始使用的命令是:

ffmpeg -i "concat:seconds10.mp3|seconds10.mp3" -acodec copy seconds20.mp3

對於 .mp3 的格式,這個命令是成功的; 但是,這個命令在少數情況下,拼接了多段音樂,但是播放的時候卻只有第一段,後面的幾段是沒有聲音的。

使用命令:

ffmpeg -i music.amr -filter_complex "[0:a]afifo[a0];[0:a]afifo[a1];[a0][a1]concat=n=2:v=0:a=1[a]" -map "[a]" result.amr

得到錯誤:

Input #0, amr, from 'music.amr':
  Duration: 00:00:15.96, bitrate: 12 kb/s
    Stream #0:0: Audio: amr_nb (samr / 0x726D6173), 8000 Hz, mono, flt
Automatic encoder selection failed for output stream #0:0. Default encoder for format amr (codec amr_nb) is probably disabled. Please choose an encoder manually.
Error selecting an encoder for stream 0:0

查看文檔 https://trac.ffmpeg.org/wiki/Concatenate#demuxer

拼接相同類型的文件有兩種方法
1.the concat ‘‘demuxer’’
2.the concat ‘‘protocol’’
第一種方式更加靈活——它需要相同的編解碼器,但可以使用不同的容器格式;它可以被用於任何容器格式; 第二種方式僅適用於少數容器。

選用第一種方式:
新建一個 mylist.txt 的文件,寫入內容:

file 'music.amr'
file 'music.amr'
file 'music.amr'

需要注意的是,文件名前後加上單引號(’), 避免文件名中有空格造成拼接錯誤。
輸入命令:

ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.amr

可以正確輸出。

3. 如何使用 ffmpeg 給沒有音頻流的視頻添加靜音音頻?

時間:2020年05月12日17:34:05

在命令行下查看一個沒有音頻流的視頻信息:

(base) wangzhichao@wangzhichao:~/視頻$ ffmpeg -i nuanyangxiajingyin.mp4
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'nuanyangxiajingyin.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.29.100
    comment         : [p:dk][20330][HUAWEI][BTV-DL09][Android 24][i][h][f][2019-12-18_23:11:12]
    copyright       : 42115e51f7b367c8b8438b37ea04c12c
  Duration: 00:00:27.20, start: 0.000000, bitrate: 7666 kb/s
    Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1088x1920, 7664 kb/s, 30 fps, 30 tbr, 1000k tbn, 2000k tbc (default)
    Metadata:
      handler_name    : VideoHandler
At least one output file must be specified

可以看到,這個視頻只有一個視頻流:

Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1088x1920, 7664 kb/s, 30 fps, 30 tbr, 1000k tbn, 2000k tbc (default)

但實際的需求需要給視頻設置音量,如果一個視頻沒有音頻流,再去給它設置音量,會直接崩潰。
所以,需要給沒有音頻流的視頻添加靜音音頻。
參考https://stackoverflow.com/questions/42147512/ffmpeg-adding-silence-struggling-to-use-i-anullsrc-option
,使用命令:

ffmpeg -i nuanyangxiajingyin.mp4 -f lavfi -i anullsrc -c:v copy -c:a aac -shortest nuanyangxiangaudio.mp4

再查看生成的視頻信息:

(base) wangzhichao@wangzhichao:~/視頻$ ffmpeg -i nuanyangxiangaudio.mp4 
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.29.100
    comment         : [p:dk][20330][HUAWEI][BTV-DL09][Android 24][i][h][f][2019-12-18_23:11:12]
    copyright       : 42115e51f7b367c8b8438b37ea04c12c
  Duration: 00:00:27.21, start: 0.000000, bitrate: 7670 kb/s
    Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1088x1920, 7664 kb/s, 30 fps, 30 tbr, 1000k tbn, 2000k tbc (default)
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 2 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
At least one output file must be specified

可以看到生成的視頻裏包含了音頻流:Stream #0:1(und): Audio。

4. 如何把指定的位置自動滑動到屏幕中間,免去手動滑動列表去尋找選中條目的麻煩?

時間:2020年05月12日17:34:05

參考:https://blog.csdn.net/iblade/article/details/90449089

5. 解決 OOM 的思路

時間:2020年05月12日17:34:05

發現應用在一個性能差的手機上會報出各種 OOM,
報錯指向了 ExoPlayer2

 java.lang.OutOfMemoryError: Failed to allocate a 65548 byte allocation with 40232 free bytes and 39KB until OOM
 	at com.google.android.exoplayer2.upstream.DefaultAllocator.allocate(DefaultAllocator.java:102)
 	at com.google.android.exoplayer2.source.SampleDataQueue.preAppend(SampleDataQueue.java:392)
 	at com.google.android.exoplayer2.source.SampleDataQueue.sampleData(SampleDataQueue.java:181)
 	at com.google.android.exoplayer2.source.SampleQueue.sampleData(SampleQueue.java:471)
 	at com.google.android.exoplayer2.extractor.mp4.Mp4Extractor.readSample(Mp4Extractor.java:552)
 	at com.google.android.exoplayer2.extractor.mp4.Mp4Extractor.read(Mp4Extractor.java:192)
 	at com.google.android.exoplayer2.source.ProgressiveMediaPeriod$ExtractingLoadable.load(ProgressiveMediaPeriod.java:982)
 	at com.google.android.exoplayer2.upstream.Loader$LoadTask.run(Loader.java:391)
 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
 	at java.lang.Thread.run(Thread.java:818)

多次拋出 OOM:拋出這類錯誤,一般是由於方法重複調用、死循環引起,直至內存耗盡。

java.lang.OutOfMemoryError: OutOfMemoryError thrown while trying to throw OutOfMemoryError; no stack trace available

報錯指向 Lottie,但是我的 Lottie 資源都很小,並且不包含圖片資源。

 FATAL EXCEPTION: main
 Process: com.koki.callshow, PID: 3574
 java.lang.OutOfMemoryError: Failed to allocate a 24 byte allocation with 552 free bytes and 552B until OOM
 	at java.util.concurrent.CopyOnWriteArrayList.iterator(CopyOnWriteArrayList.java:184)
 	at java.util.concurrent.CopyOnWriteArraySet.iterator(CopyOnWriteArraySet.java:306)
 	at com.airbnb.lottie.utils.BaseLottieAnimator.notifyUpdate(BaseLottieAnimator.java:87)
 	at com.airbnb.lottie.utils.LottieValueAnimator.doFrame(LottieValueAnimator.java:98)
 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:892)
 	at android.view.Choreographer.doCallbacks(Choreographer.java:696)
 	at android.view.Choreographer.doFrame(Choreographer.java:628)
 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880)
 	at android.os.Handler.handleCallback(Handler.java:815)
 	at android.os.Handler.dispatchMessage(Handler.java:104)
 	at android.os.Looper.loop(Looper.java:205)
 	at android.app.ActivityThread.main(ActivityThread.java:5814)
 	at java.lang.reflect.Method.invoke(Native Method)
 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:806)
 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
05-10 14:15:44.306 E/AndroidRuntime( 3574): FATAL EXCEPTION: main
05-10 14:15:44.306 E/AndroidRuntime( 3574): Process: com.koki.callshow, PID: 3574
05-10 14:15:44.306 E/AndroidRuntime( 3574): java.lang.OutOfMemoryError: Failed to allocate a 24 byte allocation with 552 free bytes and 552B until OOM
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at java.util.concurrent.CopyOnWriteArrayList.iterator(CopyOnWriteArrayList.java:184)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at java.util.concurrent.CopyOnWriteArraySet.iterator(CopyOnWriteArraySet.java:306)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at com.airbnb.lottie.utils.BaseLottieAnimator.notifyUpdate(BaseLottieAnimator.java:87)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at com.airbnb.lottie.utils.LottieValueAnimator.doFrame(LottieValueAnimator.java:98)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:892)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at android.view.Choreographer.doCallbacks(Choreographer.java:696)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at android.view.Choreographer.doFrame(Choreographer.java:628)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at android.os.Handler.handleCallback(Handler.java:815)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at android.os.Handler.dispatchMessage(Handler.java:104)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at android.os.Looper.loop(Looper.java:205)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at android.app.ActivityThread.main(ActivityThread.java:5814)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at java.lang.reflect.Method.invoke(Native Method)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:806)
05-10 14:15:44.306 E/AndroidRuntime( 3574): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)

報錯指向給 ImageView 設置圖片,但是圖片並不是大圖片

FATAL EXCEPTION: main
java.lang.OutOfMemoryError: Failed to allocate a 129612 byte allocation with 110080 free bytes and 107KB until OOM
	at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
	at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
	at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:651)
	at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:486)
	at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1085)
	at android.content.res.Resources.loadDrawableForCookie(Resources.java:2935)
	at android.content.res.Resources.loadDrawable(Resources.java:2822)
	at android.content.res.Resources.getDrawable(Resources.java:939)
	at android.content.Context.getDrawable(Context.java:478)
	at androidx.core.content.ContextCompat.getDrawable(ContextCompat.java:454)
	at androidx.appcompat.widget.ResourceManagerInternal.getDrawable(ResourceManagerInternal.java:144)
	at androidx.appcompat.widget.ResourceManagerInternal.getDrawable(ResourceManagerInternal.java:132)
	at androidx.appcompat.content.res.AppCompatResources.getDrawable(AppCompatResources.java:104)
	at androidx.appcompat.widget.AppCompatImageHelper.loadFromAttributes(AppCompatImageHelper.java:59)
	at androidx.appcompat.widget.AppCompatImageView.<init>(AppCompatImageView.java:78)
	at androidx.appcompat.widget.AppCompatImageView.<init>(AppCompatImageView.java:68)
	at androidx.appcompat.app.AppCompatViewInflater.createImageView(AppCompatViewInflater.java:187)
	at androidx.appcompat.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:107)
	at androidx.appcompat.app.AppCompatDelegateImpl.createView(AppCompatDelegateImpl.java:1407)
	at androidx.appcompat.app.AppCompatDelegateImpl.onCreateView(AppCompatDelegateImpl.java:1457)
	at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:746)
	at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
	at android.view.LayoutInflater.rInflate(LayoutInflater.java:835)
	at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798)
	at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
	at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
	at com.koki.callshow.databinding.PreviewVideoActivityBinding.inflate(PreviewVideoActivityBinding.java:151)
	at com.koki.callshow.databinding.PreviewVideoActivityBinding.inflate(PreviewVideoActivityBinding.java:145)
	at com.koki.callshow.ui.previewvideo.PreviewVideoActivity.onCreate(PreviewVideoActivity.java:127)
	at android.app.Activity.performCreate(Activity.java:6345)
	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1146)
	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2538)
	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2673)
	at android.app.ActivityThread.-wrap11(ActivityThread.java)
	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1507)
	at android.os.Handler.dispatchMessage(Handler.java:111)
	at android.os.Looper.loop(Looper.java:205)
	at android.app.ActivityThread.main(ActivityThread.java:5814)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:806)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)

我有點奇怪,爲什麼可以到處拋出 OOM 異常呢?

看到 JakeWharton 大神在 github 上 OutOfMemoryError thrown while trying to throw OutOfMemoryError #534 的回覆:

OOMs rarely are caused by the stacktrace they report. In reality, it’s the
last straw the broke the camel’s back.

翻譯一下:OOM 異常很少是由於所報出的堆棧信息引起的。事實上,所報出的堆棧信息只不過是壓死駱駝的最後一根稻草而已。

我使用 AndroidStudio 的 Profiler 工具去查看內存佔用,最終定位到是由於 ExoPlayer2 佔用內存過多導致的 OOM。

6. Android 8.0 手機給通知欄設置了鈴聲,去掉鈴聲後,再運行程序依然有鈴聲

時間:2020年05月12日17:34:05

需要卸載 app,重新安裝。

最後

代碼出錯了,關鍵是要仔細查看日誌。能夠仔細地查看日誌,就離解決問題很近了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章