Android Architecture Components(AAC) 初探

簡介

Android Architecture components 是一組 Android 庫布卡,它可以幫助我們以一種健壯的拙寡、可測(cè)試和可維護(hù)的方式構(gòu)建 APP救斑。

注意: 這個(gè)架構(gòu)目前仍處于 alpha 開發(fā)狀態(tài)稍走。在正式版發(fā)布之前 API 可能會(huì)改變原探,你可能會(huì)遇到穩(wěn)定性和性能問題。

下面將會(huì)介紹使用生命周期感知(lifecycle-aware)組件去構(gòu)建APP:

  • ViewModel - 提供了創(chuàng)建和檢索(類似于單例)綁定到特定生命周期對(duì)象的方法蚯撩, ViewModel 通常是存儲(chǔ) View 數(shù)據(jù)的狀態(tài)并與其他的組件進(jìn)行通信础倍,如數(shù)據(jù)存儲(chǔ)組件和處理業(yè)務(wù)邏輯的組件。想了解更多胎挎,請(qǐng)查看 ViewModel 指南沟启。
  • LifecycleOwner/LifecycleRegistryOwner - LifecycleOwnerLifecycleRegistryOwner 都是在 LifecycleActivityLifecycleFragment 類中實(shí)現(xiàn)的接口。你可以將自己的組件也實(shí)現(xiàn)這些接口以觀察生命周期所有者的狀態(tài)變化犹菇。想了解更多德迹,請(qǐng)查看 Lifecycles 指南
  • LiveData - 允許您觀察應(yīng)用程序的多個(gè)組件的數(shù)據(jù)更改揭芍,而不會(huì)在它們之間創(chuàng)建明確的胳搞,剛性的依賴路徑。LiveData 關(guān)心應(yīng)用程序組件復(fù)雜的生命周期称杨,包括 Activity , Fragmnet , Service 或者 APP 中定義的任何 LifecycleOwner肌毅。LiveData 會(huì)管理觀察者的訂閱狀態(tài),LifecycleOwner 對(duì)象 stopped 時(shí)會(huì)暫停訂閱姑原,以及 LifecycleOwner 對(duì)象 Finished 時(shí)會(huì)取消訂閱悬而。想了解更多,請(qǐng)查看 LiveData 指南锭汛。

如果你已經(jīng)安裝了 Android Studio 2.3 或者更高版本并且熟悉 Activity 生命周期 笨奠,那么你可以繼續(xù)向下看了。

配置環(huán)境

  • 下載源碼唤殴,并導(dǎo)入 Android Studio

  • 運(yùn)行 【Step 1】般婆,界面大概是下面這樣的

step 1
  • 旋轉(zhuǎn)屏幕,計(jì)時(shí)器會(huì)從0開始重新計(jì)時(shí)朵逝。

這部分代碼比較簡單腺兴,首先是布局文件:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.android.lifecycles.step1.ChronoActivity1">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:id="@+id/hello_textview"/>

    <Chronometer
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/hello_textview"
        android:layout_centerHorizontal="true"
        android:id="@+id/chronometer"/>
</RelativeLayout>

然后在 Activity 的 onCreate 函數(shù)中開始計(jì)時(shí)即可,如下:

public class ChronoActivity1 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Chronometer chronometer = (Chronometer) findViewById(R.id.chronometer);

        chronometer.start();
    }
}

Chronometer 是 Android 提供的一個(gè)計(jì)時(shí)器組件廉侧,該組件繼承自 TextView页响,它顯示從某個(gè)起始時(shí)間開始過去了多少時(shí)間。

想要在屏幕旋轉(zhuǎn)時(shí)計(jì)時(shí)器狀態(tài)不被更改段誊,您可以使用 ViewModel 闰蚕,因?yàn)榇祟惪梢栽谂渲酶模ɡ缙聊恍D(zhuǎn))時(shí)不會(huì)被回收。

注:mainfest 文件中可以配置 Activity 在屏幕旋轉(zhuǎn)時(shí)不重新創(chuàng)建 Activity 连舍,從而保持計(jì)時(shí)器的狀態(tài)没陡,這種情況不在本篇談?wù)摲秶鷥?nèi)。

注:如源碼中的 google maven 不能訪問,可將項(xiàng)目中 gradle 文件改為如下

    repositories {
        jcenter()
        maven {
            url "https://dl.google.com/dl/android/maven2/"
        }
    }

添加 ViewModel

在此步驟中盼玄,您可以使用 ViewModel 在屏幕旋轉(zhuǎn)之間保持狀態(tài)贴彼,并解決您在上一步中觀察到的行為(旋轉(zhuǎn)屏幕時(shí)計(jì)時(shí)器會(huì)重置)。在上一步中埃儿,運(yùn)行了一個(gè)顯示計(jì)時(shí)器的 Activity器仗。當(dāng)配置更改(如屏幕旋轉(zhuǎn))會(huì)導(dǎo)致 Activity 被銷毀,此定時(shí)器將重置童番。

您可以使用 ViewModelActivityFragment 的整個(gè)生命周期中保留數(shù)據(jù)精钮。如上一步所示,使用 Activity 來管理 APP 的數(shù)據(jù)是不明智的剃斧。 ActivityFragment 是一種短命的對(duì)象轨香,它們隨著用戶與應(yīng)用程序交互而頻繁創(chuàng)建和銷毀。 ViewModel 還適用于管理與網(wǎng)絡(luò)通信相關(guān)的任務(wù)幼东,以及數(shù)據(jù)的操作和持久化臂容。

使用ViewModel來保持計(jì)時(shí)器的狀態(tài)

首先需要?jiǎng)?chuàng)建一個(gè)ViewModel,如下

public class ChronometerViewModel extends ViewModel {

    @Nullable
    private Long startDate;

    @Nullable
    public Long getStartDate() {
        return startDate;
    }

    public void setStartDate(final long startDate) {
        this.startDate = startDate;
    }
}

打開 ChronoActivity2 并檢查該 Activity 如何檢索并使用 ViewModel 的根蟹,如下:

public class ChronoActivity2 extends LifecycleActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // ViewModelProviders 會(huì)提供一個(gè)新的或者之前已經(jīng)創(chuàng)建過的 ViewModel
        ChronometerViewModel chronometerViewModel
                = ViewModelProviders.of(this).get(ChronometerViewModel.class);

        // 獲取 chronometer 
        Chronometer chronometer = (Chronometer) findViewById(R.id.chronometer);

        if (chronometerViewModel.getStartDate() == null) {
            // 如果開始時(shí)間為 null , 那么這個(gè) ViewModel 是剛被創(chuàng)建的
            long startTime = SystemClock.elapsedRealtime();
            chronometerViewModel.setStartDate(startTime);
            chronometer.setBase(startTime);
        } else {
            // 否則這個(gè) ViewModel 是從 ViewModelProviders 中被檢索出來的策橘,所以需要設(shè)置剛開始的開始時(shí)間
            chronometer.setBase(chronometerViewModel.getStartDate());
        }

        chronometer.start();
    }
}

其中

ChronometerViewModel chronometerViewModel
        = ViewModelProviders.of(this).get(ChronometerViewModel.class);

thisLifecycleOwner 的實(shí)例。 只要 LifecycleOwner 的范圍是活躍的(alive)娜亿,框架就可以使 ViewModel 處于活躍狀態(tài)。如果其所有者因?yàn)榕渲酶模ɡ缙聊恍D(zhuǎn))而被毀壞(destroyed)蚌堵,ViewModel 則不會(huì)被銷毀买决。生命周期所有者會(huì)重新連接到現(xiàn)有的 ViewModel ,如下圖所示:

Viewmodel Lifecycle

注意ActivityFragment 的范圍從 createdfinished(或終止)吼畏,您不能與被 destroyed 混淆督赤。請(qǐng)記住,當(dāng)一個(gè)設(shè)備旋轉(zhuǎn)時(shí)泻蚊, Activity 被銷毀躲舌,但是與它關(guān)聯(lián)的任何 ViewModel 的實(shí)例并不會(huì)被銷毀。

試試看

運(yùn)行應(yīng)用程序并確認(rèn)執(zhí)行以下任一操作時(shí)定時(shí)器不會(huì)重置:

  1. 旋轉(zhuǎn)屏幕性雄。
  2. 導(dǎo)航到另一個(gè)應(yīng)用程序没卸,然后返回。
定時(shí)器不會(huì)重置

但是秒旋,如果你或系統(tǒng)退出應(yīng)用程序约计,則定時(shí)器將重置。

注意: 系統(tǒng)會(huì)在生命周期所有者(例如 ActivityFragment )的整個(gè)生命周期中將 ViewModel 實(shí)例保存在內(nèi)存中 迁筛。 系統(tǒng)不會(huì)將 ViewModel 的實(shí)例持久化到長期存儲(chǔ)煤蚌。

使用 LiveData 包裝數(shù)據(jù)

這一步使用自定義的 Timer 實(shí)現(xiàn)上一步的中的 chronometer 。將上面的邏輯添加到 LiveDataTimerViewModel 類中,將 Activity 的主要功能放在管理用戶和UI之間的交互上尉桩。

Activity 會(huì)在定時(shí)器通知時(shí)更新UI筒占。為了避免內(nèi)存泄露, ViewModel 不應(yīng)該持有 Activity 的實(shí)例蜘犁。比如翰苫,配置更改(例如屏幕旋轉(zhuǎn))會(huì)使 Activity 被系統(tǒng)回收,如果這時(shí) ViewModel 仍持有Activity 的實(shí)例那么 Activity 就不會(huì)被系統(tǒng)回收從而導(dǎo)致內(nèi)存泄露 沽瘦。系統(tǒng)會(huì)保留 ViewModel 的實(shí)例至到 Activity 或生命周期持有者不再存在革骨。

注意: 在 ViewModel 中持有 Context 或者 View 的實(shí)例可能會(huì)導(dǎo)致內(nèi)存泄露。避免引用 Context 或者 View 類的實(shí)例的字段析恋。 ViewModel 中的 onCleared() 方法可用于取消訂閱或清除對(duì)具有較長生命周期的其他對(duì)象的引用良哲,但不用于清除 Context 或者 View 對(duì)象的引用。

可以設(shè)置 ActivityFragment 來觀察數(shù)據(jù)源助隧,當(dāng)數(shù)據(jù)更改時(shí)將會(huì)接收通知筑凫,而不是直接從 ViewModel 修改視圖。這就是觀察者模式并村。

注意: 要想將數(shù)據(jù)可被觀察巍实,可將數(shù)據(jù)包裝在LiveData類中。

如果你使用過 Data Binding Library 或其他響應(yīng)式庫(如RxJava)哩牍,你應(yīng)該很熟悉觀察者模式棚潦。LiveData 是一個(gè)特殊的可觀測(cè)類,它可以感知生命周期膝昆,并且只在聲明周期活躍時(shí)通知觀察者丸边。

LifecycleOwner

ChronoActivity3LifecycleActivity 的子類,他提供了聲明周期的狀態(tài)荚孵。如下:

public class LifecycleActivity extends FragmentActivity implements LifecycleRegistryOwner {...}

LifecycleRegistryOwner 接口的作用是用來將 ViewModelLiveData 綁定到 ActivityFragment 生命周期中妹窖。如果Fragment 的話可以繼承 LifecycleFragment 類。

Update ChronoActivity

  1. ChronoActivity3 中添加如下代碼收叶,在 subscribe() 方法中創(chuàng)建訂閱者:
public class ChronoActivity3 extends LifecycleActivity {

    private LiveDataTimerViewModel mLiveDataTimerViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.chrono_activity_3);

        mLiveDataTimerViewModel = ViewModelProviders.of(this).get(LiveDataTimerViewModel.class);

        subscribe();
    }

    private void subscribe() {
        // 創(chuàng)建觀察者
        final Observer<Long> elapsedTimeObserver = new Observer<Long>() {
            @Override
            public void onChanged(@Nullable final Long aLong) {
                String newText = ChronoActivity3.this.getResources().getString(
                        R.string.seconds, aLong);
                ((TextView) findViewById(R.id.timer_textview)).setText(newText);
            }
        };

        mLiveDataTimerViewModel.getElapsedTime().observe(this, elapsedTimeObserver);
    }
}
  1. 接下來在 LiveDataTimerViewModel 中設(shè)置計(jì)時(shí)時(shí)間骄呼,如下:
public class LiveDataTimerViewModel extends ViewModel {

    private static final int ONE_SECOND = 1000;

    private MutableLiveData<Long> mElapsedTime = new MutableLiveData<>();

    private long mInitialTime;

    public LiveDataTimerViewModel() {
        mInitialTime = SystemClock.elapsedRealtime();
        Timer timer = new Timer();

        // Update the elapsed time every second.
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                final long newValue = (SystemClock.elapsedRealtime() - mInitialTime) / 1000;
                // setValue() 不允許在子線程中調(diào)用,所以需要post主線程執(zhí)行
                // 其實(shí)也可以直接使用 postValue() 方法判没,該方法會(huì)在內(nèi)部post到主線程執(zhí)行
                new Handler(Looper.getMainLooper()).post(new Runnable() {
                    @Override
                    public void run() {
                        //setValue時(shí)蜓萄,觀察者可監(jiān)聽到值的變化
                        mElapsedTime.setValue(newValue);
                    }
                });
            }
        }, ONE_SECOND, ONE_SECOND);

    }

    public LiveData<Long> getElapsedTime() {
        return mElapsedTime;
    }
}
  1. 運(yùn)行 APP 你會(huì)發(fā)現(xiàn)界面每秒都在更新,除非你導(dǎo)航到另外一個(gè) APP澄峰。如果你的設(shè)備支持多窗口绕德,或者旋轉(zhuǎn)屏幕并不會(huì)影響APP顯示。如下圖:

注意LiveData 只有在 Activity 或者 LifecycleOwner 活躍(active)時(shí)才發(fā)送更新摊阀。如果你導(dǎo)航到其他的APP耻蛇,Activity 中的日志打印將會(huì)停止踪蹬,至到你重新回到APP。當(dāng) LiveData 對(duì)象的各自的生命周期所有者處于 STARTED 或者 RESUMED臣咖,我們才稱 LiveData 是活躍的跃捣。

訂閱生命周期事件

許多 Android 組件或庫要求你

  • 訂閱或初始化組件或庫
  • 取消訂閱或 stop 組件或庫

沒有做上面的步驟可能會(huì)導(dǎo)致內(nèi)存泄露或者產(chǎn)生bugs。

生命周期所有者可以傳遞給生命周期感知組件生命周期的狀態(tài)夺蛇,以確保他們知道生命周期的當(dāng)前狀態(tài)疚漆。

你可以用下面的方法查詢生命周期的狀態(tài):

lifecycleOwner.getLifecycle().getCurrentState()

上面的語句返回的是什么周期的狀態(tài),如 Lifecycle.State.RESUMED, 或 Lifecycle.State.DESTROYED 刁赦。

實(shí)現(xiàn) LifecycleObserver 接口的生命周期感知對(duì)象還可以觀察生命周期所有者的狀態(tài)的變化:

lifecycleOwner.getLifecycle().addObserver(this);

可以通過注解的方式娶聘,實(shí)現(xiàn)在各個(gè)生命周期事件執(zhí)行相應(yīng)的方法:

@OnLifecycleEvent(Lifecycle.EVENT.ON_RESUME)
void addLocationListener() { ... }

創(chuàng)建生命周期感知組件

在這里我們會(huì)創(chuàng)建一個(gè)對(duì) Activity 生命周期所有者做出響應(yīng)的組件,使用 Fragment 作為生命周期所有者時(shí)甚脉,可以采用類似的原則和步驟丸升。

使用 Android framework 的 LocationManager 去獲取經(jīng)緯度并且展示給用戶,這允許你

  • 訂閱更改并使用 LiveData 自動(dòng)更新UI牺氨。

  • 創(chuàng)建一個(gè)包裝器狡耻,他可以根據(jù) Activity 生命狀態(tài)的來決定是注冊(cè)還是注銷對(duì)LocationManager的監(jiān)聽。

通常的做法是在 Activity 的 onStart()onResume() 中注冊(cè)監(jiān)聽器猴凹,在 onStop()onPause() 方法中移除監(jiān)聽器夷狰,如下:

// 在 activity 中通常這樣做

@Override
protected void onResume() {
    mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mListener);
}

@Override
protected void onPause() {
    mLocationManager.removeUpdates(mListener);
}

看下我們是如何改造上面代碼的,首先我們需要?jiǎng)?chuàng)建一個(gè) BoundLocationManager 類郊霎,它需要實(shí)現(xiàn) LifecycleOwner 接口并且需要傳入 LifecycleRegistryOwner 的實(shí)例沼头。 BoundLocationManager 類的實(shí)例綁定到 Activity 的生命周期上了,如下:

    static class BoundLocationListener implements LifecycleObserver {
        private final Context mContext;
        private LocationManager mLocationManager;
        private final LocationListener mListener;

        public BoundLocationListener(LifecycleOwner lifecycleOwner,
                                     LocationListener listener, Context context) {
            mContext = context;
            mListener = listener;
            //想要觀察 Activity 的聲明周期书劝,必須將其添加到觀察者中进倍。添加下面的代碼
            //才能是 BoundLocationListener 實(shí)例監(jiān)聽到生命周期
            lifecycleOwner.getLifecycle().addObserver(this);
        }

        //可以使用  @OnLifecycleEvent 注解來監(jiān)聽 Activity 生命周期的變化
        // 可以使用下面的注解來添加 addLocationListener() 方法
        @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
        void addLocationListener() {
            mLocationManager =
                    (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
            mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mListener);
            Log.d("BoundLocationMgr", "Listener added");

            // Force an update with the last location, if available.
            Location lastLocation = mLocationManager.getLastKnownLocation(
                    LocationManager.GPS_PROVIDER);
            if (lastLocation != null) {
                mListener.onLocationChanged(lastLocation);
            }
        }

        // 可以使用下面的注解來移除 removeLocationListener() 方法
        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        void removeLocationListener() {
            if (mLocationManager == null) {
                return;
            }
            mLocationManager.removeUpdates(mListener);
            mLocationManager = null;
            Log.d("BoundLocationMgr", "Listener removed");
        }
    }

注意: 觀察者可以觀測(cè)到提供者的當(dāng)前狀態(tài),所以不需要從構(gòu)造函數(shù)調(diào)用 addLocationListener() 方法庄撮。他是在觀察者添加到生命周期所有者的時(shí)候被調(diào)用的。

運(yùn)行APP毙籽,在旋轉(zhuǎn)屏幕的時(shí)候會(huì)有下面的打印

D/BoundLocationMgr: Listener added
D/BoundLocationMgr: Listener removed
D/BoundLocationMgr: Listener added
D/BoundLocationMgr: Listener removed

使用 Android 模擬器改變?cè)O(shè)備的位置洞斯,UI 就會(huì)更新,如下圖:

改變?cè)O(shè)備的位置

在 Fragmnet 之間共享 ViewModel

在 Fragmnet 之間共享 ViewModel 之前坑赡,我們需要做一些前期準(zhǔn)備

首先需要?jiǎng)?chuàng)建一個(gè) Activity 烙如,該 Activity 中包含兩個(gè) Fragment,在其布局文件中添加兩個(gè) Fragment 即可毅否,如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.android.lifecycles.step5_solution.Activity_step5">

    <fragment
        android:id="@+id/fragment1"
        android:name="com.example.android.lifecycles.step5_solution.Fragment_step5"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <fragment
        android:id="@+id/fragment2"
        android:name="com.example.android.lifecycles.step5_solution.Fragment_step5"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

其中 Fragment_step5 就是需要共享 ViewModel 的 Fragment亚铁,這個(gè) Fragment 也很簡單,只是包含了一個(gè) SeekBar 控件螟加,如下:

<FrameLayout 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"
    tools:context="com.example.android.lifecycles.step5_solution.Fragment_step5">

    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

然后就是創(chuàng)建一個(gè)包含 LiveData 的 ViewModel徘溢,如下:

public class SeekBarViewModel extends ViewModel {

    public MutableLiveData<Integer> seekbarValue = new MutableLiveData<>();
}

運(yùn)行這一步中的代碼吞琐,你會(huì)發(fā)現(xiàn)這是兩個(gè)彼此獨(dú)立的SeekBar實(shí)例:

使用 ViewModel 在 Fragment 之間通信,以便當(dāng)一個(gè) SeekBar 更改時(shí)然爆,另一個(gè) SeekBar 將被更新:

使用 ViewMode 進(jìn)行通信的代碼如下:

public class Fragment_step5 extends Fragment {

    private SeekBar mSeekBar;

    private SeekBarViewModel mSeekBarViewModel;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View root = inflater.inflate(R.layout.fragment_step5, container, false);
        mSeekBar = (SeekBar) root.findViewById(R.id.seekBar);

        mSeekBarViewModel = ViewModelProviders.of(getActivity()).get(SeekBarViewModel.class);

        subscribeSeekBar();

        return root;
    }

    private void subscribeSeekBar() {

        // 當(dāng) SeekBar 變化的時(shí)候更新 ViewModel
        mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser) {
                    Log.d("Step5", "Progress changed!");
                    mSeekBarViewModel.seekbarValue.setValue(progress);
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });

        // 當(dāng) ViewModel 變化的時(shí)候更新 SeekBar
        mSeekBarViewModel.seekbarValue.observe((LifecycleOwner) getActivity(),
                new Observer<Integer>() {
                    @Override
                    public void onChanged(@Nullable Integer value) {
                        if (value != null) {
                            mSeekBar.setProgress(value);
                        }
                    }
                });
    }
}

注意: 你應(yīng)該使用 Activity 作為生命周期的持有者站粟,因?yàn)槊總€(gè) Fragment 的生命周期都是獨(dú)立的。

至此曾雕,你應(yīng)該對(duì) AAC 有一個(gè)初步的認(rèn)識(shí)了奴烙。

參考

Android Architecture Components

Android lifecycle-aware components codelab

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市剖张,隨后出現(xiàn)的幾起案子切诀,更是在濱河造成了極大的恐慌,老刑警劉巖搔弄,帶你破解...
    沈念sama閱讀 222,104評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幅虑,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡肯污,警方通過查閱死者的電腦和手機(jī)翘单,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹦渣,“玉大人哄芜,你說我怎么就攤上這事〖砦ǎ” “怎么了认臊?”我有些...
    開封第一講書人閱讀 168,697評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锄奢。 經(jīng)常有香客問我失晴,道長,這世上最難降的妖魔是什么拘央? 我笑而不...
    開封第一講書人閱讀 59,836評(píng)論 1 298
  • 正文 為了忘掉前任涂屁,我火速辦了婚禮,結(jié)果婚禮上灰伟,老公的妹妹穿的比我還像新娘拆又。我一直安慰自己,他們只是感情好栏账,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評(píng)論 6 397
  • 文/花漫 我一把揭開白布帖族。 她就那樣靜靜地躺著,像睡著了一般挡爵。 火紅的嫁衣襯著肌膚如雪竖般。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評(píng)論 1 310
  • 那天茶鹃,我揣著相機(jī)與錄音涣雕,去河邊找鬼艰亮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛胞谭,可吹牛的內(nèi)容都是我干的垃杖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼丈屹,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼调俘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起旺垒,我...
    開封第一講書人閱讀 39,899評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤彩库,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后先蒋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骇钦,經(jīng)...
    沈念sama閱讀 46,457評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評(píng)論 3 341
  • 正文 我和宋清朗相戀三年竞漾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了眯搭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,664評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡业岁,死狀恐怖鳞仙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情笔时,我是刑警寧澤棍好,帶...
    沈念sama閱讀 36,346評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站允耿,受9級(jí)特大地震影響借笙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜较锡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評(píng)論 3 334
  • 文/蒙蒙 一业稼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蚂蕴,春花似錦低散、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽看成。三九已至君编,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間川慌,已是汗流浹背吃嘿。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評(píng)論 1 272
  • 我被黑心中介騙來泰國打工祠乃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人兑燥。 一個(gè)月前我還...
    沈念sama閱讀 49,081評(píng)論 3 377
  • 正文 我出身青樓亮瓷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親降瞳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘱支,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評(píng)論 2 359

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