总结几个Kotlin扩展的应用

一、用扩展函数优化Snackbar

例如一般Snackbar的使用:

Snackbar.make(
    coordinatorLayout!!,
    "这是一个snackbar",
    Snackbar.LENGTH_SHORT
).show()

Anso框架中Snackbar的扩展函数。

inline fun View.snackbar(message: Int, actionText: String, noinline action: (View) -> Unit) =
    Snackbar.make(this, message, Snackbar.LENGTH_SHORT)
        .setAction(actionText, action)
        .apply { show() }

 如果我们只需要唯一的参数是消息。则需要消除视图参数。改良后方法如下:

inline fun View.snackbar(message: Int) {
    val activity = context
    if (activity is Activity) Snackbar.make(this, message, Snackbar.LENGTH_SHORT)
        .apply { show() }
    else throw IllegalStateException("视图必须承载在Activity上")
}

注意:View不一定附加在Activity上,我们要做出防御式判断。在我们尝试显示Snackbar之前,我们必须确保View的context属性隐藏了一个Activity的实例。

 

二、用扩展函数封装Utils

比如我们有一个判断手机网络是否可用的方法:

常规写法:

object NetworkUtils {

    /**
     * 手机网络是否可用
     */
    fun isMobileConnected(context: Context): Boolean {
        val connectivityManager =
            context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
        val networkInfo = connectivityManager?.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
        return networkInfo?.isAvailable == true
    }
}

 在Activity中调用可以这样写:

val mobileConnected = NetworkUtils.isMobileConnected(this)

虽然用起来比没有封装之前优雅很多,但每次都要传入context,造成的繁琐先不计较,重要的是可能会让读者忽视context和mobileNetwork之间的强联系。作为调用者,我们更希望在调用时省略NetworkUtils类名,并让isMobileConnected看起来像context的一个属性或方法。

所以进行如下修改:

fun Context.isMobileConnected(): Boolean {
    val connectivityManager =
        this.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
    val networkInfo = connectivityManager?.getNetworkInfo(ConnectivityManager.TYPE_MOBILE)
    return networkInfo?.isAvailable == true
}

在Activity中调用可以这样写:

val mobileConnected = this.isMobileConnected()

在Android中对Context的生命周期需要进行很好的把控,这里我们应该使用ApplictionContext,防止出现生命周期不一致导致内存泄漏或者其他问题。

 

三、解决重复的findViewById

利用扩展函数简化这个繁琐的过程:

fun <T : View> Activity._view(@IdRes id: Int): T {
    return findViewById<T>(id)
}

在Activity中可以这样调用:

_view<FloatingActionButton>(R.id.snackbar_fab)

 尝试直接使用R.id.*操作,比如点击事件:

fun <T : View> Activity._view(@IdRes id: Int): T {
    return findViewById<T>(id)
}

fun Int.onClick(click: () -> Unit) {
    val temp = _view<View>(this).apply {
        setOnClickListener {
            click()
        }
    }
}

在Activity中调用如下:

R.id.snackbar_fab.onClick {
    println("haha")
}

 Kotlin为我们提供了扩展插件,gradle默认集成,从而可以省略R.id.*,直接使用组件的 id来操作视图。

apply plugin: 'kotlin-android-extensions'
import kotlinx.android.synthetic.main.activity_four.*
snackbar_fab.setOnClickListener{
    println("啦啦")
}
public final class ExtensionActivity extends AppCompatActivity {
   private HashMap _$_findViewCache;

   protected void onCreate(@Nullable Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      this.setContentView(-1300040);
      ((FloatingActionButton)this._$_findCachedViewById(id.snackbar_fab)).setOnClickListener((OnClickListener)null.INSTANCE);
   }

   public View _$_findCachedViewById(int var1) {
      if (this._$_findViewCache == null) {
         this._$_findViewCache = new HashMap();
      }

      View var2 = (View)this._$_findViewCache.get(var1);
      if (var2 == null) {
         var2 = this.findViewById(var1);
         this._$_findViewCache.put(var1, var2);
      }

      return var2;
   }

   public void _$_clearFindViewByIdCache() {
      if (this._$_findViewCache != null) {
         this._$_findViewCache.clear();
      }

   }
}

转成Java后,可以发现,在缓存集合中进行查找,有就直接使用,没有则通过findViewById进行查找,并添加到缓存集合中,还提供了_$_clearFindViewByIdCache() 方法用于清除缓存,在我们彻底替换界面控件时可以使用。

注意:Fragment的onDestroyView方法中默认调用了_$_clearFindViewByIdCache() 方法清除缓存,而Activity 没有。

 

参考:Kotlin核心编程

 

 

发布了182 篇原创文章 · 获赞 179 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/zhangying1994/article/details/105013357
今日推荐