Activity的4種啟動(dòng)模式

登錄

小豬快跑22

關(guān)注

一個(gè)實(shí)例讓你徹底明白Activity的4種啟動(dòng)模式

原創(chuàng) 2017年08月03日 14:46:54 閱讀 792

首先,我們得有一個(gè)概念,就是啟動(dòng)的Activity都是放在相應(yīng)的任務(wù)棧中。按Back鍵的時(shí)候Activity會(huì)從任務(wù)棧中返回,當(dāng)任務(wù)棧為空時(shí)系統(tǒng)就會(huì)回收這個(gè)任務(wù)棧。

那么我們?yōu)槭裁葱枰@4中啟動(dòng)模式呢?我們新建Activity的并在Androidmanifest.xml文件中注冊(cè)的時(shí)候,默認(rèn)的就是standard模式,如果你在這個(gè)Activity中一直通過(guò)startActivity來(lái)啟動(dòng)這個(gè)Activity,那么任務(wù)棧中就會(huì)有許多該Activity,你要多次按返回鍵才能返回到launcher頁(yè)面。這樣的體驗(yàn)簡(jiǎn)直糟糕啊。

模式1:standard

標(biāo)準(zhǔn)模式,也是Activity默認(rèn)的啟動(dòng)方式。這個(gè)在Androidmanifest.xml中的Activity里聲明,如下:

<activity

? ? ? ? ? ? android:name="luanchmode.ActivityB"

? ? ? ? ? ? android:launchMode="standard" />

1

2

3

以這種方式啟動(dòng)的Activity每次都會(huì)創(chuàng)建一個(gè)新的實(shí)例,不管這個(gè)實(shí)例是否已經(jīng)存在。

比如在 Activity A 中啟動(dòng) A,那么任務(wù)棧中會(huì)有2個(gè)A。

例子1:ActivityA 中以standard啟動(dòng) ActivityA,代碼如下:

manefest.xml:

<activity android:name="luanchmode.ActivityA"

? ? ? ? ? ? android:launchMode="standard">

? ? ? ? ? ? <intent-filter>

? ? ? ? ? ? ? ? <action android:name="android.intent.action.MAIN" />

? ? ? ? ? ? ? ? <category android:name="android.intent.category.LAUNCHER" />

? ? ? ? ? ? </intent-filter>

? ? ? ? </activity>

1

2

3

4

5

6

7

8

ActivityA.java:

public class ActivityA extends Activity {

? ? @Override

? ? protected void onCreate(@Nullable Bundle savedInstanceState) {

? ? ? ? Log.e("xxx", "ActivityA, onCreate");

? ? ? ? super.onCreate(savedInstanceState);

? ? ? ? TextView tv = new TextView(this);

? ? ? ? tv.setTextSize(20);

? ? ? ? tv.setText("This is activityA");

? ? ? ? tv.setGravity(Gravity.CENTER);

? ? ? ? tv.setBackgroundColor(Color.parseColor("#999999"));

? ? ? ? setContentView(tv, new ViewGroup.LayoutParams(200, 100));

? ? ? ? tv.setFocusable(true);

? ? ? ? tv.requestFocus();

? ? ? ? tv.setOnClickListener(new View.OnClickListener() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onClick(View v) {

? ? ? ? ? ? ? ? Log.e("xxx","onclick A");

? ? ? ? ? ? ? ? Intent intent = new Intent(ActivityA.this, ActivityA.class);

? ? ? ? ? ? ? ? startActivity(intent);

? ? ? ? ? ? }

? ? ? ? });

? ? }

? ? @Override

? ? protected void onNewIntent(Intent intent) {

? ? ? ? Log.e("xxx", "ActivityA, onNewIntent");

? ? ? ? super.onNewIntent(intent);

? ? }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

log如下:

08-02 19:33:45.720 11791-11791/com.example.aidlclient E/xxx: ActivityA, onCreate

08-02 19:33:59.192 11791-11791/com.example.aidlclient E/xxx: onclick A

08-02 19:33:59.207 11791-11791/com.example.aidlclient E/xxx: ActivityA, onCreate

1

2

3

可以看到 點(diǎn)擊跳轉(zhuǎn)到 ActivityA 的時(shí)候,任然會(huì)執(zhí)行 onCreate方法。

通過(guò)指令:adb shell dumpsys activity 查看任務(wù)棧:

? Running activities (most recent first):

? ? TaskRecord{2470eca6 #1587 A=com.example.aidlclient U=0 sz=2}

? ? ? Run #1: ActivityRecord{3456102c u0 com.example.aidlclient/luanchmode.ActivityA t1587}

? ? ? Run #0: ActivityRecord{352831f7 u0 com.example.aidlclient/luanchmode.ActivityA t1587}

1

2

3

4

可以看出任務(wù)棧中有2個(gè)ActivityA 。

模式2:singleTop 棧頂復(fù)用模式

在這種模式下啟動(dòng)的Activity,如果該Activity已經(jīng)位于棧頂,那么就不會(huì)去創(chuàng)建新的實(shí)例,調(diào)用該Activity的onNewIntent方法。如果不在棧頂還是會(huì)新建一個(gè)Activity實(shí)例。

例子: A 啟動(dòng)B,B的啟動(dòng)模式為singleTop ,然后 B 再啟動(dòng) B;

AndroidManifest.xml如下:

<activity android:name="luanchmode.ActivityA"

? ? ? ? ? ? android:launchMode="standard">

? ? ? ? ? ? <intent-filter>

? ? ? ? ? ? ? ? <action android:name="android.intent.action.MAIN" />

? ? ? ? ? ? ? ? <category android:name="android.intent.category.LAUNCHER" />

? ? ? ? ? ? </intent-filter>

? ? ? ? </activity>

? ? ? ? <activity

? ? ? ? ? ? android:name="luanchmode.ActivityB"

? ? ? ? ? ? android:launchMode="singleTop" />

? ? ? ? <activity

1

2

3

4

5

6

7

8

9

10

11

12

AcitivityA 和 ActivityB 中的部分代碼如下:

tv.setOnClickListener(new View.OnClickListener() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onClick(View v) {

? ? ? ? ? ? ? ? Intent intent = new Intent(ActivityA.this, ActivityB.class);

? ? ? ? ? ? ? ? startActivity(intent);

? ? ? ? ? ? }

? ? ? ? });

1

2

3

4

5

6

7

tv.setOnClickListener(new View.OnClickListener() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onClick(View v) {

? ? ? ? ? ? ? ? Intent intent = new Intent(ActivityB.this, ActivityB.class);

//? ? ? ? ? ? ? ? intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

? ? ? ? ? ? ? ? startActivity(intent);

? ? ? ? ? ? }

? ? ? ? });

1

2

3

4

5

6

7

8

log如下:

08-03 09:13:01.841 26939-26939/com.example.aidlclient E/xxx: ActivityA, onCreate

08-03 09:18:08.513 26939-26939/com.example.aidlclient E/xxx: ActivityB, onCreate

08-03 09:18:09.983 26939-26939/com.example.aidlclient E/xxx: ActivityB, onNewIntent

1

2

3

可以看出從A跳轉(zhuǎn)到B時(shí),由于棧中沒(méi)有B,所以會(huì)新建B的實(shí)例并放入棧中;從B跳到B中,由于棧頂以經(jīng)是B了,所以不會(huì)新建實(shí)例,而是會(huì)調(diào)用B的onNewIntent方法。

我們看看任務(wù)棧中是不是只有A和B ?

Running activities (most recent first):

? ? TaskRecord{351e6f43 #1596 A=com.example.aidlclient U=0 sz=2}

? ? Run #1: ActivityRecord{2925d326 u0 com.example.aidlclient/luanchmode.ActivityB t1596}

? ? Run #0: ActivityRecord{1e64c90 u0 com.example.aidlclient/luanchmode.ActivityA t1596}

1

2

3

4

可以看到任務(wù)棧中只有A和B,也可以看出如果如果B在棧頂就不會(huì)創(chuàng)建新的實(shí)例。接下來(lái)我們看看如果B不是棧頂,那又會(huì)如何?

接下來(lái)的例子是這樣的 A 啟動(dòng) B, B 啟動(dòng) C, C 再啟動(dòng) B:

代碼很簡(jiǎn)單就不貼A和B的了,貼下C的。

tv.setOnClickListener(new View.OnClickListener() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onClick(View v) {

? ? ? ? ? ? ? ? Intent intent = new Intent(ActivityC.this, ActivityB.class);

//? ? ? ? ? ? ? ? intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

? ? ? ? ? ? ? ? startActivity(intent);

? ? ? ? ? ? }

? ? ? ? });

1

2

3

4

5

6

7

8

log如下:

08-03 09:36:35.259 17108-17108/com.example.aidlclient E/xxx: ActivityA, onCreate

08-03 09:36:39.482 17108-17108/com.example.aidlclient E/xxx: ActivityB, onCreate

08-03 09:36:40.979 17108-17108/com.example.aidlclient E/xxx: ActivityC onCreate

08-03 09:36:42.171 17108-17108/com.example.aidlclient E/xxx: ActivityB, onCreate

1

2

3

4

可以看出,C再次啟動(dòng)B的時(shí)候B會(huì)創(chuàng)建新的實(shí)例。我們查看下任務(wù)棧看看是什么樣的,任務(wù)棧中應(yīng)該是 A->B->C->B.

Running activities (most recent first):

? ? ? TaskRecord{1d40b112 #1602 A=com.example.aidlclient U=0 sz=4}

? ? ? ? Run #3: ActivityRecord{3482a81a u0 com.example.aidlclient/luanchmode.ActivityB t1602}

? ? ? ? Run #2: ActivityRecord{a101309 u0 com.example.aidlclient/luanchmode.ActivityC t1602}

? ? ? ? Run #1: ActivityRecord{3575d5f8 u0 com.example.aidlclient/luanchmode.ActivityB t1602}

? ? ? ? Run #0: ActivityRecord{31f704f3 u0 com.example.aidlclient/luanchmode.ActivityA t1602}

1

2

3

4

5

6

以上2個(gè)例子驗(yàn)證了,以singleTop啟動(dòng)的Activity,如果棧頂是該Activity,那么不會(huì)創(chuàng)建新的實(shí)例,如果該Activity不在棧頂,要啟動(dòng)這個(gè)Activity還是會(huì)創(chuàng)建新的實(shí)例。

模式3:singleTask 站內(nèi)復(fù)用模式

在這種模式下,如果Activity存在于棧中,那么啟動(dòng)這個(gè)Activity不會(huì)創(chuàng)建新的實(shí)例,而是會(huì)調(diào)用onNewIntent(),并且將該Activity上面的所有Activity移出棧;當(dāng)以singleTask 啟動(dòng)一個(gè)Activity的時(shí)候,首先去判斷是否要為該Activity去創(chuàng)建一個(gè)任務(wù)棧?怎么判斷的我們下面再講,如果需要的話,那么就會(huì)創(chuàng)建一個(gè)任務(wù)棧,并且將該Activity放入棧中;如果不需要的話,直接將該Activity放入當(dāng)前的任務(wù)棧中。

現(xiàn)在我們來(lái)講怎么判斷是否需要?jiǎng)?chuàng)建任務(wù)棧?任務(wù)棧的創(chuàng)建跟taskAffinity的屬性相關(guān),每個(gè)Activity都有taskAffinity屬性,這個(gè)屬性指出了它希望進(jìn)入的Task。如果一個(gè)Activity沒(méi)有顯式的指明該Activity的taskAffinity,那么它的這個(gè)屬性就等于Application指明的taskAffinity,如果Application也沒(méi)有指明,那么該taskAffinity的值就等于包名。

在singleTask 模式下,如果你在要啟動(dòng)的Activity中設(shè)置taskAffinity屬性,且該屬性的值不等于包名,那么就需要?jiǎng)?chuàng)建任務(wù)棧,否則不需要?jiǎng)?chuàng)建。taskAffinity的屬性設(shè)置如下:

<activity

? ? ? ? ? ? android:name="luanchmode.ActivityB"

? ? ? ? ? ? android:launchMode="singleTask"

? ? ? ? ? ? android:taskAffinity="com.example.aidlclient.test" />

1

2

3

4

而我的應(yīng)用的包名是:package=”com.example.aidlclient”>

例子1:A中啟動(dòng)B,B中啟動(dòng)C,然后C啟動(dòng)D,D再啟動(dòng)B,其中A和C、D是standard模式,B是singleTask模式。

manifest.xml如下:

<activity

? ? ? ? ? ? android:name="luanchmode.ActivityA"

? ? ? ? ? ? android:launchMode="standard">

? ? ? ? ? ? <intent-filter>

? ? ? ? ? ? ? ? <action android:name="android.intent.action.MAIN" />

? ? ? ? ? ? ? ? <category android:name="android.intent.category.LAUNCHER" />

? ? ? ? ? ? </intent-filter>

? ? ? ? </activity>

? ? ? ? <activity

? ? ? ? ? ? android:name="luanchmode.ActivityB"

? ? ? ? ? ? android:launchMode="singleTask" />

? ? ? ? <activity android:name="luanchmode.ActivityC" />

? ? ? ? <activity android:name="luanchmode.ActivityD" />

1

2

3

4

5

6

7

8

9

10

11

12

13

14

還是先看log:

08-03 10:40:33.896 14823-14823/? E/xxx: ActivityA, onCreate

08-03 10:40:42.777 14823-14823/? E/xxx: ActivityB, onCreate

08-03 10:40:44.169 14823-14823/? E/xxx: ActivityC onCreate

08-03 10:40:45.218 14823-14823/? E/xxx: ActivityD onCreate

08-03 10:40:46.696 14823-14823/? E/xxx: ActivityB, onNewIntent

1

2

3

4

5

6

7

A->B : 由于棧中沒(méi)有B且未對(duì)B設(shè)置android:taskAffinity屬性,所以直接創(chuàng)建B的實(shí)例并放在該棧中;

B->C->D:創(chuàng)建C和D的實(shí)例并放到棧中

D->B : 由于B已經(jīng)存在棧中,所以直接將B移到棧頂,調(diào)用onNewIntent(),并且B上面的Activity全部出棧。

任務(wù)棧如下:

Running activities (most recent first):

? ? ? TaskRecord{33b61cae #1611 A=com.example.aidlclient U=0 sz=2}

? ? ? ? Run #1: ActivityRecord{2291853f u0 com.example.aidlclient/luanchmode.ActivityB t1611}

? ? ? ? Run #0: ActivityRecord{390ec8d6 u0 com.example.aidlclient/luanchmode.ActivityA t1611}

1

2

3

4

可以看到A和B都在同一個(gè)棧中,且從D跳轉(zhuǎn)到B的時(shí)候,B上面的Activity全部出棧。

例子2:為B設(shè)置android:taskAffinity=”com.example.aidlclient.test”和包名不一樣

manifest.xml如下:

<activity

? ? ? ? ? ? android:name="luanchmode.ActivityB"

? ? ? ? ? ? android:launchMode="singleTask"

? ? ? ? ? ? android:taskAffinity="com.example.aidlclient.test"/>

1

2

3

4

log如下:

08-03 10:45:24.335 15566-15566/com.example.aidlclient E/xxx: ActivityA, onCreate

08-03 10:45:38.858 15566-15566/com.example.aidlclient E/xxx: ActivityB, onCreate

08-03 10:45:40.912 15566-15566/com.example.aidlclient E/xxx: ActivityC onCreate

08-03 10:45:42.694 15566-15566/com.example.aidlclient E/xxx: ActivityD onCreate

08-03 10:45:44.406 15566-15566/com.example.aidlclient E/xxx: ActivityB, onNewIntent

1

2

3

4

5

A->B:由于B不存在與任務(wù)棧中,所以會(huì)新建B的實(shí)例,至于有沒(méi)有創(chuàng)建對(duì)應(yīng)的棧,log中看不出,等下通過(guò)adb來(lái)查看。

B->C->D:正常啟動(dòng),創(chuàng)建C和D的實(shí)例并放入任務(wù)棧

D->B:由于B存在于任務(wù)棧中,所以直接將B移到棧頂,調(diào)用onNewIntent(),并且B上面的Activity全部出棧。

利用 adb shell dumpsys activity查看任務(wù)棧情況:

先看 A->B->C->D:的任務(wù)棧詳情:

Running activities (most recent first):

? ? ? TaskRecord{3874c557 #1618 A=com.example.aidlclient.test U=0 sz=3}

? ? ? ? Run #3: ActivityRecord{84f09e0 u0 com.example.aidlclient/luanchmode.ActivityD t1618}

? ? ? ? Run #2: ActivityRecord{255bda6b u0 com.example.aidlclient/luanchmode.ActivityC t1618}

? ? ? ? Run #1: ActivityRecord{2ac8c0a u0 com.example.aidlclient/luanchmode.ActivityB t1618}

? ? ? TaskRecord{1d0e98b2 #1617 A=com.example.aidlclient U=0 sz=1}

? ? ? ? Run #0: ActivityRecord{3863a8b u0 com.example.aidlclient/luanchmode.ActivityA t1617}

1

2

3

4

5

6

7

可以看出 B、C、D在一個(gè)任務(wù)棧,A在另外一個(gè)任務(wù)棧。

先看 A->B->C->D->B:的任務(wù)棧詳情

? Running activities (most recent first):

? ? ? TaskRecord{3874c557 #1618 A=com.example.aidlclient.test U=0 sz=1}

? ? ? ? Run #1: ActivityRecord{2ac8c0a u0 com.example.aidlclient/luanchmode.ActivityB t1618}

? ? ? TaskRecord{1d0e98b2 #1617 A=com.example.aidlclient U=0 sz=1}

? ? ? ? Run #0: ActivityRecord{3863a8b u0 com.example.aidlclient/luanchmode.ActivityA t1617}

1

2

3

4

5

可以看出,從B->D后,會(huì)將B上面的Activity全部移除出棧。

模式4:singleInstance

這種模式下,Activity只能單獨(dú)的存在一個(gè)任務(wù)棧中,舉個(gè)例子,就是說(shuō)A以singleInstance 啟動(dòng)了B,那么會(huì)創(chuàng)建一個(gè)任務(wù)棧,并把B放到創(chuàng)建的任務(wù)棧中,該棧只能有B的存在。

例子1:A啟動(dòng)B,B啟動(dòng)C,其中A、C的啟動(dòng)模式為standard,D的啟動(dòng)模式為singleInstance 。

manifest.xml如下:

<activity

? ? ? ? ? ? android:name="luanchmode.ActivityA"

? ? ? ? ? ? android:launchMode="standard">

? ? ? ? ? ? <intent-filter>

? ? ? ? ? ? ? ? <action android:name="android.intent.action.MAIN" />

? ? ? ? ? ? ? ? <category android:name="android.intent.category.LAUNCHER" />

? ? ? ? ? ? </intent-filter>

? ? ? ? </activity>

? ? ? ? <activity

? ? ? ? ? ? android:name="luanchmode.ActivityB"

? ? ? ? ? ? android:launchMode="singleInstance" />

? ? ? ? <activity android:name="luanchmode.ActivityC" />

1

2

3

4

5

6

7

8

9

10

11

12

13

log如下:

08-03 11:07:29.810 5490-5490/com.example.aidlclient E/xxx: ActivityA, onCreate

08-03 11:07:37.698 5490-5490/com.example.aidlclient E/xxx: ActivityB, onCreate

08-03 11:07:41.398 5490-5490/com.example.aidlclient E/xxx: ActivityC onCreate

08-03 11:08:37.934 5490-5490/com.example.aidlclient E/xxx: ActivityB, onNewIntent

1

2

3

4

A->B:由于不存在B需要的任務(wù)棧,所以先創(chuàng)建任務(wù)棧,然后將B壓入棧

B->C:正常啟動(dòng),創(chuàng)建C的實(shí)例并入棧。

C->B:不會(huì)創(chuàng)建B新的實(shí)例,而是調(diào)用onNewIntent()。

先看 A->B->C的任務(wù)棧詳情:

Running activities (most recent first):

? ? ? TaskRecord{2d63becf #1621 A=com.example.aidlclient U=0 sz=2}

? ? ? ? Run #2: ActivityRecord{340fa242 u0 com.example.aidlclient/luanchmode.ActivityC t1621}

? ? ? TaskRecord{323683de #1622 A=com.example.aidlclient U=0 sz=1}

? ? ? ? Run #1: ActivityRecord{2aef961d u0 com.example.aidlclient/luanchmode.ActivityB t1622}

? ? ? TaskRecord{2d63becf #1621 A=com.example.aidlclient U=0 sz=2}

? ? ? ? Run #0: ActivityRecord{3486b42c u0 com.example.aidlclient/luanchmode.ActivityA t1621}

1

2

3

4

5

6

7

A->B 會(huì)新建一個(gè)任務(wù)棧然后創(chuàng)建B的實(shí)例并壓入該棧;B->C 直接創(chuàng)建C的實(shí)例并壓入之前A所在的棧。

Activity的4種啟動(dòng)模式就寫(xiě)到這里,下面會(huì)寫(xiě)Intent中設(shè)置flag,以及taskAffinity。

閱讀全文

舉報(bào)

小豬快跑22訪問(wèn)量 6萬(wàn)+ 原創(chuàng) 54 博主更多文章>

Android中Activity的使用,簡(jiǎn)單實(shí)例講解

qq_32175491 10449次閱讀 2016-12-27 16:09:12

activity例子

shiyanming1223 8317次閱讀 2015-02-28 22:11:30

通過(guò)官網(wǎng)的一個(gè)例子來(lái)看Activity的分組管理

chuyouyinghe 302次閱讀 2016-05-20 10:51:25

如何獲取Activity的實(shí)例

u011663865 1394次閱讀 2016-04-02 22:21:38

徹底弄懂Activity四大啟動(dòng)模式

mynameishuangshuai 70645次閱讀 2016-05-24 16:04:24

Activity的四種啟動(dòng)模式和應(yīng)用場(chǎng)景

wangxueming 5020次閱讀 2017-06-15 17:56:44

activity的四種啟動(dòng)模式區(qū)別_launchmode圖文詳解

androidstar_cn 1409次閱讀 2016-10-03 23:55:06

[Android開(kāi)發(fā)]Activity的四種啟動(dòng)模式及其應(yīng)用場(chǎng)景

CodeEmperor 26320次閱讀 2016-01-08 11:39:41

Activity的4種啟動(dòng)模式

wl1fy 74次閱讀 2017-03-28 18:08:42

更多相關(guān)文章

CSDN

CSDN精彩內(nèi)容推薦

查看熊掌號(hào)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 從前文知道,Android中任務(wù)棧(Task)會(huì)隨著啟動(dòng)模式的不同而表現(xiàn)出不同的狀況。其實(shí)除了在Mainfest中...
    張利強(qiáng)閱讀 13,704評(píng)論 4 7
  • 今天想來(lái)說(shuō)說(shuō)Android的啟動(dòng)模式,一來(lái)自己做一個(gè)總結(jié),二來(lái)如果能幫助到別人就更好了~ 首先來(lái)看一個(gè)實(shí)際的業(yè)務(wù)場(chǎng)...
    JxYoung閱讀 8,059評(píng)論 27 62
  • 【Android Activity】 什么是 Activity? 四大組件之一,通常一個(gè)用戶(hù)交互界面對(duì)應(yīng)一個(gè) ac...
    Rtia閱讀 3,849評(píng)論 3 18
  • 新的一年已經(jīng)開(kāi)始了,許多人又開(kāi)始像往年一樣,信心滿(mǎn)滿(mǎn)的開(kāi)始制定2017年的各項(xiàng)計(jì)劃,給自己設(shè)置宏偉的目標(biāo)。滿(mǎn)滿(mǎn)的一...
    c4801閱讀 846評(píng)論 0 0
  • 這是仿微信的圖片選擇器。 項(xiàng)目地址:PictureSelector 簡(jiǎn)介 1、來(lái)源:相機(jī),本地圖片媒體庫(kù)中jpg和...
    arvinljw閱讀 22,901評(píng)論 31 14