一、用扩展函数优化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 Activity._view(@IdRes id: Int): T {
return findViewById(id)
}
在Activity中可以这样调用:
_view(R.id.snackbar_fab)
尝试直接使用R.id.*操作,比如点击事件:
fun Activity._view(@IdRes id: Int): T {
return findViewById(id)
}
fun Int.onClick(click: () -> Unit) {
val temp = _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核心编程