google支付回調(diào)驗(yàn)證(備用)
969
2025-03-31
簡(jiǎn)述: 這應(yīng)該是2019年的第一篇文章了,臨近過年回家一個(gè)月需求是真的很多,正如康少說的那樣,一年的需求幾乎都在最后一兩月寫完了。所以寫文章也擱置了很久,當(dāng)然再忙每天都會(huì)刷掘金。很久就一直在使用Kotlin寫項(xiàng)目,說實(shí)話到目前為止Kotlin用的是越來越順手了(心里只能用美滋滋來形容了)。當(dāng)然這次依然講的是Kotlin,說下我這次需求開發(fā)中自己一些思考和實(shí)踐。其中讓自己感受最深的就是: "Don't Repeat Yourself"。當(dāng)你經(jīng)常寫一些重復(fù)性的代碼,不妨停下來想下是否要去改變這樣一種狀態(tài)。
今天我們來講個(gè)非常非常簡(jiǎn)單的東西,那就是回調(diào)俗稱Callback, 在Android開發(fā)以及一些客戶端開發(fā)中經(jīng)常會(huì)使用回調(diào)。其實(shí)如果端的界面開發(fā)當(dāng)做一個(gè)黑盒的話,無非就是輸入和輸出,輸入數(shù)據(jù),輸出UI的渲染以及用戶的交互事件,那么這個(gè)交互事件大多數(shù)場(chǎng)景會(huì)采用回調(diào)來實(shí)現(xiàn)。那么今天一起來說說如何讓你的回調(diào)更具kotlin風(fēng)味:
1、Java中的回調(diào)實(shí)現(xiàn)
簡(jiǎn)述: 這應(yīng)該是2019年的第一篇文章了,臨近過年回家一個(gè)月需求是真的很多,正如康少說的那樣,一年的需求幾乎都在最后一兩月寫完了。所以寫文章也擱置了很久,當(dāng)然再忙每天都會(huì)刷掘金。很久就一直在使用Kotlin寫項(xiàng)目,說實(shí)話到目前為止Kotlin用的是越來越順手了(心里只能用美滋滋來形容了)。當(dāng)然這次依然講的是Kotlin,說下我這次需求開發(fā)中自己一些思考和實(shí)踐。其中讓自己感受最深的就是: "Don't Repeat Yourself"。當(dāng)你經(jīng)常寫一些重復(fù)性的代碼,不妨停下來想下是否要去改變這樣一種狀態(tài)。
今天我們來講個(gè)非常非常簡(jiǎn)單的東西,那就是回調(diào)俗稱Callback, 在Android開發(fā)以及一些客戶端開發(fā)中經(jīng)常會(huì)使用回調(diào)。其實(shí)如果端的界面開發(fā)當(dāng)做一個(gè)黑盒的話,無非就是輸入和輸出,輸入數(shù)據(jù),輸出UI的渲染以及用戶的交互事件,那么這個(gè)交互事件大多數(shù)場(chǎng)景會(huì)采用回調(diào)來實(shí)現(xiàn)。那么今天一起來說說如何讓你的回調(diào)更具kotlin風(fēng)味:
1、Java中的回調(diào)實(shí)現(xiàn)
2、使用Kotlin來改造Java中的回調(diào)
3、進(jìn)一步讓你的回調(diào)更具Kotlin風(fēng)味
4、Object對(duì)象表達(dá)式回調(diào)和DSL回調(diào)對(duì)比
5、Kotlin中回調(diào)使用建議
6、Don't Repeat Yourself(DSL回調(diào)配置太模板化了,不妨來擼個(gè)自動(dòng)生成代碼的AS插件吧)
7、DslListenerBuilder插件基本介紹和使用
8、DslListenerBuilder插件源碼和Velocity模板引擎基本介紹
9、總結(jié)
一、Java中的回調(diào)實(shí)現(xiàn)
Java中的回調(diào)一般處理步驟都是寫一個(gè)接口,然后在接口中定義一些回調(diào)函數(shù);然后再暴露一個(gè)設(shè)置回調(diào)接口的函數(shù),傳入函數(shù)實(shí)參就是回調(diào)接口的一個(gè)實(shí)例,一般情況都是以匿名對(duì)象形式存在。例如以Android中OnClickListener和TextWatcher源碼為例:
1、OnClickListener回調(diào)的Java實(shí)現(xiàn)
//OnClickListener的定義
public?interface?OnClickListener?{
void?onClick(View?v);
}
public?void?setOnClickListener(OnClickListener?listener)?{
this.clickListener?=?listener;
}
//OnClickListener的使用
mBtnSubmit.setOnClickListener(new?View.OnClickListener()?{
@Override
public?void?onClick(View?v)?{
//add?your?logic?code
}
});
2、TextWatcher回調(diào)的Java實(shí)現(xiàn)
//TextWatcher的定義
public?interface?TextWatcher?extends?NoCopySpan?{
public?void?beforeTextChanged(CharSequence?s,?int?start,int?count,?int?after);
public?void?onTextChanged(CharSequence?s,?int?start,?int?before,?int?count);
public?void?afterTextChanged(Editable?s);
}
public?void?addTextChangedListener(TextWatcher?watcher)?{
if?(mListeners?==?null)?{
mListeners?=?new?ArrayList
}
mListeners.add(watcher);
}
//TextWatcher的使用
mEtComment.addTextChangedListener(new?TextWatcher()?{
@Override
public?void?beforeTextChanged(CharSequence?s,?int?start,?int?count,?int?after)?{
//add?your?logic?code
}
@Override
public?void?onTextChanged(CharSequence?s,?int?start,?int?before,?int?count)?{
//add?your?logic?code
}
@Override
public?void?afterTextChanged(Editable?s)?{
//add?your?logic?code
}
});
二、使用Kotlin來改造Java中的回調(diào)
針對(duì)上述Java中的回調(diào)寫法,估計(jì)大部分人轉(zhuǎn)到Kotlin后,估計(jì)會(huì)做如下處理:
1、如果接口只有一個(gè)回調(diào)函數(shù)可以直接使用lamba表達(dá)式實(shí)現(xiàn)回調(diào)的簡(jiǎn)寫。
2、如果接口中含有多個(gè)回調(diào)函數(shù),都會(huì)使用object對(duì)象表達(dá)式來實(shí)現(xiàn)的。
以改造上述代碼為例:
1、(只有一個(gè)回調(diào)函數(shù)簡(jiǎn)寫形式)OnClickListener回調(diào)Kotlin改造
//只有一個(gè)回調(diào)函數(shù)普通簡(jiǎn)寫形式:?OnClickListener的使用
mBtnSubmit.setOnClickListener?{?view?->
//add?your?logic?code
}
//針對(duì)OnClickListener監(jiān)聽設(shè)置Coroutine協(xié)程框架中onClick擴(kuò)展函數(shù)的使用
mBtnSubmit.onClick?{?view?->
//add?your?logic?code
}
//Coroutine協(xié)程框架:?onClick的擴(kuò)展函數(shù)定義
fun?android.view.View.onClick(
context:?CoroutineContext?=?UI,
handler:?suspend?CoroutineScope.(v:?android.view.View?)?->?Unit
)?{
setOnClickListener?{?v?->
launch(context)?{
handler(v)
}
}
}
2、(多個(gè)回調(diào)函數(shù)object表達(dá)式)TextWatcher回調(diào)的Kotlin改造(object對(duì)象表達(dá)式)
mEtComment.addTextChangedListener(object:?TextWatcher{
override?fun?afterTextChanged(s:?Editable?)?{
//add?your?logic?code
}
override?fun?beforeTextChanged(s:?CharSequence?,?start:?Int,?count:?Int,?after:?Int)?{
//add?your?logic?code
}
override?fun?onTextChanged(s:?CharSequence?,?start:?Int,?before:?Int,?count:?Int)?{
//add?your?logic?code
}
})
關(guān)于object對(duì)象表達(dá)式實(shí)現(xiàn)的Kotlin中回調(diào),有不少的Kotlin的小伙伴在公眾號(hào)留言向我吐槽過,感覺這樣的寫法是直接從Java中的翻譯過來的一樣,完全看不出Kotlin的優(yōu)勢(shì)在哪。問我有沒有什么更加具有Kotlin風(fēng)味的寫法,當(dāng)然是有的,請(qǐng)接著往下看。
三、進(jìn)一步讓你的回調(diào)更具Kotlin風(fēng)味(DSL配置回調(diào))
其實(shí)如果你看過很多國(guó)外大佬的有關(guān)Koltin項(xiàng)目的源碼,你就會(huì)發(fā)現(xiàn)他們寫回調(diào)很少去使用object表達(dá)式去實(shí)現(xiàn)回調(diào),而是采用另一種方式去實(shí)現(xiàn),并且整體寫法看起來更具有Kotlin風(fēng)味。即使內(nèi)部用到object表達(dá)式,暴露給外層中間都會(huì)做一層DSL配置轉(zhuǎn)換,讓外部調(diào)用起來更加Kotlin化。以Github中的MaterialDrawer項(xiàng)目(目前已經(jīng)有1W多star)中官方指定MatrialDrawer項(xiàng)目Kotlin版本實(shí)現(xiàn)的MaterialDrawerKt項(xiàng)目中間一段源碼為例:
1、DrawerImageLoader 回調(diào)定義
//注意:?這個(gè)函數(shù)參數(shù)是一個(gè)帶返回值的lambda表達(dá)式
public?fun?drawerImageLoader(actions:?DrawerImageLoaderKt.()?->?Unit):?DrawerImageLoader.IDrawerImageLoader?{
val?loaderImpl?=?DrawerImageLoaderKt().apply(actions).build()?//
DrawerImageLoader.init(loaderImpl)
return?loaderImpl
}
//DrawerImageLoaderKt:?DSL?listener?Builder類
public?class?DrawerImageLoaderKt?{
//定義需要回調(diào)的函數(shù)lamba成員對(duì)象
private?var?setFunc:?((ImageView,?Uri,?Drawable?,?String?)?->?Unit)??=?null
private?var?placeholderFunc:?((Context,?String?)?->?Drawable)??=?null
internal?fun?build()?=?object?:?AbstractDrawerImageLoader()?{
private?val?setFunction:?(ImageView,?Uri,?Drawable?,?String?)?->?Unit?=?setFunc
?:?throw?IllegalStateException("DrawerImageLoader?has?to?have?a?set?function")
private?val?placeholderFunction?=?placeholderFunc
?:?{?ctx,?tag?->?super.placeholder(ctx,?tag)?}
override?fun?set(imageView:?ImageView,?uri:?Uri,?placeholder:?Drawable?,?tag:?String?)?=?setFunction(imageView,?uri,?placeholder,?tag)
override?fun?placeholder(ctx:?Context,?tag:?String?)?=?placeholderFunction(ctx,?tag)
}
//暴露給外部調(diào)用的回調(diào)函數(shù),在構(gòu)建類中類似setter,getter方法
public?fun?set(setFunction:?(imageView:?ImageView,?uri:?Uri,?placeholder:?Drawable?,?tag:?String?)?->?Unit)?{
this.setFunc?=?setFunction
}
public?fun?placeholder(placeholderFunction:?(ctx:?Context,?tag:?String?)?->?Drawable)?{
this.placeholderFunc?=?placeholderFunction
}
2、DrawerImageLoader回調(diào)使用
drawerImageLoader?{
//內(nèi)部的回調(diào)函數(shù)可以選擇性重寫
set?{?imageView,?uri,?placeholder,?_?->
Picasso.with(imageView.context)
.load(uri)
.placeholder(placeholder)
.into(imageView)
}
cancel?{?imageView?->
Picasso.with(imageView.context)
.cancelRequest(imageView)
}
}
可以看到使用DSL配置的回調(diào)更加具有Kotlin風(fēng)味,讓整個(gè)回調(diào)看起來非常的舒服,那種效果豈止絲滑。
四、DSL配置回調(diào)基本步驟
在Kotlin的一個(gè)類中實(shí)現(xiàn)了DSL配置回調(diào)非常簡(jiǎn)單主要就三步:
1、定義一個(gè)回調(diào)的Builder類,并且在類中定義回調(diào)lamba表達(dá)式對(duì)象成員,最后再定義Builder類的成員函數(shù),這些函數(shù)就是暴露給外部回調(diào)的函數(shù)。個(gè)人習(xí)慣把它作為一個(gè)類的內(nèi)部類。類似下面這樣
class?AudioPlayer(context:?Context){
//other?logic?...
inner?class?ListenerBuilder?{
internal?var?mAudioPlayAction:?((AudioData)?->?Unit)??=?null
internal?var?mAudioPauseAction:?((AudioData)?->?Unit)??=?null
internal?var?mAudioFinishAction:?((AudioData)?->?Unit)??=?null
fun?onAudioPlay(action:?(AudioData)?->?Unit)?{
mAudioPlayAction?=?action
}
fun?onAudioPause(action:?(AudioData)?->?Unit)?{
mAudioPauseAction?=?action
}
fun?onAudioFinish(action:?(AudioData)?->?Unit)?{
mAudioFinishAction?=?action
}
}
}
2、然后,在類中聲明一個(gè)ListenerBuilder的實(shí)例引用,并且暴露一個(gè)設(shè)置該實(shí)例對(duì)象的一個(gè)方法,也就是我們常說的注冊(cè)事件監(jiān)聽或回調(diào)的方法,類似setOnClickListenter這種。但是需要注意的是函數(shù)的參數(shù)是帶ListenerBuilder返回值的lamba,類似下面這樣:
class?AudioPlayer(context:?Context){
//other?logic?...
private?lateinit?var?mListener:?ListenerBuilder
fun?registerListener(listenerBuilder:?ListenerBuilder.()?->?Unit)?{//帶ListenerBuilder返回值的lamba
mListener?=?ListenerBuilder().also(listenerBuilder)
}
}
3、最后在觸發(fā)相應(yīng)事件調(diào)用Builder實(shí)例中l(wèi)amba即可
class?AudioPlayer(context:?Context){
//other?logic?...
val?mediaPlayer?=?MediaPlayer(mContext)
mediaPlayer.play(mediaItem,?object?:?PlayerCallbackAdapter()?{
override?fun?onPlay(item:?MediaItem?)?{
if?(::mListener.isInitialized)?{
mListener.mAudioPlayAction?.invoke(mAudioData)
}
}
override?fun?onPause(item:?MediaItem?)?{
if?(::mListener.isInitialized)?{
mListener.mAudioPauseAction?.invoke(mAudioData)
}
}
override?fun?onPlayCompleted(item:?MediaItem?)?{
if?(::mListener.isInitialized)?{
mListener.mAudioFinishAction?.invoke(mAudioData)
}
}
})
}
4、外部調(diào)用
val?audioPlayer?=?AudioPlayer(context)
audioPlayer.registerListener?{
//可以任意選擇需要回調(diào)的函數(shù),不必要完全重寫
onAudioPlay?{
//todo?your?logic
}
onAudioPause?{
//todo?your?logic
}
onAudioFinish?{
//todo?your?logic
}
}
相比object表達(dá)式回調(diào)寫法,有沒有發(fā)現(xiàn)DSL回調(diào)配置更懂Kotlin. 可能大家看起來確實(shí)不錯(cuò),但是不知道它具體原理,畢竟這樣寫法太語法糖化,不太好理解,讓我們接下來一起揭開它的糖衣。
五、揭開DSL回調(diào)配置的語法糖衣
1、原理闡述
DSL回調(diào)配置其實(shí)挺簡(jiǎn)單的,實(shí)際上就一個(gè)Builder類中維護(hù)著多個(gè)回調(diào)lambda的實(shí)例,然后在外部回調(diào)的時(shí)候再利用帶Builder類返回值實(shí)例的lamba特性,在該lambda作用域內(nèi)this可以內(nèi)部表達(dá)為Builder類實(shí)例,利用Builder類實(shí)例調(diào)用它內(nèi)部定義成員函數(shù)并且賦值初始化Builder類回調(diào)lambda成員實(shí)例,而這些被初始化過的lambda實(shí)例就會(huì)在內(nèi)部事件被觸發(fā)的時(shí)候執(zhí)行invoke操作。如果在該lambda內(nèi)部沒有調(diào)用某個(gè)成員方法,那么在該Builder類中這個(gè)回調(diào)lambda成員實(shí)例就是為null,即使內(nèi)部事件觸發(fā),為空就不會(huì)回調(diào)到外部。
換句話就是外部回調(diào)的函數(shù)block塊會(huì)通過Builder類中成員函數(shù)初始化Builder類中回調(diào)lambda實(shí)例(在上述代碼表現(xiàn)就是mXXXAction實(shí)例),然后當(dāng)內(nèi)部事件觸發(fā)后,根據(jù)當(dāng)前l(fā)ambda實(shí)例是否被初始化,如果初始化完畢,就是立即執(zhí)行這個(gè)lambda也就是執(zhí)行傳入的block代碼塊
2、代碼拆解
為了更加清楚論證上面的闡述,我們可以把代碼拆解一下:
mAudioPlayer.registerListener({
//registerListener參數(shù)是個(gè)帶ListenerBuilder實(shí)例返回值的lambda
//所以這里this就是內(nèi)部指代為L(zhǎng)istenerBuilder實(shí)例
this.onAudioPlay?({
//logic?block
})
this.onAudioPause?({
//?logic?block
})
this.onAudioFinish({
//?logic?block
})
})
以onAudioPlay為例其他同理,調(diào)用ListenerBuilder中onAudioPlay函數(shù),并傳入block塊來賦值初始化ListenerBuilder類中的mAudioPlayActionlambda實(shí)例,當(dāng)AudioPlayer中的onPlay函數(shù)被回調(diào)時(shí),就執(zhí)行mAudioPlayActionlambda。
貌似看起來object對(duì)象表達(dá)式回調(diào)相比DSL回調(diào)表現(xiàn)那么一無是處,是不是完全可以摒棄object對(duì)象表達(dá)式這種寫法呢?其實(shí)不然,object對(duì)象表達(dá)式這種寫法也是有它優(yōu)點(diǎn)的,具體有什么優(yōu)點(diǎn),請(qǐng)接著看它們兩種形式對(duì)比。
六、object對(duì)象表達(dá)式回調(diào)和DSL回調(diào)對(duì)比
1、調(diào)用寫法上對(duì)比
//使用DSL配置回調(diào)
val?audioPlayer?=?AudioPlayer(context)
audioPlayer.registerListener?{
//可以任意選擇需要回調(diào)的函數(shù),不必要完全重寫
onAudioPlay?{
//todo?your?logic
}
onAudioPause?{
//todo?your?logic
}
onAudioFinish?{
//todo?your?logic
}
}
//使用object對(duì)象表達(dá)式回調(diào)
val?audioPlayer?=?AudioPlayer(context)
audioPlayer.registerListener(object:?AudioPlayListener{
override?fun?onAudioPlay(audioData:?AudioData)?{
//todo?your?logic
}
override?fun?onAudioPause(audioData:?AudioData)?{
//todo?your?logic
}
override?fun?onAudioFinish(audioData:?AudioData)?{
//todo?your?logic
}
})
調(diào)用寫法對(duì)比明顯感覺DSL配置更加符合Kotlin風(fēng)格,所以DSL配置回調(diào)更勝一籌
2、使用上對(duì)比
使用上DSL有個(gè)明顯優(yōu)勢(shì)就是對(duì)于不需要監(jiān)聽的回調(diào)函數(shù)可以直接省略,而對(duì)于object表達(dá)式是直接實(shí)現(xiàn)一個(gè)接口回調(diào)必須重寫,雖然它也能做到任意選擇自己需要方法回調(diào),但是還是避免不了一層callback adapter層的處理。所以與其做個(gè)adapter層還不如一步到位。所以DSL配置回調(diào)更勝一籌
3、性能上對(duì)比
其實(shí)通過上述調(diào)用寫法上看,一眼就能看出來,DSL配置回調(diào)這種方式會(huì)針對(duì)每個(gè)回調(diào)函數(shù)都會(huì)創(chuàng)建lambda實(shí)例對(duì)象,而object對(duì)象表達(dá)式不管內(nèi)部回調(diào)的方法有多少個(gè),都只會(huì)生成一個(gè)匿名對(duì)象實(shí)例。區(qū)別就在這里,所以在性能方面object對(duì)象表達(dá)式這種方式會(huì)更優(yōu)一點(diǎn),但是通過問過一些Kotlin社區(qū)的大佬們他們還是更傾向于DSL配置這種寫法。所以其實(shí)這兩種方式都挺好的,看不同需求,自己權(quán)衡選擇即可, 反正我個(gè)人挺喜歡DSL那種。為了驗(yàn)證我們上述所說的,不妨來看下兩種方式下反編譯的代碼,看看是否是我們所說的那樣:
//DSL配置回調(diào)反編譯code
public?final?void?setListener(@NotNull?Function1?listener)?{
Intrinsics.checkParameterIsNotNull(listener,?"listener");
ListenerBuilder?var2?=?new?ListenerBuilder();
listener.invoke(var2);
ListenerBuilder?var10000?=?this.mListener;
//獲取AudioPlay方法對(duì)應(yīng)的實(shí)例對(duì)象
Function0?var3?=?var10000.getMAudioPlayAction$Coroutine_main();
Unit?var4;
if?(var3?!=?null)?{
var4?=?(Unit)var3.invoke();
}
//獲取AudioPause方法對(duì)應(yīng)的實(shí)例對(duì)象
var3?=?var10000.getMAudioPauseAction$Coroutine_main();
if?(var3?!=?null)?{
var4?=?(Unit)var3.invoke();
}
//獲取AudioFinish方法對(duì)應(yīng)的實(shí)例對(duì)象
var3?=?var10000.getMAudioFinishAction$Coroutine_main();
if?(var3?!=?null)?{
var4?=?(Unit)var3.invoke();
}
}
//object對(duì)象表達(dá)式反編譯code
public?static?final?void?main(@NotNull?String[]?args)?{
Intrinsics.checkParameterIsNotNull(args,?"args");
int?count?=?true;
PlayerPlugin?player?=?new?PlayerPlugin();
//new?Callback一個(gè)實(shí)例
player.setCallback((Callback)(new?Callback()?{
public?void?onAudioPlay()?{
}
public?void?onAudioPause()?{
}
public?void?onAudioFinish()?{
}
}));
}
七、Don't Repeat Yourself(所以順便使用kotlin來擼個(gè)自動(dòng)生成ListenerBuilder的插件吧)
使用過DSL配置回調(diào)的小伙伴們有沒有覺得寫這些代碼沒有任何技術(shù)含量的,且浪費(fèi)時(shí)間, 那么Don't Repeat Yourself從現(xiàn)在開始。如果整個(gè)DSL配置回調(diào)的過程可以做成類似toString、setter、getter方法那樣自動(dòng)生成,豈不美滋滋,所以來擼個(gè)插件吧。所以接下來大致介紹下DslListenerBuilder插件的開發(fā)。
開發(fā)整體思路:
實(shí)際上就是通過Swing的UI窗口配置需要信息參數(shù),然后通過Velocity模板引擎生成模板代碼,然后通過Intellij Plugin API 將生成的代碼插入到當(dāng)前代碼文件中。所以所有需要自動(dòng)生成代碼的需求都類似這樣流程。下次需要生成不一樣的代碼只需要修改Velocity模板即可。
使用到技術(shù)點(diǎn):
1、Kotlin基礎(chǔ)開發(fā)知識(shí)
2、Kotlin擴(kuò)展函數(shù)
3、Kotlin的lambda表達(dá)式
4、Swing UI組件開發(fā)知識(shí)
5、Intellij Plugin開發(fā)基本知識(shí)
6、IntelliJ Plugin 常用開發(fā)API(Editor、WriteCommandAction、PsiDocumentManager、Document等API的使用)
7、Velocity模板基本語法(#if,#foreach,#set等)
8、Velocity模板引擎API的基本使用
基本介紹和使用:
這是一款自動(dòng)生成DSL ListenerBuilder回調(diào)模板代碼的IDEA插件,支持IDEA、AndroidStudio以及JetBrains全家桶。
第一步: 首先按照IDEA一般插件安裝流程安裝好DslListenerBuilder插件。
第二步: 然后打開具體某個(gè)類文件,將光標(biāo)定位在具體代碼生成的位置,
第三步: 使用快捷鍵調(diào)出Generate中的面板,選擇其中的“Listener Builder”, 然后就會(huì)彈出一個(gè)面板,可以點(diǎn)擊add按鈕添加一個(gè)或多個(gè)回調(diào)函數(shù)的lamba, 也可以從面板中選擇任一一條不需要的Item進(jìn)行刪除。
第四步: 最后點(diǎn)擊OK就可以在指定光標(biāo)位置生成需要的代碼。
九、DslListenerBuilder插件源碼和Velocity模板引擎學(xué)習(xí)資源
這里推薦一些有關(guān)Velocity模板引擎的學(xué)習(xí)資源,此外有關(guān)插件的更多具體實(shí)現(xiàn)內(nèi)容請(qǐng)查看下面GitHub中的源碼,如果覺得不錯(cuò)歡迎給個(gè)star~~~
目前插件已經(jīng)上傳到JetBrains IntelliJ Plugins官方倉庫,還處于審核,過幾天就可以直接在AndroidStudio或者IntelliJ IDEA中搜索 DslListenerBuilder直接安裝了
DslListenerBuilder插件-
DslListenerBuilder插件源碼地址
Velocity模板基本語法
使用 Velocity 模板引擎快速生成代碼
十、總結(jié)
到這里有關(guān)Kotlin回調(diào)相關(guān)內(nèi)容已經(jīng)講得很清楚了,然后還給大家介紹了如何去開發(fā)一個(gè)自動(dòng)生成代碼的插件。整個(gè)插件開發(fā)流程同樣適用于其他的代碼生成需求。為什么要寫這么個(gè)插件呢,主要是由于最近需求太多,每次寫回調(diào)的時(shí)候都需要不斷重復(fù)去寫很多類似的代碼。有時(shí)候當(dāng)我們?cè)谥貜?fù)性做一些操作的時(shí)候,不妨去思考下用什么工具能否把整個(gè)流程給自動(dòng)化。歸根結(jié)底一句話: Don't Repeat Yourself.
歡迎關(guān)注Kotlin開發(fā)者聯(lián)盟,這里有最新Kotlin技術(shù)文章,每周會(huì)不定期翻譯一篇Kotlin國(guó)外技術(shù)文章。如果你也喜歡Kotlin,歡迎加入我們~~~
Kotlin系列文章,歡迎查看:
Effective Kotlin翻譯系列
[譯]Effective Kotlin系列之考慮使用原始類型的數(shù)組優(yōu)化性能(五)
[譯]Effective Kotlin系列之使用Sequence來優(yōu)化集合的操作(四)
[譯]Effective Kotlin系列之探索高階函數(shù)中inline修飾符(三)
[譯]Effective Kotlin系列之遇到多個(gè)構(gòu)造器參數(shù)要考慮使用構(gòu)建器(二)
[譯]Effective Kotlin系列之考慮使用靜態(tài)工廠方法替代構(gòu)造器(一)
原創(chuàng)系列:
Jetbrains開發(fā)者日見聞(三)之Kotlin1.3新特性(inline class篇)
JetBrains開發(fā)者日見聞(二)之Kotlin1.3的新特性(Contract契約與協(xié)程篇)
JetBrains開發(fā)者日見聞(一)之Kotlin/Native 嘗鮮篇
教你如何攻克Kotlin中泛型型變的難點(diǎn)(實(shí)踐篇)
教你如何攻克Kotlin中泛型型變的難點(diǎn)(下篇)
教你如何攻克Kotlin中泛型型變的難點(diǎn)(上篇)
Kotlin的獨(dú)門秘籍Reified實(shí)化類型參數(shù)(下篇)
有關(guān)Kotlin屬性代理你需要知道的一切
淺談Kotlin中的Sequences源碼解析
淺談Kotlin中集合和函數(shù)式API完全解析-上篇
淺談Kotlin語法篇之lambda編譯成字節(jié)碼過程完全解析
淺談Kotlin語法篇之Lambda表達(dá)式完全解析
淺談Kotlin語法篇之?dāng)U展函數(shù)
淺談Kotlin語法篇之頂層函數(shù)、中綴調(diào)用、解構(gòu)聲明
淺談Kotlin語法篇之如何讓函數(shù)更好地調(diào)用
淺談Kotlin語法篇之變量和常量
淺談Kotlin語法篇之基礎(chǔ)語法
翻譯系列:
[譯]記一次Kotlin官方文檔翻譯的PR(內(nèi)聯(lián)類)
[譯]Kotlin中內(nèi)聯(lián)類的自動(dòng)裝箱和高性能探索(二)
[譯]Kotlin中內(nèi)聯(lián)類(inline class)完全解析(一)
[譯]Kotlin的獨(dú)門秘籍Reified實(shí)化類型參數(shù)(上篇)
[譯]Kotlin泛型中何時(shí)該用類型形參約束?
[譯] 一個(gè)簡(jiǎn)單方式教你記住Kotlin的形參和實(shí)參
[譯]Kotlin中是應(yīng)該定義函數(shù)還是定義屬性?
[譯]如何在你的Kotlin代碼中移除所有的!!(非空斷言)
[譯]掌握Kotlin中的標(biāo)準(zhǔn)庫函數(shù): run、with、let、also和apply
[譯]有關(guān)Kotlin類型別名(typealias)你需要知道的一切
[譯]Kotlin中是應(yīng)該使用序列(Sequences)還是集合(Lists)?
[譯]Kotlin中的龜(List)兔(Sequence)賽跑
實(shí)戰(zhàn)系列:
用Kotlin擼一個(gè)圖片壓縮插件ImageSlimming-導(dǎo)學(xué)篇(一)
用Kotlin擼一個(gè)圖片壓縮插件-插件基礎(chǔ)篇(二)
用Kotlin擼一個(gè)圖片壓縮插件-實(shí)戰(zhàn)篇(三)
淺談Kotlin實(shí)戰(zhàn)篇之自定義View圖片圓角簡(jiǎn)單應(yīng)用
Java Kotlin
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。