Android Util Code KTX! It's time to improve your development efficiency! (Update!)

AndroidUtilCodeKTX It has been a month since Ktx was officially open source. So far, 98 star s and 11 fork s have been harvested on Github. During this period, I made a list of Github Trending Kotlin classifications, and also received good comments and suggestions from some developers. After this month's tortoise update, I did some functions I wanted to add, and fixed some developers'feedback problems.

The latest version is 0.0.6:

implementation 'luyao.util.ktx:AndroidUtilKTX:0.0.6'

This version of Change log:

* Add log switch
 * Add TextView.notEmpty() extension method
 * Add ShellExt to provide command-line correlation functions
 * Adding default exception handling callbacks to BaseVMFragment and BaseVMActivity
 * android Version Judgment
 * Judging whether accessibility services are open
* RecyclerView.itemPadding
 * Send mail
 * Document-related
 * BaseActivity/BaseFragment Add CoroutineScope Implementation
 * KtxHandler for Automatic Perception of Life Cycle
 * Activity unified management
 * Application of front-end and back-end monitoring
 * KtxSpan, encapsulating the use of common Spans

Here is a brief introduction to the main modifications of version 0.0.6.

A series of empty judgments

Thanks to the use of higher-order functions and lambda expressions, we can make full use of our imagination to encapsulate some general logic. For example, for an empty object, executing a specified operation in non-space-time is equivalent to executing another operation in space-time. Our code may be full of code with this structure:

if (obj == null) {
    ...
} else {
    ...
}

See how this logic is written in Ktx:

obj.notNull({
    ...    
}, {
    ...    
})

Well, it seems a little more elegant than before (allow me to deceive myself). The implementation is also simple, as follows:

fun <T> Any?.notNull(f: () -> T, t: () -> T): T {
    return if (this != null) f() else t()
}

Support for return values. Ignoring the less obvious optimization above, along this line of thought, we can do similar optimization in a slightly more complex situation. For example, if the text in TextView is empty, you can define the following extension functions:

fun TextView.notEmpty(f: TextView.() -> Unit, t: TextView.() -> Unit) {
    if (text.toString().isNotEmpty()) f() else t()
}

If you think of more usage scenarios, welcome to smash them. issue.

Execute shell commands

There's nothing special about this. It's from me. Box Requirements for reading linux kernel versions in the project. Although it was not read successfully in the end, a top-level function was added as follows:

fun executeCmd(command: String): String {
    val process = Runtime.getRuntime().exec(command)

    val resultReader = BufferedReader(InputStreamReader(process.inputStream))
    val errorReader = BufferedReader(InputStreamReader(process.errorStream))

    val resultBuilder = StringBuilder()
    var resultLine: String? = resultReader.readLine()

    val errorBuilder = StringBuilder()
    var errorLine = errorReader.readLine()

    while (resultLine != null) {
        resultBuilder.append(resultLine)
        resultLine = resultReader.readLine()
    }

    while (errorLine != null) {
        errorBuilder.append(errorLine)
        errorLine = errorReader.readLine()
    }

    return "$resultBuilder\n$errorBuilder"
}

BaseActivity adds exception handling

This comes from me. wanandroid Project issue 7 The main purpose is to deal with Kotlin Coroutine's anomaly. There was exception handling, but the mException used to receive exceptions in BaseViewModel was private and could not be obtained directly. This version does general exception handling and can get exceptions directly through onError() callbacks in BaseVMActivity and BaseVMFragment. Specific reference MvvmActivity Exception handling demonstration in.

Android Version Judgment

fun fromM() = fromSpecificVersion(Build.VERSION_CODES.M)
fun beforeM() = beforeSpecificVersion(Build.VERSION_CODES.M)
fun fromN() = fromSpecificVersion(Build.VERSION_CODES.N)
fun beforeN() = beforeSpecificVersion(Build.VERSION_CODES.N)
fun fromO() = fromSpecificVersion(Build.VERSION_CODES.O)
fun beforeO() = beforeSpecificVersion(Build.VERSION_CODES.O)
fun fromP() = fromSpecificVersion(Build.VERSION_CODES.P)
fun beforeP() = beforeSpecificVersion(Build.VERSION_CODES.P)
fun fromSpecificVersion(version: Int): Boolean = Build.VERSION.SDK_INT >= version
fun beforeSpecificVersion(version: Int): Boolean = Build.VERSION.SDK_INT < version

Judging whether accessibility services are open

A small requirement encountered in the work, according to the barrier-free service name to determine whether the service is open.

fun Context.checkAccessbilityServiceEnabled(serviceName: String): Boolean {
    val settingValue =
        Settings.Secure.getString(applicationContext.contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
    return settingValue.notNull({
        var result = false
        val splitter = TextUtils.SimpleStringSplitter(':')
        while (splitter.hasNext()) {
            if (splitter.next().equals(serviceName, true)) {
                result = true
                break
            }
        }
        result
    }, { false })
}

RecyclerView.itemPadding

fun RecyclerView.itemPadding(top: Int, bottom: Int, left: Int = 0, right: Int = 0) {
    addItemDecoration(PaddingItemDecoration(top, bottom, left, right))
}

Easy and quick to add itemPadding, as follows:

commonRecycleView.run {
    itemPadding(5, 5, 10, 10)
    layoutManager = LinearLayoutManager(this@CommonListActivity)
    adapter = commonAdapter
}

The unit is dp. The logic of dp2px is processed internally.

Send mail

IntentExt adds the function of sending mail to support the most basic subject and text.

fun Context.sendEmail(email: String, subject: String?, text: String?) {
    Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:$email")).run {
        subject?.let { putExtra(Intent.EXTRA_SUBJECT, subject) }
        text?.let { putExtra(Intent.EXTRA_TEXT, text) }
        startActivity(this)
    }
}

Document-related

Document-related parts are intended to take a lot of effort to integrate, but Kotlin standard library support for document operation is too perfect. I have a reference to the file tool class in Android UtilCode, and the standard library basically meets most of these functions. In order to encapsulate the tool classes related to file management more comprehensively, I am Box A simple file management function has been added to the project, which can be seen in the latest commit.

Through this simple file manager module, on the basis of the standard library, the following extended attributes and functions are added.

val File.canListFiles: Boolean : Can I get subfolders?
val File.totalSize: Long       : Total size, including all subfolders
val File.formatSize: String    : Format the total file size, including all subfolders
val File.mimeType: String      : get files mimeType

/**
 * [isRecursive] Get all subfolders
 * [filter] File filter
 * /
fun File.listFiles(isRecursive: Boolean = false, filter: ((file: File) -> Boolean)? = null): Array<out File> {}

/**
 * [append] Whether to add or not
 * [text] Content to write
 * [charset] Character encoding
 * /
fun File.writeText(append: Boolean = false, text: String, charset: Charset = Charsets.UTF_8)
fun File.writeBytes(append: Boolean = false, bytes: ByteArray)

/**
 *   [destFile]  Target file/folder
 *   [overwrite] Coverage or not
 *   [reserve] Whether to retain source files
 */
fun File.moveTo(destFile: File, overwrite: Boolean = true, reserve: Boolean = true)

/**
 *   [destFolder] Target file/folder
 *   [overwrite] Coverage or not
 *   [func] Progress callback for individual files (from 0 to 100)
 */
fun File.moveToWithProgress(
    destFolder: File,
    overwrite: Boolean = true,
    reserve: Boolean = true,
    func: ((file: File, i: Int) -> Unit)? = null
)

fun File.rename(newName: String)
fun File.rename(newFile: File)

In addition, most of the common operations are already included in Kotlin Stdlib. Readers can read the / kotlin/io/Utils.kt file.

CoroutineScope

CoroutineScope implementation is added to BaseActivity/BaseFragment, which can directly use the main thread's scope through launch {} in its subclasses, and automatically cancel the start of the process in this scope in onDestroy(). Students who have experience in the use of cooperative processes should not be difficult to understand, and the implementation is also simple.

abstract class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope() {

    ...
    ...
    
    override fun onDestroy() {
        super.onDestroy()
        cancel()
    }
}

It doesn't matter if you haven't used a coordinator. I'll write an article about how to use the coordinator correctly in Android.

KtxHandler for Automatic Perception of Life Cycle

This is an Andler that automatically senses the life cycle of a component and registers it with a Lifecycle Owner, which automatically cleans up resources when the component onDestroy(). This idea comes from the code I saw on the internet. Sorry, I can't remember the origin. Next time, I will record the origin and mark it in advance.

class KtxHandler(lifecycleOwner: LifecycleOwner, callback: Callback) : Handler(callback), LifecycleObserver {

    private val mLifecycleOwner: LifecycleOwner = lifecycleOwner

    init {
        lifecycleOwner.lifecycle.addObserver(this)
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private fun onDestroy() {
        removeCallbacksAndMessages(null)
        mLifecycleOwner.lifecycle.removeObserver(this)
    }
}

Its simple use can be referred to LifeCycleActivity.kt .

Activity Unified Management/Application Front and Background Monitoring

This comes from the requirement of the issue area. There are no more than two requirements in development. Close the specified Activity and close all Activities when you exit the application. These two functions are defined in the singleton class KtxManager.

fun  finishActivity(clazz: Class<*>){
    for (activity in mActivityList)
        if (activity.javaClass == clazz)
            activity.finish()
}

fun finishAllActivity() {
    for (activity in mActivityList)
        activity.finish()
}

Also in LifeCycleActivity.kt There are examples of the use of these two functions.

The use of this piece is still quite ingenious. Activity Lifecycle Callbacks are used to monitor the activity's life cycle, and the general way of using Activity Lifecycle Callbacks is to register in Application. But in Ktx, there are no Application classes, and there is no need for developers to write any code at the time of integration. It automatically completes the registration monitoring of the lifecycle. Maybe some of your classmates have seen this trick in other places. If you don't know it, read it. Ktx.kt Believe you understand.

Incidentally, the application is also monitored through Process Lifecycle Owner to enter the foreground and background. I believe you also see the corresponding Toast prompt.

KtxSpan

Finally, it's a Span tool class. Let's see the effect first.

If you are familiar with this picture, you are Blankji's. AndroidUtilCode Faithful users. I don't have to rebuild the wheel here, nor do I copy Android Util Code entirely. I've always been material-dialogs Users like its API form very much, so they reconstruct KtxSpan following its API structure.

KtxSpan().with(spanTv).show {
            text(
                "SpanUtils",
                foregroundColor = Color.YELLOW,
                backgroundColor = Color.LTGRAY,
                alignment = Layout.Alignment.ALIGN_CENTER
            )
            text("Foreground color", foregroundColor = Color.GREEN)
            text("background color", backgroundColor = Color.LTGRAY)
            blockLine(spanTv.dp2px(6), true)
            text("Row height", lineHeight = 2 * spanTv.lineHeight, backgroundColor = Color.LTGRAY)
            text(
                "Test paragraph indentation, first line indentation, other line indentation, other line indentation",
                first = (spanTv.textSize * 2).toInt(),
                rest = 0,
                backgroundColor = Color.GREEN
            )
            text(
                "Test references, followed by words for two lines of effect",
                quoteColor = Color.GREEN,
                quoteStripeWidth = 10,
                quoteGapWidth = 10,
                backgroundColor = Color.LTGRAY
            )
            image(
                R.drawable.small,
                verticalAlignment = ImageSpan.ALIGN_BOTTOM,
                marginLeft = dp2px(30),
                marginRight = dp2px(40)
            )
}

KtxSpan has only three methods, but it's enough to cover most usage scenarios.

The first method, text(), can represent most of the effect of text. Thanks to Kotlin's method parameters supporting default values, most of the method overloads are eliminated. The parameters of the text() method are quite large, with a total of 31 parameters. Except text is necessary, the rest can be assigned according to the requirements. By default, each text() method is a new line, and you can also pass in isNewLine: Boolean = false to make the next line no longer newline.

The second method is image(), which can represent the image display, and support the alignment of attributes and left-right spacing.

The third method is blockLine(), which represents paragraph spacing. There are two parameters, one is the value of paragraph spacing, and the other is whether to add spacing to all subsequent paragraphs.

For the specific use of KtxSpan, see the sample code in the project: KtxSpanActivity .

Last

That's all for this update. Android Util Code KTX is still a kid. Welcome!

Writing the first Wechat Public Number: Dedicated to Java, Android original knowledge sharing, LeetCode problem solving.

Android Util Code KTX latest update information, sweep code to pay attention to me!

Keywords: Android github REST Lambda

Added by dserf on Sun, 18 Aug 2019 17:03:55 +0300