前言
按照官方的分類柳弄,操作符大致分為以下幾種:
- Creating Observables(Observable的創(chuàng)建操作符)精续,比如:Observable.create()、Observable.just()状原、Observable.from()等等挚赊;
- Transforming Observables(Observable的轉(zhuǎn)換操作符),比如:observable.map()洪橘、observable.flatMap()跪者、observable.buffer()等等;
- Filtering Observables(Observable的過(guò)濾操作符)熄求,比如:observable.filter()渣玲、observable.sample()、observable.take()等等弟晚;
- Combining Observables(Observable的組合操作符)忘衍,比如:observable.join()、observable.merge()卿城、observable.combineLatest()等等枚钓;
- Error Handling Operators(Observable的錯(cuò)誤處理操作符),比如:observable.onErrorResumeNext()瑟押、observable.retry()等等搀捷;
- Observable Utility Operators(Observable的功能性操作符),比如:observable.subscribeOn()多望、observable.observeOn()嫩舟、observable.delay()等等;
- Conditional and Boolean Operators(Observable的條件操作符)便斥,比如:observable.amb()至壤、observable.contains()、observable.skipUntil()等等枢纠;
- Mathematical and Aggregate Operators(Observable數(shù)學(xué)運(yùn)算及聚合操作符)像街,比如:observable.count()、observable.reduce()晋渺、observable.concat()等等镰绎;
- 其他如observable.toList()、observable.connect()木西、observable.publish()等等畴栖;
1、創(chuàng)建型操作符
-
create操作符
create操作符是所有創(chuàng)建型操作符的“根”八千,也就是說(shuō)其他創(chuàng)建型操作符最后都是通過(guò)create操作符來(lái)創(chuàng)建Observable的
-
from操作符
from操作符是把其他類型的對(duì)象和數(shù)據(jù)類型轉(zhuǎn)化成Observable
-
just操作符
just操作符也是把其他類型的對(duì)象和數(shù)據(jù)類型轉(zhuǎn)化成Observable吗讶,它和from操作符很像燎猛,只是方法的參數(shù)有所差別
-
defer操作符
defer操作符是直到有訂閱者訂閱時(shí),才通過(guò)Observable的工廠方法創(chuàng)建Observable并執(zhí)行
-
timer操作符
timer操作符是創(chuàng)建一串連續(xù)的數(shù)字照皆,產(chǎn)生這些數(shù)字的時(shí)間間隔是一定的
-
interval操作符
interval操作符是每隔一段時(shí)間就產(chǎn)生一個(gè)數(shù)字重绷,這些數(shù)字從0開始,一次遞增1直至無(wú)窮大膜毁;interval操作符的實(shí)現(xiàn)效果跟上面的timer操作符的第二種情形一樣
-
range操作符
range操作符是創(chuàng)建一組在從n開始昭卓,個(gè)數(shù)為m的連續(xù)數(shù)字,比如range(3,10)瘟滨,就是創(chuàng)建3候醒、4、5…12的一組數(shù)字
-
repeat/repeatWhen操作符
repeat操作符是對(duì)某一個(gè)Observable杂瘸,重復(fù)產(chǎn)生多次結(jié)果
repeatWhen操作符是對(duì)某一個(gè)Observable倒淫,有條件地重新訂閱從而產(chǎn)生多次結(jié)果
2、Observable的轉(zhuǎn)換操作符
-
buffer
buffer操作符周期性地收集源Observable產(chǎn)生的結(jié)果到列表中败玉,并把這個(gè)列表提交給訂閱者昌简,訂閱者處理后,清空buffer列表绒怨,同時(shí)接收下一次收集的結(jié)果并提交給訂閱者纯赎,周而復(fù)始
-
flatmap
把Observable產(chǎn)生的結(jié)果轉(zhuǎn)換成多個(gè)Observable,然后把這多個(gè)Observable“扁平化”成一個(gè)Observable南蹂,并依次提交產(chǎn)生的結(jié)果給訂閱者
-
concatMap操作符
flatMap操作符不同的是犬金,concatMap操作符在處理產(chǎn)生的Observable時(shí),采用的是“連接(concat)”的方式六剥,而不是“合并(merge)”的方式晚顷,這就能保證產(chǎn)生結(jié)果的順序性,也就是說(shuō)提交給訂閱者的結(jié)果是按照順序提交的疗疟,不會(huì)存在交叉的情況
-
switchMap
與flatMap操作符不同的是该默,switchMap操作符會(huì)保存最新的Observable產(chǎn)生的結(jié)果而舍棄舊的結(jié)果
-
groupBy操作符
groupBy操作符是對(duì)源Observable產(chǎn)生的結(jié)果進(jìn)行分組,形成一個(gè)類型為GroupedObservable的結(jié)果集策彤,GroupedObservable中存在一個(gè)方法為getKey()栓袖,可以通過(guò)該方法獲取結(jié)果集的Key值
-
cast操作符
而cast操作符主要是做類型轉(zhuǎn)換的
-
scan操作符
scan操作符通過(guò)遍歷源Observable產(chǎn)生的結(jié)果,依次對(duì)每一個(gè)結(jié)果項(xiàng)按照指定規(guī)則進(jìn)行運(yùn)算店诗,計(jì)算后的結(jié)果作為下一個(gè)迭代項(xiàng)參數(shù)裹刮,每一次迭代項(xiàng)都會(huì)把計(jì)算結(jié)果輸出給訂閱者
-
window操作符
window操作符非常類似于buffer操作符,區(qū)別在于buffer操作符產(chǎn)生的結(jié)果是一個(gè)List緩存庞瘸,而window操作符產(chǎn)生的結(jié)果是一個(gè)Observable捧弃,訂閱者可以對(duì)這個(gè)結(jié)果Observable重新進(jìn)行訂閱處理
3、Observable的過(guò)濾操作符
-
debounce操作符
debounce操作符對(duì)源Observable每產(chǎn)生一個(gè)結(jié)果后,如果在規(guī)定的間隔時(shí)間內(nèi)沒(méi)有別的結(jié)果產(chǎn)生违霞,則把這個(gè)結(jié)果提交給訂閱者處理嘴办,否則忽略該結(jié)果。
-
distinct操作符
distinct操作符對(duì)源Observable產(chǎn)生的結(jié)果進(jìn)行過(guò)濾买鸽,把重復(fù)的結(jié)果過(guò)濾掉户辞,只輸出不重復(fù)的結(jié)果給訂閱者,非常類似于SQL里的distinct關(guān)鍵字癞谒。
-
elementAt操作符
elementAt操作符在源Observable產(chǎn)生的結(jié)果中,僅僅把指定索引的結(jié)果提交給訂閱者刃榨,索引是從0開始的
-
filter操作符
filter操作符是對(duì)源Observable產(chǎn)生的結(jié)果按照指定條件進(jìn)行過(guò)濾弹砚,只有滿足條件的結(jié)果才會(huì)提交給訂閱者
-
ofType操作符
ofType操作符類似于filter操作符,區(qū)別在于ofType操作符是按照類型對(duì)結(jié)果進(jìn)行過(guò)濾
-
first操作符
first操作符是把源Observable產(chǎn)生的結(jié)果的第一個(gè)提交給訂閱者枢希,first操作符可以使用elementAt(0)和take(1)替代
-
single操作符
single操作符是對(duì)源Observable的結(jié)果進(jìn)行判斷桌吃,如果產(chǎn)生的結(jié)果滿足指定條件的數(shù)量不為1,則拋出異常苞轿,否則把滿足條件的結(jié)果提交給訂閱者
-
last操作符
last操作符把源Observable產(chǎn)生的結(jié)果的最后一個(gè)提交給訂閱者茅诱,last操作符可以使用takeLast(1)替代
-
ignoreElements操作符
ignoreElements操作符忽略所有源Observable產(chǎn)生的結(jié)果,只把Observable的onCompleted和onError事件通知給訂閱者搬卒。ignoreElements操作符適用于不太關(guān)心Observable產(chǎn)生的結(jié)果瑟俭,只是在Observable結(jié)束時(shí)(onCompleted)或者出現(xiàn)錯(cuò)誤時(shí)能夠收到通知
-
skip操作符
skip操作符針對(duì)源Observable產(chǎn)生的結(jié)果,跳過(guò)前面n個(gè)不進(jìn)行處理契邀,而把后面的結(jié)果提交給訂閱者處理
-
skipLast操作符
skipLast操作符針對(duì)源Observable產(chǎn)生的結(jié)果摆寄,忽略O(shè)bservable最后產(chǎn)生的n個(gè)結(jié)果,而把前面產(chǎn)生的結(jié)果提交給訂閱者處理坯门,
-
take操作符
take操作符是把源Observable產(chǎn)生的結(jié)果微饥,提取前面的n個(gè)提交給訂閱者,而忽略后面的結(jié)果
-
takeFirst操作符
takeFirst操作符類似于take操作符古戴,同時(shí)也類似于first操作符欠橘,都是獲取源Observable產(chǎn)生的結(jié)果列表中符合指定條件的前一個(gè)或多個(gè),與first操作符不同的是现恼,first操作符如果獲取不到數(shù)據(jù)肃续,則會(huì)拋出NoSuchElementException異常,而takeFirst則會(huì)返回一個(gè)空的Observable叉袍,該Observable只有onCompleted通知而沒(méi)有onNext通知痹升。
-
takeLast操作符
takeLast操作符是把源Observable產(chǎn)生的結(jié)果的后n項(xiàng)提交給訂閱者
4、Observable的組合操作符
-
combineLatest操作符
combineLatest操作符把兩個(gè)Observable產(chǎn)生的結(jié)果進(jìn)行合并畦韭,合并的結(jié)果組成一個(gè)新的Observable疼蛾。這兩個(gè)Observable中任意一個(gè)Observable產(chǎn)生的結(jié)果,都和另一個(gè)Observable最后產(chǎn)生的結(jié)果艺配,按照一定的規(guī)則進(jìn)行合并
-
join操作符
join操作符把類似于combineLatest操作符察郁,也是兩個(gè)Observable產(chǎn)生的結(jié)果進(jìn)行合并衍慎,合并的結(jié)果組成一個(gè)新的Observable,但是join操作符可以控制每個(gè)Observable產(chǎn)生結(jié)果的生命周期
-
groupJoin操作符
groupJoin操作符非常類似于join操作符皮钠,區(qū)別在于join操作符中第四個(gè)參數(shù)的傳入函數(shù)不一致
-
merge操作符
merge操作符是按照兩個(gè)Observable提交結(jié)果的時(shí)間順序稳捆,對(duì)Observable進(jìn)行合并
-
mergeDelayError操作符
從merge操作符的流程圖可以看出,一旦合并的某一個(gè)Observable中出現(xiàn)錯(cuò)誤麦轰,就會(huì)馬上停止合并乔夯,并對(duì)訂閱者回調(diào)執(zhí)行onError方法,而mergeDelayError操作符會(huì)把錯(cuò)誤放到所有結(jié)果都合并完成之后才執(zhí)行
-
startWith操作符
startWith操作符是在源Observable提交結(jié)果之前款侵,插入指定的某些數(shù)據(jù)
-
switchOnNext操作符
switchOnNext操作符是把一組Observable轉(zhuǎn)換成一個(gè)Observable末荐,轉(zhuǎn)換規(guī)則為:對(duì)于這組Observable中的每一個(gè)Observable所產(chǎn)生的結(jié)果,如果在同一個(gè)時(shí)間內(nèi)存在兩個(gè)或多個(gè)Observable提交的結(jié)果新锈,只取最后一個(gè)Observable提交的結(jié)果給訂閱者
-
zip操作符
zip操作符是把兩個(gè)observable提交的結(jié)果甲脏,嚴(yán)格按照順序進(jìn)行合并,其流程圖如下:
5妹笆、 Observable的錯(cuò)誤處理操作符
-
onErrorReturn操作符
onErrorReturn操作符是在Observable發(fā)生錯(cuò)誤或異常的時(shí)候(即將回調(diào)oError方法時(shí))块请,攔截錯(cuò)誤并執(zhí)行指定的邏輯,返回一個(gè)跟源Observable相同類型的結(jié)果拳缠,最后回調(diào)訂閱者的onComplete方法
-
onErrorResumeNext操作符
onErrorResumeNext操作符跟onErrorReturn類似墩新,只不過(guò)onErrorReturn只能在錯(cuò)誤或異常發(fā)生時(shí)只返回一個(gè)和源Observable相同類型的結(jié)果,而onErrorResumeNext操作符是在錯(cuò)誤或異常發(fā)生時(shí)返回一個(gè)Observable窟坐,也就是說(shuō)可以返回多個(gè)和源Observable相同類型的結(jié)果
-
onExceptionResumeNext操作符
onExceptionResumeNext操作符和onErrorResumeNext操作符類似抖棘,不同的地方在于onErrorResumeNext操作符是當(dāng)Observable發(fā)生錯(cuò)誤或異常時(shí)觸發(fā),而onExceptionResumeNext是當(dāng)Observable發(fā)生異常時(shí)才觸發(fā)
-
retry操作符
retry操作符是當(dāng)Observable發(fā)生錯(cuò)誤或者異常時(shí)狸涌,重新嘗試執(zhí)行Observable的邏輯切省,如果經(jīng)過(guò)n次重新嘗試執(zhí)行后仍然出現(xiàn)錯(cuò)誤或者異常,則最后回調(diào)執(zhí)行onError方法帕胆;當(dāng)然如果源Observable沒(méi)有錯(cuò)誤或者異常出現(xiàn)朝捆,則按照正常流程執(zhí)行
常用操作符(舉例學(xué)習(xí))
(1)Observable.from()。
使用from( )創(chuàng)建Observable懒豹,遍歷集合芙盘,發(fā)送每個(gè)item:
List list = new ArrayList<>();
list.add("from1");
list.add("from2");
list.add("from3");
Observable fromObservable = Observable.from(list); //遍歷list 每次發(fā)送一個(gè)
關(guān)于創(chuàng)建的操作符,我在前邊的文章里已經(jīng)總結(jié)過(guò)脸秽,這里不再列舉儒老。有興趣 的同學(xué)可以參考本系列第一篇文章 RxJava入門與提高(1)
(2)Observable.map()
用來(lái)把一個(gè)事件轉(zhuǎn)換為另一個(gè)事件。
map()操作符就是用于變換Observable對(duì)象的记餐,map操作符返回一個(gè)Observable對(duì)象针饥,這樣就可以實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用洲守,在一個(gè)Observable對(duì)象上多次使用map操作符缴守,最終將最簡(jiǎn)潔的數(shù)據(jù)傳遞給Subscriber對(duì)象。
特性:
它不必返回Observable對(duì)象返回的類型挖腰,你可以使用map操作符返回一個(gè)發(fā)出新的數(shù)據(jù)類型的observable對(duì)象。
可以對(duì)一個(gè)Observable多次使用map
用一個(gè)例子來(lái)練習(xí):
//剛創(chuàng)建的Observable是String類型的
Observable.just("Hellp Map Operator")
.map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
return 2015;//通過(guò)第一個(gè)map轉(zhuǎn)成Integer
}
}).map(new Func1<Integer, String>() {
@Override
public String call(Integer integer) {
return String.valueOf(integer);//再通過(guò)第二個(gè)map轉(zhuǎn)成String
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
});
Run起來(lái)輸出日志: 2015
(3)Observable.flatMap()
Observable.flatMap()接收一個(gè)Observable的輸出作為參數(shù)輸入练湿,同時(shí)輸出另外一個(gè)Observable猴仑。這一點(diǎn)很類似于map()。稍后總結(jié)flatMap()與map()肥哎。
舉例說(shuō)明
List<String> list = Arrays.asList("Java", "Android", "Ruby", "Ios", "Swift");
//注意這里的Func1的參數(shù)List<String>是 .just(list)返回的Observable的輸出,并且返會(huì)一個(gè)Observable<String>
Observable.just(list)
.flatMap(new Func1<List<String>, Observable<String>>() {
@Override
public Observable<String> call(List<String> strings) {
//結(jié)合from處理
return Observable.from(strings);
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println("_flatMap:"+s);
}
});
日志:
_flatMap:Java
_flatMap:Android
_flatMap:Ruby
_flatMap:Ios
_flatMap:Swift
假設(shè)這時(shí)候我們需要處理一下所獲取的結(jié)果,我們加個(gè)前綴,在保證不修改subscriber的前提下我們可以這么做:
增加個(gè)函數(shù),用來(lái)增加個(gè)前綴:
static Observable<String>addPre(String lan){
return Observable.just("addPre_"+lan);
}
Observable.just(list)
.flatMap(new Func1<List<String>, Observable<String>>() {
@Override
public Observable<String> call(List<String> strings) {
return Observable.from(strings);
}
}).flatMap(new Func1<String, Observable<String>>() {
@Override
public Observable<String> call(String s) {
//我們?cè)谶@里調(diào)用`addPre`方法,就行處理
return addPre(s);
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
});
輸出日志
addPre_Java
addPre_Android
addPre_Ruby
addPre_Ios
addPre_Swift
- 小結(jié) :flatMap()與map()
(1)flatMap()與map()變換操作完后辽俗,都是返回的Observable對(duì)象,即數(shù)據(jù)源篡诽,這樣可以繼續(xù)發(fā)射數(shù)據(jù)崖飘,或者調(diào)用subscribe去叫接收員接收數(shù)據(jù)。
(2)map()中的Func類重寫的的call()方法的入?yún)⑹? 轉(zhuǎn)換前的Observable對(duì)象 發(fā)射的數(shù)據(jù)內(nèi)容(可以理解為Observable對(duì)象里邊包含的數(shù)據(jù)內(nèi)容)霞捡,返回的數(shù)據(jù)是轉(zhuǎn)換后的Observable對(duì)象要發(fā)射的數(shù)據(jù)。
flatMap()中的Func類重寫的的call()方法的入?yún)⒁彩? 轉(zhuǎn)換前的Observable對(duì)象 發(fā)射的數(shù)據(jù)內(nèi)容薄疚,返回的數(shù)據(jù)是Observable對(duì)象碧信。
代碼片段
.map(new Func1<Integer, String>() {
@Override
public String call(Integer integer) {
return String.valueOf(integer);//再通過(guò)第二個(gè)map轉(zhuǎn)成String,返回String
}
})
*******************************************************
.flatMap(new Func1<String, Observable<String>>() {
@Override
public Observable<String> call(String s) {
//我們?cè)谶@里調(diào)用`addPre`方法,返回的是Observable<String>
return addPre(s);
}
}
(3)flatMap()處理集合街夭、數(shù)組等砰碴,map()處理單一對(duì)象數(shù)據(jù)。
(4)Buffer
Buffer操作符定期收集Observable的數(shù)據(jù)放進(jìn)一個(gè)數(shù)據(jù)包裹板丽,然后發(fā)射這些數(shù)據(jù)包裹呈枉,而不是一次發(fā)射一個(gè)值。
Buffer操作符將一個(gè)Observable變換為另一個(gè)埃碱,原來(lái)的Observable正常發(fā)射數(shù)據(jù)猖辫,變換產(chǎn)生的Observable發(fā)射這些數(shù)據(jù)的緩存集合。
RxView.clickEvents(mButton)
.buffer(2, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<ViewClickEvent>>() {
@Override
public void onCompleted() {}
@Override
public void onError(Throwable e) {}
@Override
public void onNext(List<ViewClickEvent> viewClickEvents) {
if (viewClickEvents.size() > 0) {
Toast.makeText(MainActivity.this, "2秒內(nèi)點(diǎn)擊了" + viewClickEvents.size() + "次", Toast.LENGTH_SHORT).show();
} else {
}
}
});
如果原來(lái)的Observable發(fā)射了一個(gè)onError通知砚殿,Buffer會(huì)立即傳遞這個(gè)通知啃憎,而不是首先發(fā)射緩存的數(shù)據(jù),即使在這之前緩存中包含了原始Observable發(fā)射的數(shù)據(jù)似炎。
- 再舉個(gè)栗子
將原發(fā)射出來(lái)的數(shù)據(jù)已count為單元打包之后在分別發(fā)射出來(lái)
Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
.buffer(3)
.subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
System.out.println("onNext--> " + o);
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
System.out.println("onError--> " + throwable.getMessage());
}
}, new Action0() {
@Override
public void call() {
System.out.println("onComplete");
}
});
日志:
onNext--> [1, 2, 3]
onNext--> [4, 5, 6]
onNext--> [7, 8, 9]
onNext--> [10]
onComplete
GroupBy
GroupBy操作符將原始Observable發(fā)射的數(shù)據(jù)按照key來(lái)拆分成一些小的Observable辛萍,然后這些小的Observable分別發(fā)射其所包含的的數(shù)據(jù)。
Observable.just(1, 2, 3, 4, 5, 6)
.groupBy(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
return integer % 2 == 0;
}
})
.subscribe(new Action1<GroupedObservable<Boolean, Integer>>() {
@Override
public void call(final GroupedObservable<Boolean, Integer> observable) {
//toList方法轉(zhuǎn)換為Observable<List<T>>
observable.toList().subscribe(new Action1<List<Integer>>() {
@Override
public void call(List<Integer> integers) {
Log.d(TAG, "key=" + observable.getKey() + ",values=" + integers);
//key=false,values=[1, 3, 5]
//key=true,values=[2, 4, 6]
}
});
}
});
Filter
Filter返回滿足過(guò)濾條件的數(shù)據(jù)羡藐。
Observable.from(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9})
.filter(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
return integer < 5;
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.d(TAG, "integer=" + integer); //1,2,3,4
}
});
First
First操作符返回第一條數(shù)據(jù)或者返回滿足條件的第一條數(shù)據(jù)贩毕。
Observable.from(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9})
.first()
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.d(TAG, "integer=" + integer); //1 返回第一條數(shù)據(jù)
}
});
Observable.from(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9})
.first(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
return integer > 3;
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.d(TAG, "integer=" + integer); //4 返回滿足條件的第一條數(shù)據(jù)
}
});
Last
Last操作符返回最后一條數(shù)據(jù)或者滿足條件的最后一條數(shù)據(jù)。
Skip
Skip操作符將源Observable發(fā)射的數(shù)據(jù)過(guò)濾掉前n項(xiàng)仆嗦。
Observable.from(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9})
.skip(6)
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.d(TAG, "integer=" + integer); //7,8,9
}
});
Take
Take操作符只取前n項(xiàng)辉阶。
Observable.from(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9})
.take(2)
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.d(TAG, "integer=" + integer); //1,2
}
});
- 說(shuō)明:根據(jù)我的學(xué)習(xí)和研究,個(gè)人覺(jué)得filter、first睛藻、等操作符與map的用法類似启上,感覺(jué)都可以用map()自己封裝。
本文暫時(shí)總結(jié)這些店印,如果以后有總結(jié)冈在,在更新。
關(guān)于線程控制按摘,放在下篇講解包券。
歡迎繼續(xù)收看:RxJava入門與提高-線程控制Scheduler篇(4)
作者:ZhangYushui
來(lái)源:簡(jiǎn)書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)炫贤,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處溅固。