Reading Your Android App’s Logs

I’ve got an Android project going that uses FFmpeg to build short video files (more on this at a later date). Normally, you run FFmpeg in a terminal window or command prompt. It updates you on the status of a task in that terminal window. I’ve instrumented FFmpeg on Android with some C code and a JNI interface. When I execute FFmpeg from an Android app those status updates are written to logcat.

There are some important details that I was to surface in my app, primarily the progress of an encoding process. In order to do this, I needed a way to read my Android apps logging statements. This is possible on Android and without needing to request the scary READ_LOGS Android permission.

Note: All of my example code is in Kotlin because I ❤ Kotlin.

You can execute a process with Android’s Runtime API.

val process = Runtime.getRuntime().exec("some_command_here")

You can then get an InputStream to the Process’s output.

val process = Runtime.getRuntime().exec("some_command_here")
val inputStream = process.inputStream

Putting it all together, this is how one would get your apps logging statements from logcat, within the scope of your app.

val process = Runtime.getRuntime().exec("logcat")
reader = BufferedReader(InputStreamReader(process.inputStream))
var line: String?

do {
    line = reader.readLine()

    if (line != null) {
        // do something with this logging statement
    }
} while (line != null)

reader.close()

This code essentially runs forever because, as far as I’ve seen, reader doesn’t return a null line.

I’m close, but I still needed to add some sophistication. I needed to read and parse logs while FFmpeg was running so I can update the user on the status of their job. I needed to start parsing logs when I wanted to update the user while FFmpeg was running and end parsing when FFmpeg was complete. This problem is perfectly solved using RxJava.

fun readLogs(): Observable = 
  return Observable.create ({ emitter ->
    var reader: BufferedReader? = null

    try {
      val process = Runtime.getRuntime().exec("logcat")
      reader = BufferedReader(InputStreamReader(process.inputStream))
      var line: String?

      do {
          line = reader.readLine()

          if (line != null && line.length > 0) {
              emitter.onNext(line)
          }
      } while (line != null)

    } catch (e: Exception) {
      emitter.onError(e)
    } finally {
      reader?.close()
      emitter.onComplete()
    }
  })

With RxJava, I can emit a logging statement as it’s received by logcat.

Usage:

val disposable = readLogs()
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe({ logLine -> 
    logTextView.setText(logLine)
  }, { error -> throw error })
  
// later, when you no longer need to subscribe to your logs
disposable.dispose()

Because it’s all based on RxJava, you can do more advanced things like filtering

val disposable = readLogs()
  .filter({ line -> line.startsWith("foo") })
  .subscribeOn(Schedulers.io())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe({ logLine -> 
    logTextView.setText(logLine)
  }, { error -> throw error })

This allows you to “subscribe” to your apps logs!

/* fini */

稿源:emuneee.com (源链) | 关于 | 阅读提示

本站遵循[CC BY-NC-SA 4.0]。如您有版权、意见投诉等问题,请通过eMail联系我们处理。
酷辣虫 » 移动开发 » Reading Your Android App’s Logs

喜欢 (0)or分享给?

专业 x 专注 x 聚合 x 分享 CC BY-NC-SA 4.0

使用声明 | 英豪名录