Service(服務(wù))

Service為Android四大組件之一

  • 目錄
  • 什么是Service?
  • 服務(wù)的基本用法
  • Android-8.0的行為變更

什么是Service?

  • 服務(wù)是Android中實現(xiàn)程序后臺運行的方案,他非常適合去執(zhí)行那些不需要和用戶交互而且還要求長期運行的任務(wù)。
  • 服務(wù)的運行不依賴于任何用戶界面,即使程序被切換到后臺,或者用戶打開了其他應(yīng)用程序,服務(wù)仍然能夠保持正常運行。
  • 服務(wù)并不是運行在一個獨立的進程當(dāng)中的,而是依賴于創(chuàng)建服務(wù)時所在的應(yīng)用程序進程。當(dāng)某個應(yīng)用程序被殺掉時,所有依賴于該進程的服務(wù)也會停止運行(當(dāng)然,設(shè)置為多進程狀況除外)
  • 不要被服務(wù)的后臺概念所迷惑,實際上服務(wù)并不會自動開啟線程,所有的代碼都是默認在運行在主線程當(dāng)中的。也就是說,我們需要在服務(wù)內(nèi)部手動創(chuàng)建子線程,并在里面執(zhí)行具體的任務(wù),或者就有可能出現(xiàn)主線程被阻塞的情況出現(xiàn)。
  • 服務(wù)的超時時間是20s。

Android中的多線程編程

① 使用Thread類
② 使用Runnable類
③ 使用Handler類
④ 使用AsyncTask類

服務(wù)的基本用法

一、定義一個服務(wù)

新建一個Service,命名為MyService,


創(chuàng)建Service界面.png

Exported屬性表示是否允許除了當(dāng)前程序之外的其他程序訪問這個服務(wù)
Enabled屬性表示是否啟動這個服務(wù)

將兩個屬性都勾選,點擊Finish完成創(chuàng)建,現(xiàn)在觀察MyService中的代碼:

package com.sl.demo;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

可以看見MyService繼承自Service類的,說明這是一個服務(wù);現(xiàn)在看里面只有一個構(gòu)造方法和一個onBind()方法,這個onBind()方法時Service中的唯一的一個抽象方法,必須在子類實現(xiàn),現(xiàn)在我們先忽略這個方法,后面再講解這個方法;
服務(wù)里面的邏輯應(yīng)該在哪里寫呢?這就需要我們重寫Service中另外一些方法了,如下:

public class MyService extends Service {
    public MyService() {
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

我們重寫了三個方法:

  • onCreate() : 此方法會在服務(wù)創(chuàng)建時調(diào)用
  • onStartCommand() : 此方法會在每次服務(wù)啟動時調(diào)用
  • onDestroy() : 此方法會在程序銷毀時調(diào)用

通常情況下,如果希望服務(wù)一啟動就立刻去執(zhí)行某個動作,就可以將邏輯寫在onStartCommand()方法中。而當(dāng)服務(wù)銷毀時,我們又應(yīng)該在onDestroy()方法中去回收那些不再使用的資源。
注意:每一個服務(wù)都需要在AndroidManifest.xml中進行注冊才能生效。這也是Android四大組件共有的特點,當(dāng)通過Android studio通過new 創(chuàng)建服務(wù)時,Android studio已幫我們在Androidmanifest .xml中將這一步完成了

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sl.demo">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
       
        <service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
        </service>
    </application>
</manifest>

這樣一個服務(wù)就定義好了。

二、啟動和停止服務(wù)

現(xiàn)在先在Service中的幾個方法中加入打印日志:

public class MyService extends Service {
    public MyService() {
        Log.d("MyService","MyService() executed");
    }
    @Override
    public IBinder onBind(Intent intent) {
        Log.d("MyService","onBind executed");
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("MyService","onCreate executed");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService","onStartCommand executed");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.d("MyService","onDestroy executed");
        super.onDestroy();
    }
}

在MainActivity中添加兩個按鈕,并綁定點擊事件,一個用于啟動服務(wù),一個用于停止服務(wù),布局就不貼了,現(xiàn)在看MainActivity中代碼:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button start_Service ,stop_service;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start_Service = findViewById(R.id.start_Service);
        stop_service = findViewById(R.id.stop_service);
        start_Service.setOnClickListener(this);      //添加點擊事件
        stop_service.setOnClickListener(this);       //添加點擊事件   
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.start_Service:            //啟動服務(wù)
                Intent startIntent = new Intent(this,MyService.class);
                startService(startIntent);
                break;
            case  R.id.stop_service:            //停止服務(wù)
                Intent stopIntent = new Intent(this,MyService.class);
                stopService(stopIntent);
                break;
        }
    }

可以看見,啟動和停止都是通過Intent來實現(xiàn)的;startService(Intent)和stopService(Intent)方法都是定義在Context類中,這里完全時由活動來開控制服務(wù)的啟動和停止的。
服務(wù)自身也是可以讓自己停止下來的,只需要在需要的位置調(diào)用stopSelf()方法就能讓該服務(wù)停止下來;

現(xiàn)在我們來運行程序,查看服務(wù)的運行日志:
點擊開始服務(wù)按鈕:

03-13 11:50:20.692 1744-1744/com.sl.demo D/MyService: MyService() executed
03-13 11:50:20.692 1744-1744/com.sl.demo D/MyService: onCreate executed
03-13 11:50:20.692 1744-1744/com.sl.demo D/MyService: onStartCommand executed

看結(jié)果說明這個服務(wù)啟動了,onCreate和onStartCommand方法都執(zhí)行了,我們也可以在手機中查看該服務(wù)是否啟動:設(shè)置——》開發(fā)者選項——》正在運行的服務(wù),能再列表中看到該應(yīng)用,點擊后可以看見詳情:


image.png

不要糾結(jié)我這個項目名為Notification,因為我是在一個已有的項目上進行測試滴,很明顯的看見Myservice是啟動的
在這里在驗證一下onCreate和onStartCommand方法,我們多次對啟動服務(wù)按鈕點擊,查看:

03-13 12:05:53.742 1744-1744/com.sl.demo D/MyService: MyService() executed
03-13 12:05:53.742 1744-1744/com.sl.demo D/MyService: onCreate executed
03-13 12:05:53.742 1744-1744/com.sl.demo D/MyService: onStartCommand executed
03-13 12:05:54.899 1744-1744/com.sl.demo D/MyService: onStartCommand executed
03-13 12:05:55.697 1744-1744/com.sl.demo D/MyService: onStartCommand executed
03-13 12:05:56.331 1744-1744/com.sl.demo D/MyService: onStartCommand executed
03-13 12:05:56.863 1744-1744/com.sl.demo D/MyService: onStartCommand executed
03-13 12:05:57.397 1744-1744/com.sl.demo D/MyService: onStartCommand executed
03-13 12:05:57.965 1744-1744/com.sl.demo D/MyService: onStartCommand executed
03-13 12:05:58.662 1744-1744/com.sl.demo D/MyService: onStartCommand executed

從這里可以看見,onCreate只運行了一次,而每次啟動服務(wù)時,onStartCommand都會運行。
點擊停止服務(wù)按鈕:

03-13 11:50:25.915 1744-1744/com.sl.demo D/MyService: onDestroy executed

再進入設(shè)置里面查看的時候,已經(jīng)沒有這個服務(wù)了。
至此就完成了服務(wù)的啟動和停止

三、活動與服務(wù)通信

前面只是通過活動來啟動和停止服務(wù),但是活動并不知道服務(wù)做了什么,以及完成得如何。如果想讓活動和服務(wù)的關(guān)系更緊密一些,就可以借助我們剛才忽略的onBind()方法了.
例,我們需要在MyService里main提供一個下載功能,然后在活動中可以決定何時下載,以及隨時查看下載進度。實現(xiàn)這個功能的思路是創(chuàng)建一個專門的Binder對象來對下載功能進行管理,修改MyService中的代碼:

public class MyService extends Service {
    ......      //省略前面的一些代碼
    private DownLoadBinder mBinder = new DownLoadBinder() ;
    
    class DownLoadBinder extends Binder{
        public void startDownLoad(){
            Log.d("MyService","startDownLoad executed");
        }
        public int getProgress(){
            Log.d("MyService","getProgress executed");
            return 0 ;
        }
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder ;
    }
}

這里主要做了一下三個工作:
① 新建了一個DownLoadBinder繼承Binder類,然后在它的內(nèi)容提供了開始下載和查看進度的模擬方法
② 在MyService中創(chuàng)建了DownLoadBinder實例
③ 在onBind()方法中返回這個實例
至此完成了MyService的修改;
現(xiàn)在在對MainActivity進行修改,將兩個按鈕修改為綁定服務(wù)和解綁服務(wù),當(dāng)一個活動和服務(wù)綁定了后,就可以調(diào)用該服務(wù)里的Binder提供的方法了,修改MainActivity如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button bind_Service ,unBind_service;
    private MyService.DownLoadBinder downLoadBinder ;
    
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected executed");
            downLoadBinder = (MyService.DownLoadBinder)service ;
            downLoadBinder.startDownLoad();
            downLoadBinder.getProgress();
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected executed");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bind_Service = findViewById(R.id.bind_Service);
        unBind_service = findViewById(R.id.unBind_service);
        bind_Service.setOnClickListener(this);      //添加點擊事件
        unBind_service.setOnClickListener(this);       //添加點擊事件
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.bind_Service:            //綁定服務(wù)
                Intent bindIntent = new Intent(this,MyService.class);
                bindService(bindIntent,connection,BIND_AUTO_CREATE);                
                break;
            case  R.id.unBind_service:            //解綁服務(wù)
                unbindService(connection);
                break;
        }
    }
}

在MainActivity中主要實現(xiàn)了
① 創(chuàng)建了一個ServiceConnection類,在里面重寫了onServiceConnected()方法和onServiceDisconnected()方法,這兩個方法分別會在活動和服務(wù)成功綁定和解除綁定的時候調(diào)用。在onServiceConnected()方法中,我們通過向下轉(zhuǎn)型得到了DownLoadBinder的實例,通過這個實例活動和服務(wù)就變得非常緊密了,在活動中可以根據(jù)具體的場景來調(diào)用DownLoadBinder中的任何public方法了。
② 在綁定服務(wù)的按鈕點擊事件中,構(gòu)建Intent兌現(xiàn),調(diào)用bindService()方法,將MainActivity和MyService進行綁定;
③ 在解除綁定服務(wù)中按鈕點擊事件中,直接調(diào)用unbindService()方法即可

點擊綁定服務(wù)查看日志:

03-21 14:15:55.918 30849-30849/com.sl.demo D/MyService: onCreate executed
03-21 14:15:55.927 30849-30849/com.sl.demo D/MainActivity: onServiceConnected executed
03-21 14:15:55.927 30849-30849/com.sl.demo D/MyService: startDownLoad executed
03-21 14:15:55.927 30849-30849/com.sl.demo D/MyService: getProgress executed

點擊解綁服務(wù)查看日志:

03-21 14:17:18.371 31155-31155/com.sl.demo D/MyService: onDestroy executed 

發(fā)現(xiàn)onServiceDisconnected()方法時沒有被調(diào)用的,在連接正常關(guān)閉的情況下是不會被調(diào)用的, 該方法只在Service 被破壞了或者被殺死的時候調(diào)用. 例如, 系統(tǒng)資源不足, 要關(guān)閉一些Services, 剛好連接綁定的 Service 是被關(guān)閉者之一, 這個時候onServiceDisconnected() 就會被調(diào)用

注:任何一個服務(wù)在整個應(yīng)用程序范圍內(nèi)都是通用的,即MyService不僅可以和MainActivity綁定,還可以和任何一個其他的活動綁定,而且綁定完成后他們都可以獲取到相同的DownLoadBinder實例

四、服務(wù)的生命周期

Service的生命周期.png

1)啟動Service服務(wù)
單次:startService() —> onCreate() —> onStartCommand()
多次:startService() —> onCreate() —> onStartCommand() —> onStartCommand()
2)停止Service服務(wù)
stopService() —> onDestroy()
3)綁定Service服務(wù)
bindService() —> onCreate() —> onBind()
4)解綁Service服務(wù)
unbindService() —> onUnbind() —> onDestroy()
5)啟動綁定Service服務(wù)
startService() —> onCreate() —> onStartCommand() —> bindService() —> onBind()
6)解綁停止Service服務(wù)
unbindService() —> onUnbind() —> stopService() —> onDestroy()
7)解綁綁定Service服務(wù)
unbindService() —> onUnbind(ture) —> bindService() —> onRebind()

五、前臺服務(wù)

服務(wù)幾乎都是在后臺運行的,但是服務(wù)的優(yōu)先級還是比較低,當(dāng)系統(tǒng)出現(xiàn)內(nèi)存不足的時候,就有可能會回收正在后天運行的服務(wù)。如果希望服務(wù)可以一直保持運行狀態(tài),而不會由于系統(tǒng)內(nèi)存不足的原因?qū)е卤换厥?,就可以考慮前臺服務(wù);
前臺服務(wù)后后臺服務(wù)最大的區(qū)別就在于,他會一直有一個正在運行的圖片在系統(tǒng)狀態(tài)欄顯示,下拉狀態(tài)欄可以看到更加詳細的信息,非常類似于通知的效果。
修改MyService的onCreate()方法如下:

  @Override
    public void onCreate() {
        Log.d("MyService","onCreate executed");
        super.onCreate();
        int channelId = 1 ;
        Intent intent = new Intent(this,MainActivity.class);
        PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationCompat.Builder builder ;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){        //Android 8.0適配
            NotificationChannel channel = manager.getNotificationChannel(String.valueOf(channelId));
            if (channel == null){
                channel = new NotificationChannel(String.valueOf(channelId),
                        "channel_name",
                        NotificationManager.IMPORTANCE_HIGH);
                manager.createNotificationChannel(channel);
            }
            builder = new NotificationCompat.Builder(this,String.valueOf(channelId));
        }else{
            builder = new NotificationCompat.Builder(this);
        }
        Notification notification = builder
                .setContentTitle("this is content title")
                .setContentText("this is content text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pi)
                .build();
        startForeground(1,notification);
    }

創(chuàng)建一個Notification對象,調(diào)用startForeground()方法就會讓MyService變?yōu)橐粋€前臺服務(wù),并在系統(tǒng)欄顯示出現(xiàn),現(xiàn)在調(diào)用StartService()或BindService()方法,MyService就會以前臺服務(wù)的模式啟動了

六、使用IntentService

服務(wù)中的代碼默認都是運行在主線程當(dāng)中的,如果直接在服務(wù)里去處理一些耗時的邏輯,就很容易出現(xiàn)ANR的情況(Application Not Responding)
這種情況我們可以在具體實現(xiàn)的方法中開啟一個子線程,讓后在里面處理耗時邏輯,但是這種服務(wù)一旦啟動起來就會一直處于運行狀態(tài),所以,如果想要讓一個服務(wù)在執(zhí)行完畢后自動停止,就必須在執(zhí)行完耗時操作后調(diào)用stopSelf();
IntentService的目的是為了簡單的創(chuàng)建一個異步的、會自動停止的服務(wù)。他是繼承Service的一個抽象類,下面看看它的用法。
新建一個MyIntentService類集成子IntentService:

public class MyIntentService extends IntentService {
    public MyIntentService(){
        super("MyIntentService");           //調(diào)用父類有參構(gòu)造
    }

    /** 實現(xiàn)父類的這個抽象方法,此方法為異步線程,也為主要Service的主要運行方法 */
    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        Log.d("MyIntentService", "onHandleIntent: Theard id is " + Thread.currentThread().getId());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyIntentService", "onDestroy executed");
    }
}

修改主界面布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <Button
        android:id="@+id/bind_Service"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="啟動服務(wù)"
        android:onClick="startIntentService"/>
</LinearLayout>

MainActivity代碼:

public class MainActivity extends AppCompatActivity  {
    private static final String TAG = "MainActivity";
      @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void startIntentService(View view){
        Log.d(TAG, "startIntentService: Theard id is " +  Thread.currentThread().getId());
        Intent intent = new Intent(this,MyIntentService.class);
        startService(intent);
    }
}

當(dāng)然,不能忘記在AndroidManifest.xml里注冊服務(wù):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.sl.demo">
   <application
        android:name=".app.DemoApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:replace="android:label">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".MyIntentService" />
    </application>
</manifest>

運行項目,查看log日志:

03-21 17:28:12.300 23843-23843/com.sl.demo D/MainActivity: startIntentService: Theard id is 2
03-21 17:28:12.316 23843-24604/com.sl.demo D/MyIntentService: onHandleIntent: Theard id is 5820
03-21 17:28:12.318 23843-23843/com.sl.demo D/MyIntentService: onDestroy executed

可以看見,MyIntentService和MainActivity所在的線程id不一樣,而且MyIntentService的onDestory()方法在運行完畢后也自動停止了。

Android 8.0的行為變更

Android 8.0為提高電池續(xù)航時間,引入了 后臺執(zhí)行限制,當(dāng)您的應(yīng)用進入 已緩存 的狀態(tài)時,如果沒有活動的組件,系統(tǒng)將解除應(yīng)用具有的所有喚醒鎖。
此外,為提高設(shè)備性能,系統(tǒng)會限制未在前臺運行的應(yīng)用的某些行為。具體而言:

  • 現(xiàn)在,在后臺運行的應(yīng)用對后臺服務(wù)的訪問受到限制。
  • 應(yīng)用無法使用其清單注冊大部分隱式廣播(即,并非專門針對此應(yīng)用的廣播)。

默認情況下,這些限制僅適用于針對 O 的應(yīng)用。不過,用戶可以從 Settings 屏幕為任意應(yīng)用啟用這些限制,即使應(yīng)用并不是以 O 為目標平臺。

Android 8.0 還對特定函數(shù)做出了以下變更:

  • 如果針對 Android 8.0 的應(yīng)用嘗試在不允許其創(chuàng)建后臺服務(wù)的情況下使用 startService() 函數(shù),則該函數(shù)將引發(fā)一個 IllegalStateException。
  • 新的 Context.startForegroundService() 函數(shù)將啟動一個前臺服務(wù)?,F(xiàn)在,即使應(yīng)用在后臺運行,系統(tǒng)也允許其調(diào)用 Context.startForegroundService()。不過,應(yīng)用必須在創(chuàng)建服務(wù)后的五秒內(nèi)調(diào)用該服務(wù)的 startForeground() 函數(shù)。

針對Service的行為變更定義Service如下:

public class MyService extends Service {
    public static final String ACTION = "abcdefg";

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationChannel channel =  new NotificationChannel("serviceId", "serviceName", NotificationManager.IMPORTANCE_HIGH);
            notificationManager.createNotificationChannel(channel);
            Notification notification = new NotificationCompat.Builder(getApplicationContext(), "serviceId").
                    setSmallIcon(R.drawable.ic_launcher_foreground).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_background)).
                    setContentText("服務(wù)運行中")
                    .setContentTitle("測試服務(wù)")
                    .setWhen(System.currentTimeMillis()).build();
            startForeground(1, notification);
        }
    }
    private int time = 0 ;
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(1000);
                        time ++ ;
                        Log.d(MyService.this.getClass().getName(), "計時:" + time);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }
    
    public static void startService(Context context) {
        Intent intent = new Intent(context, MyService.class);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(intent);
        } else {
            context.startService(intent);
        }
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容