23 個安卓重難點突破,帶你吃透 Service 知識點「長達 1W+ 字」

前言

  • Android 有一段時間了,想必很多人也和我同樣,平時常常東學西湊,感受知識點有些凌亂難成體系。因此趁着這幾天忙裏偷閒,把學的東西概括下,捋捋思路。

這篇文章主要針對 Service 相關的知識點,進行詳細的梳理,祝你們食用愉快!html

文章目錄

文章目錄

方便你們學習,我在 GitHub 創建了 倉庫


第一篇:Service 是什麼


Service 是什麼

1.1 什麼是 Service

什麼是 Service

  • Service (服務) 是一個一種能夠在後臺執行長時間運行操做而沒有用戶界面的應用組件。
  • 服務可由其餘應用組件啓動(如 Activity ),服務一旦被啓動將在後臺一直運行,即便啓動服務的組件( Activity )已銷燬也不受影響。
  • 此外,組件能夠綁定到服務,以與之進行交互,甚至是執行進程間通訊 ( IPC )。

1.2 Service 一般老是稱之爲 「後臺服務」

Service 一般老是稱之爲 「後臺服務」

  • 其中 「後臺」 一詞是相對於前臺而言的,具體是指:其自己的運行並不依賴於用戶可視的 UI 界面
  • 所以,從實際業務需求上來理解,Service 的適用場景應該具有如下條件:
  1. 並不依賴於用戶可視的 UI 界面(固然,這一條其實也不是絕對的,如前臺 Service 就是與 Notification 界面結合使用的)git

  2. 具備較長時間的運行特性github

  3. 注意: 是運行在主線程當中的面試

1.3 服務進程

服務進程

  • 服務進程是經過 startService() 方法啓動的進程,但不屬於前臺進程和可見進程。例如,在後臺播放音樂或者在後臺下載就是服務進程。算法

  • 系統保持它們運行,除非沒有足夠內存來保證全部的前臺進程和可視進程。數據庫

第二篇:生命週期


生命週期

2.1 Service 的生命週期

  • 咱們先來看看 Service 的生命週期 的基本流程
  • 一張聞名遐邇的圖
    Service的生命週期

2.2 開啓 Service 的兩種方式

開啓 Service 的兩種方式

2.2.1 startService()

startService()

  1. 定義一個類繼承 Service微信

  2. Manifest.xml 文件中配置該 Service網絡

  3. 使用 ContextstartService(intent) 方法開啓服務。

  4. 使用 ContextstopService(intent) 方法關閉服務。

  5. 該啓動方式,app 殺死、Activity 銷燬沒有任何影響,服務不會中止銷燬。

2.2.2 bindService()

bindService()

  1. 建立 BindService 服務端,繼承 Service 並在類中,建立一個實現 IBinder 接口的實例對象,並提供公共方法給客戶端( Activity )調用。

  2. onBinder() 回調方法返回該 Binder 實例。

  3. 在客戶端( Activity )中, 從 onServiceConnection() 回調方法參數中接收 Binder ,經過 Binder 對象便可訪問 Service 內部的數據。

  4. manifests 中註冊 BindService , 在客戶端中調用 bindService() 方法開啓綁定 Service , 調用 unbindService() 方法註銷解綁 Service

  5. 該啓動方式依賴於客戶端生命週期,當客戶端 Activity 銷燬時, 沒有調用 unbindService() 方法 , Service 也會中止銷燬。

2.3 Service 有哪些啓動方法,有什麼區別,怎樣停用 Service

Service 的啓動與綁定

  • Service 的生命週期中,被回調的方法比 Activity 少一些,只有 onCreate , onStart , onDestroy , onBindonUnbind

  • 一般有兩種方式啓動一個 Service , 他們對 Service 生命週期的影響是不同的。

2.3.1 經過 startService

被啓動的服務的生命週期

  • Service 會經歷 onCreateonStart ,而後處於運行狀態,stopService 的時候調用 onDestroy 方法。

若是是調用者本身直接退出而沒有調用 stopService 的話,Service 會一直在後臺運行。

2.3.2 經過 bindService

被綁定的服務的生命週期

Service 會運行 onCreate ,而後是調用 onBind , 這個時候調用者和 Service 綁定在一塊兒。調用者退出了,Srevice 就會調用 onUnbind -> onDestroyed 方法。

所謂綁定在一塊兒就共存亡了。調用者也能夠經過調用 unbindService 方法來中止服務,這時候 Srevice 就會調用 onUnbind -> onDestroyed 方法。

2.3.3 須要注意的是若是這幾個方法交織在一塊兒的話,會出現什麼狀況呢?

被啓動又被綁定的服務的生命週期

  1. 一個原則是 ServiceonCreate 的方法只會被調用一次,就是你不管多少次的 startServicebindServiceService 只被建立一次。

  2. 若是先是 bind 了,那麼 start 的時候就直接運行 ServiceonStart 方法,若是先是 start ,那麼 bind 的時候就直接運行 onBind 方法。

  3. 若是 service 運行期間調用了 bindService ,這時候再調用 stopService 的話,service 是不會調用 onDestroy 方法的,servicestop 不掉了,只能調用 UnbindService , service 就會被銷燬

  4. 若是一個 service 經過 startServicestart 以後,屢次調用 startService 的話,service 會屢次調 用 onStart 方法。屢次調用 stopService 的話,service 只會調用一次 onDestroyed 方法。

  5. 若是一個 service 經過 bindServicestart 以後,屢次調用 bindService 的話,service 只會調用一次 onBind 方法。屢次調用 unbindService 的話會拋出異常。

第三篇:Service 與 Thread


Service 與 Thread

3.1 Service 和 Thread 的區別

Service 和 Thread 的區別

3.1.1 首先第一點定義上

定義上

  1. thread 是程序執行的最小單元,他是分配 cpu 的基本單位安卓系統中,咱們常說的主線程,UI 線程,也是線程的一種。固然,線程裏面還能夠執行一些耗時的異步操做。
  2. service 你們記住,它是安卓中的一種特殊機制,service 是運行在主線程當中的,因此說它不能作耗時操做,它是由系統進程託管,其實 service 也是一種輕量級的 IPC 通訊,由於 activity 能夠和 service 綁定,能夠和 service 進行數據通訊。
  3. 並且有一種狀況,activityservice 是處於不一樣的進程當中,因此說它們之間的數據通訊,要經過 IPC 進程間通訊的機制來進行操做。

3.1.2 第二點是在實際開發的過程中

第二點是在實際開發的過程中

  1. 在安卓系統當中,線程通常指的是工做線程,就是後臺線程,作一些耗時操做的線程,而主線程是一種特殊的線程,它只是負責處理一些 UI 線程的繪製,UI 線程裏面絕對不能作耗時操做,這裏是最基本最重要的一點。(這是 Thread 在實際開發過程中的應用)
  2. service 是安卓當中,四大組件之一,通常狀況下也是運行在主線程當中,所以 service 也是不能夠作耗時操做的,不然系統會報 ANR 異常( ANR 全稱:Application Not Responding ),就是程序沒法作出響應。
  3. 若是必定要在 service 裏面進行耗時操做,必定要記得開啓單獨的線程去作。

3.1.3 第三點是應用場景上

應用場景上

  1. 當你須要執行耗時的網絡,或者這種文件數據的查詢,以及其它阻塞 UI 線程的時候,都應該使用工做線程,也就是開啓一個子線程的方式。
  2. 這樣才能保證 UI 線程不被佔用,而影響用戶體驗。
  3. service 來講,咱們常常須要長時間在後臺運行,並且不須要進行交互的狀況下才會使用到服務,好比說,咱們在後臺播放音樂,開啓天氣預報的統計,還有一些數據的統計等等。

3.2 爲何要用 Service 而不是 Thread

爲何要用 Service 而不是 Thread

  • Thread 的運行是獨立於 Activity 的,也就是當一個 Activityfinish 以後,若是沒有主動中止 Thread 或者 Thread 中的 run 沒有執行完畢時那麼這個線程會一直執行下去。
  • 所以這裏會出現一個問題:當 Activityfinish 以後,你再也不持有該 Thread 的引用。
  • 另外一方面,你沒有辦法在不一樣的 Activity 中對同一 Thread 進行控制。

3.3 Service 裏面是否能執行耗時的操做

Service 裏面是否能執行耗時的操做

  • service 裏面不能執行耗時的操做(網絡請求,拷貝數據庫,大文件 )

  • Service 不是獨立的進程,也不是獨立的線程,它是依賴於應用程序的主線程的,也就是說,在更多時候不建議在 Service 中編寫耗時的邏輯和操做(好比:網絡請求,拷貝數據庫,大文件),不然會引發 ANR

  • 若是想在服務中執行耗時的任務。有如下解決方案:

  1. service 中開啓一個子線程
new Thread(){}.start();
複製代碼
  1. 可使用 IntentService 異步管理服務( 有關 IntentService 的內容在後文中給出 )

3.4 Service 是否在 main thread 中執行

Service 是否在 main thread 中執行

  • 默認狀況, 若是沒有顯示的指 service 所運行的進程, Serviceactivity 是運 行在當前 app 所在進程的 main thread ( UI 主線程)裏面。
  • ServiceActivity 在同一個線程,對於同一 app 來講默認狀況下是在同一個線程中的 main Thread ( UI Thread )
  • 特殊狀況 ,能夠在清單文件配置 service 執行所在的進程 ,讓 service 在另 外的進程中執行 Service 不死之身

3.4.1 在 onStartCommand 方法中將 flag 設置爲 START_STICKY ;

<service android:name="com.baidu.location.f" android:enabled="true" android:process=":remote" >
</service>
複製代碼
return Service.START_STICKY;
複製代碼

3.4.2 在 xml 中設置了 android:priority

<!--設置服務的優先級爲MAX_VALUE-->
 <service android:name=".MyService" android:priority="2147483647" >
 </service>
複製代碼

3.4.3 在 onStartCommand 方法中設置爲前臺進程

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
  Notification notification = new Notification(R.mipmap.ic_launcher, "服務正在運行",System.currentTimeMillis());
   Intent notificationIntent = new Intent(this, MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,notificationIntent,0);
    RemoteViews remoteView = new RemoteViews(this.getPackageName(),R.layout.notification);
    remoteView.setImageViewResource(R.id.image, R.mipmap.ic_launcher);
    remoteView.setTextViewText(R.id.text , "Hello,this message is in a custom expanded view");
    notification.contentView = remoteView;
    notification.contentIntent = pendingIntent;
    startForeground(1, notification);
    return Service.START_STICKY;
}
複製代碼

3.4.4 在 onDestroy 方法中重啓 service

@Override
public void onDestroy() {
    super.onDestroy();
    startService(new Intent(this, MyService.class));
}
複製代碼

3.4.5 用 AlarmManager.setRepeating(…) 方法循環發送鬧鐘廣播, 接收的時候調用 serviceonstart 方法

Intent intent = new Intent(MainActivity.this,MyAlarmReciver.class);
PendingIntent sender = PendingIntent.getBroadcast( MainActivity.this, 0, intent, 0);

// We want the alarm to go off 10 seconds from now.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 1);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
//重複鬧鐘
/** * @param type * @param triggerAtMillis t 鬧鐘的第一次執行時間,以毫秒爲單位 * go off, using the appropriate clock (depending on the alarm type). * @param intervalMillis 表示兩次鬧鐘執行的間隔時間,也是以毫秒爲單位 * of the alarm. * @param operation 綁定了鬧鐘的執行動做,好比發送一個廣播、給出提示等等 */
am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 2 * 1000, sender);
複製代碼

3.4.6 目前市場面的不少三方的消息推送 SDK 喚醒 APP , 例如 Jpush

PS: 以上這些方法並不表明着你的 Service 就永生不死了,只能說是提升了進程的優先級。迄今爲止我沒有發現可以經過常規方法達到流氓需求 (經過長按 home 鍵清除都清除不掉) 的方法,目前全部方法都是指經過 Android 的內存回收機制和普通的第三方內存清除等手段後仍然保持運行的方法,有些手機廠商把這些知名的 app 放入了本身的白名單中,保證了進程不死來提升用戶體驗(如微信、QQ 、陌陌都在小米的白名單中)。若是從白名單中移除,他們終究仍是和普通 app 同樣躲避不了被殺的命運。

第四篇:InterService


  • 做爲一個老司機,若是連 Interservice 都沒據說過,那就有點那個啥了

InterService

4.1 什麼是 IntentService

什麼是 IntentService

  • IntentServiceService 的子類,比普通的 Service 增長了額外的功能。

  • 咱們經常使用的 Service 存在兩個問題:

  1. Service 不會專門啓動一條單獨的進程,Service 與它所在應用位於同一個進程中

  2. Service 也不是專門一條新線程,所以不該該在 Service 中直接處理耗時的任務

4.2 IntentService 的特徵

IntentService 的特徵

  • 會建立獨立的 worker 線程來處理全部的 Intent 請求

  • 會建立獨立的 worker 線程來處理 onHandleIntent() 方法實現的代碼,無需處理多線程問題

  • 全部請求處理完成後,IntentService 會自動中止,無需調用 stopSelf() 方法中止 Service

  • ServiceonBind() 提供默認實現,返回 null

  • ServiceonStartCommand 提供默認實現,將請求 Intent 添加到隊列中

4.3 Service 和 IntentService 區別

Service 和 IntentService 區別

4.3.1 Service 是用於後臺服務的

Service 是用於後臺服務的

  1. 當應用程序被掛到後臺的時候,爲了保證應用某些組件仍然能夠工做而引入了 Service 這個概念
  2. 那麼這裏面要強調的是:Service 不是獨立的進程,也不是獨立的線程,它是依賴於應用程序的主線程的,也就是說,在更多時候不建議在 Service 中編寫耗時的邏輯和操做,不然會引發 ANR

也就是,service 裏面不能夠進行耗時的操做。雖然在後臺服務。可是也是在主線程裏面。

4.3.2 當咱們編寫的耗時邏輯,不得不被 service 來管理的時候,就須要引入 IntentService

耗時邏輯

  1. IntentService 是繼承 Service 的,那麼它包含了 Service 的所有特性,固然也包含 service 的生命週期。
  2. 那麼與 service 不一樣的是,IntentService 在執行 onCreate 操做的時候,內部開了一個線程,去你執行你的耗時操做。

4.3.3 使用:

使用

  1. 重寫 protected abstract void onHandleIntent(Intent intent)

4.3.4 IntentService 是一個經過 Context.startService(Intent) 啓動能夠處理異步請求的 Service

經過 Context.startService(Intent) 啓動

  1. 使用時你只須要繼承 IntentService 和重寫其中的 onHandleIntent(Intent) 方法接收一個 Intent 對象 , 在適當的時候會中止本身 ( 通常在工做完成的時候 ) 。
  2. 全部的請求的處理都在一個工做線程中完成 , 它們會交替執行 ( 但不會阻塞主線程的執行 ) ,一次只能執行一個請求。

4.3.5 是一個基於消息的服務

是一個基於消息的服務

  1. 每次啓動該服務並非立刻處理你的工做,而是首先會建立對應的 LooperHandler 而且在 MessageQueue 中添加的附帶客戶 IntentMessage 對象。
  2. Looper 發現有 Message 的時候接着獲得 Intent 對象經過在 onHandleIntent((Intent)msg.obj) 中調用你的處理程序,處理完後即會中止本身的服務。
  3. 意思是 Intent 的生命週期跟你的處理的任務是一致的,因此這個類用下載任務中很是好,下載任務結束後服務自身就會結束退出。

4.3.6 總結 IntentService 的特徵有:

總結 IntentService 的特徵

  1. 會建立獨立的 worker 線程來處理全部的 Intent 請求;

  2. 會建立獨立的 worker 線程來處理 onHandleIntent() 方法實現的代碼,無需處理多線程問題;

  3. 全部請求處理完成後,IntentService會自動中止,無需調用 stopSelf() 方法中止 Service

第五篇:Service 與 Activity


Service 與 Activity

5.1 Activity 怎麼和 Service 綁定,怎麼在 Activity 中啓動對應的 Service

Service 與 Activity

  • Activity 經過 bindService(Intent service, ServiceConnection conn, int flags)Service 進行綁定,當綁定成功的時候 Service 會將代理對象經過回調的形式傳給 conn ,這樣咱們就拿到了 Service 提供的服務代理對象。

  • Activity 中能夠經過 startServicebindService 方法啓動 Service。通常狀況下若是想獲取 Service 的服務對象那麼確定須要經過 bindService() 方法,好比音樂播放器,第三方支付等。

  • 若是僅僅只是爲了開啓一個後臺任務那麼可使用 startService() 方法。

5.2 說說 Activity 、Intent 、Service 是什麼關係

Activity 、Intent 、Service 是什麼關係

  • 他們都是 Android 開發中使用頻率最高的類。其中 ActivityService 都屬於 Android 的四大組件。他倆都是 Context 類的子類 ContextWrapper 的子類,所以他倆能夠算是兄弟關係吧。

  • 不過他們各有各自的本領,Activity 負責用戶界面的顯示和交互,Service 負責後臺任務的處理。

  • ActivityService 之間能夠經過 Intent 傳遞數據,所以能夠把 Intent 看做是通訊使者。

5.3 Service 和 Activity 在同一個線程嗎

Service 和 Activity 在同一個線程嗎

對於同一 app 來講默認狀況下是在同一個線程中的,main ThreadUI Thread )。

5.4 Service 裏面能夠彈吐司麼

Service 裏面能夠彈吐司麼

  • 能夠
  • 彈吐司有個條件是:得有一個 Context 上下文,而 Service 自己就是 Context 的子類
  • 所以在 Service 裏面彈吐司是徹底能夠的。好比咱們在 Service 中完成下載任務後能夠彈一個吐司通知給用戶。

5.5 與 Service 交互方式

與 Service 交互方式

5.5.1 廣播交互

廣播交互

  1. Server 端將目前的下載進度,經過廣播的方式發送出來,Client 端註冊此廣播的監聽器,當獲取到該廣播後,將廣播中當前的下載進度解析出來並更新到界面上。
  2. 定義本身的廣播,這樣在不一樣的 ActivityService 以及應用程序之間,就能夠經過廣播來實現交互。

5.5.2 共享文件交互

共享文件交互

  1. 咱們使用 SharedPreferences 來實現共享,固然也可使用其它 IO 方法實現,經過這種方式實現交互時須要注意,對於文件的讀寫的時候,同一時間只能一方讀一方寫,不能兩方同時寫。
  2. Server 端將當前下載進度寫入共享文件中,Client 端經過讀取共享文件中的下載進度,並更新到主界面上。

5.5.3 Messenger 交互 ( 信使交互 )

Messenger 交互 ( 信使交互 )

  1. Messenger 翻譯過來指的是信使,它引用了一個 Handler 對象,別人可以向它發送消息 ( 使用 mMessenger.send ( Message msg ) 方法)。
  2. 該類容許跨進程間基於 Message 通訊,在服務端使用 Handler 建立一個 Messenger ,客戶端只要得到這個服務端的 Messenger 對象就能夠與服務端通訊了
  3. Server 端與 Client 端之間經過一個 Messenger 對象來傳遞消息,該對象相似於信息中轉站,全部信息經過該對象攜帶

5.5.4 自定義接口交互

自定義接口交互

  1. 其實就是咱們本身經過接口的實現來達到 ActivityService 交互的目的,咱們經過在 ActivityService 之間架設一座橋樑,從而達到數據交互的目的,而這種實現方式和 AIDL 很是相似
  2. 自定義一個接口,該接口中有一個獲取當前下載進度的空方法。Server 端用一個類繼承自 Binder 並實現該接口,覆寫了其中獲取當前下載進度的方法。Client 端經過 ServiceConnection 獲取到該類的對象,從而可以使用該獲取當前下載進度的方法,最終實現實時交互。

5.5.5 AIDL 交互

AIDL交互

  1. 遠程服務通常經過 AIDL 來實現,能夠進行進程間通訊,這種服務也就是遠程服務。
  2. AIDL 屬於 AndroidIPC 機制,經常使用於跨進程通訊,主要實現原理基於底層 Binder 機制。

第六篇:使用


使用

6.1 什麼狀況下會使用 Service

什麼狀況下會使用 Service

6.1.1 經驗總結:

經驗總結

  1. Service 其實就是背地搞事情,又不想讓別人知道
  2. 舉一個生活當中的例子,你想知道一件事情不須要直接去問,你能夠經過側面瞭解。這就是 Service 設計的初衷

6.1.2 Service 爲何被設計出來

Service 爲何被設計出來

  1. 根據 Service 的定義,咱們能夠知道須要長期在後臺進行的工做咱們須要將其放在 Service 中去作。
  2. 得再通熟易懂一點,就是不能放在 Activity 中來執行的工做就必須得放到 Service 中去作。
  3. 如:音樂播放、下載、上傳大文件、定時關閉應用等功能。這些功能若是放到 Activity 中作的話,那麼 Activity 退出被銷燬了的話,那這些功能也就中止了,這顯然是不符合咱們的設計要求的,因此要將他們放在 Service 中去執行。

6.2 onStartCommand() 返回值 int 值的區別

  • 有四種返回值,不一樣值表明的意思以下:

onStartCommand() 返回值 int 值的區別

6.2.1 START_STICKY :

  1. 若是 service 進程被 kill 掉,保留 service 的狀態爲開始狀態,但不保留遞送的 intent 對象。
  2. 隨後系統會嘗試從新建立 service, 因爲服務狀態爲開始狀態,因此建立服務後必定會調用 onStartCommand ( Intent, int, int ) 方法。
  3. 若是在此期間沒有任何啓動命令被傳遞到 service , 那麼參數 Intent 將爲 null

6.2.2 START_NOT_STICKY :

  1. 「非粘性的」。
  2. 使用這個返回值時 , 若是在執行完 onStartCommand 後 , 服務被異常 kill 掉 ,系統不會自動重啓該服務。

6.2.3 START_REDELIVER_INTENT:

  1. 重傳 Intent
  2. 使用這個返回值時,若是在執行完 onStartCommand 後,服務被異常 kill 掉
  3. 系統會自動重啓該服務 , 並將 Intent 的值傳入。

6.2.4 START_STICKY_COMPATIBILITY:

  1. START_STICKY 的兼容版本 , 但不保證服務被 kill 後必定能重啓。

6.3 在 service 的生命週期方法 onstartConmand() 可不能夠執行網絡操做?如何在 service 中執行網絡操做?

onstartConmand() 可不能夠執行網絡操做?如何在 service 中執行網絡操做?

  • 能夠直接在 Service 中執行網絡操做
  • onStartCommand() 方法中能夠執行網絡操做

6.4 提升 service 的優先級

提升 service 的優先級

  • AndroidManifest.xml 文件中對於 intent-filter 能夠經過 android:priority = 「1000」 這個屬性設置最高優先級,1000 是最高值,若是數字越小則優先級越低,同時實用於廣播。

  • onStartCommand 裏面調用 startForeground() 方法把 Service 提高爲前臺進程級別,而後再 onDestroy 裏面要記得調用 stopForeground () 方法。

  • onStartCommand 方法,手動返回 START_STICKY

廣播

  • onDestroy 方法裏發廣播重啓 service
  1. service + broadcast 方式,就是當 serviceondestory 的時候,發送一個自定義的廣播
  2. 當收到廣播的時候,從新啓動 service 。( 第三方應用或是在 setting 裏-應用強制中止時,APP 進程就直接被幹掉了,onDestroy 方法都進不來,因此沒法保證會執行 )
  • 監聽系統廣播判斷 Service 狀態。
  1. 經過系統的一些廣播
  2. 好比:手機重啓、界面喚醒、應用狀態改變等等監聽並捕獲到,而後判斷咱們的 Service 是否還存活。
  • Application 加上 Persistent 屬性。

6.5 Service 的 onRebind ( Intent ) 方法在什麼狀況下會執行

onRebind ( Intent ) 方法在什麼狀況下會執行

  • 若是在 onUnbind() 方法返回 true 的狀況下會執行 , 不然不執行。

總結


  1. 本文基本涵蓋了 Android Service 相關的知識點。因爲篇幅緣由,諸如 InterService 具體使用方法等,沒辦法詳細的介紹,你們很容易就能在網上找到資料進行學習。
  2. 重點:關於 Android 的四大組件,到如今爲止我才總結完 ActivityService,我將繼續針對,BroadcastRecevier ContentProvider 等,以及四大組件以外的,事件分發、滑動衝突、新能優化等重要模塊,進行全面總結,歡迎你們關注 _yuanhao 的 掘金 ,方便及時接收更新
  3. 開始前還覺得總結不難,實際寫文章的過程當中,才知道什麼是艱辛。也不知道本身能不能咬牙堅持下去,但願你們給我鼓勵,就算只是一個贊,也是我堅持下去的理由!

碼字不易,你的點贊是我總結的最大動力!


相關文章
相關標籤/搜索