アーキテクチャコンポーネントの4深い理解の[AAC]シリーズ:ビューモデル

0.はじめに

この記事では、ソースコードのAAC 1.1.1バージョンに基づいて、「Androidのアーキテクチャのコンポーネント第四の記事のシリーズでの深い理解であります

[AAC] Androidアプリケーションのアーキテクチャ新しい時代のシリーズ!

2つのアーキテクチャコンポーネントの基礎一連の[AAC] -depth理解:ライフサイクル

アーキテクチャコンポーネントの3人の深い理解の[AAC]シリーズ:LiveData

、毒性この点をリンクしないでください、しないでください

以前ではLiveData、物品の原則分析、我々は言及したViewModel最大の価値を最大化することができLiveDataとその協力を。

この1は、我々はViewModelにLaijiangjiang、ライフサイクルだけでなく、その実装の原理を使用し、ViewModelに簡単な言葉を見ています。

1.のViewModel概要

ダイビングのViewModelを説明する前に、最初のビューモデルの下で簡単に取ります:

ViewModelクラスは、ライフサイクルを意識した方法でUI関連のデータを保存して管理するように設計されています。ViewModelこのクラスは、データが、画面回転などの設定変更を生き残ることができます。

加えて、ビューモデルをすることができます。ViewModelには、UIに関連するデータを管理するために、ライフサイクルを感じることができるように設計された配置改变場合のデータが保存されていることを確認します。ViewModelには、に焦点を当て以感知生命周期的方式、管理インターフェイス固有のデータ。

私たちは、変更は、設定項目に類似していることを知って破壊され、再建されるために私たちの活動になりますので、画面を回転させ、データの損失を開催し、この時間の活動が続くと、ViewModel 则并不会被销毁そう私たちは、プロセス内のデータを保存することができます、というより活動を再構築します取得するつもり再後。およびビューモデルたちを可能にする不必去担心潜在的内存泄露问题ビューモデルを使用する場合に比べ同時に、onSaveInstanceState()方法をこのような比較的大きなデータ・ストレージとして多くの利点を、そしてシリアライゼーションおよびデシリアライゼーションを必要としません。

要するにViewModelに、多くの利点は、我々がViewModelに下の基本的な使い方をご紹介することになります。

2. ViewModelに基本的な使い方

ViewModelにも使用することは非常に簡単ですが、Androidのは、私たちが継承することを可能にし、提供していますのViewModelクラスを提供しViewModelProviders、私たちはViewModelにインスタンス化を支援します。

搬送公式サイトの例:

A) まず、それが依存している追加します。

def lifecycle_version = "1.1.1"
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
复制代码

B) カスタムMyViewModelから継承ViewModel、および構成しますLiveData

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<User>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}
复制代码

C) における援助活動ViewModelProvidersのインスタンスがViewModelにを取得し、LiveDataで変更をユーザーに通知する登録します:

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.

        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}
复制代码

だから、簡単な手順は、我々はMyActivityはMyViewModelを取得する、MyActivityが再作成しても、ViewModelにに使用する例です。

そこで質問があり、 ViewModel 的生命周期到底是怎么样的呢?

それを隠されたその背後にある原理は何ですか?次は、見てみましょう。

3.のViewModelのライフサイクル

我々は前に述べた、とViewModelに活動構成の変更と一緒に破壊の破壊ではないでしょう、そして、最終的にどのようにViewModelにライフサイクルの一種でありますか?

のマップを参照するには公式サイト:

ViewModelには、復興活動の時にまだ生きて見ることができます。

Why

4.ビューモデルの原則

審査のもと、私たちはViewModelにコードの前に使用しました:

MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
复制代码

ここでは、起動ViewModelProviders.of確認するために起動する方法を:

//ViewModelProviders
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
  //传入了 null
  return of(activity, null);
}

@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
  //检查合法性
  Application application = checkApplication(checkActivity(fragment));
  if (factory == null) {
    //走到这里,返回了 AndroidViewModelFactory 的单例
    factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
  }
  return new ViewModelProvider(ViewModelStores.of(fragment), factory);
}
复制代码

ViewModelProviders.of()方法は、私たちは、デフォルトの構築を支援するためAndroidViewModelFactoryのViewModelの作成を支援するために、ファクトリクラスを、ライフサイクルにおける現在の活動を返されましたViewModelProvider

見てAndroidViewModelFactory

    public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
				//单例模式
        private static AndroidViewModelFactory sInstance;
        @NonNull
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }

        private Application mApplication;
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }

        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
                //noinspection TryWithIdenticalCatches
                try {
                    return modelClass.getConstructor(Application.class).newInstance(mApplication);
                } catch (NoSuchMethodException e) {
                  //...
                }
            }
            return super.create(modelClass);
        }
    }
复制代码

事実によってAndroidViewModelFactory 反射のViewModelファクトリクラスのメソッドを構築し、単一の実施形態です。

ダウン見て、私たちはのViewModelクラスがに渡されたViewModelProvider.get()方法。

getメソッドを見てみましょう:

//ViewModelProvider
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
  String canonicalName = modelClass.getCanonicalName();
  if (canonicalName == null) {
    throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
  }
  //每个类都有一个唯一的 key
  return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}

@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
  //先从 store 中获取
  ViewModel viewModel = mViewModelStore.get(key);

  if (modelClass.isInstance(viewModel)) {
    //noinspection unchecked
    return (T) viewModel;
  } else {
    //noinspection StatementWithEmptyBody
    if (viewModel != null) {
      // TODO: log a warning.
    }
  }

  viewModel = mFactory.create(modelClass);
  mViewModelStore.put(key, viewModel);
  //noinspection unchecked
  return (T) viewModel;
}
复制代码

コードを説明し、それが各クラスはViewModelに内蔵されていることが判明した唯一的 key、と呼ばれるこのキーを通過しようとViewModelStore、それは工場がnullの作成に通過する場合は、ViewModelにインスタンスを取得するためのクラス、そして新しいインスタンスが保存されていますViewModelStoreへ。

メインプロセスは、我々は通常、何も特別なものかのように同じキャッシュを行うだけのように思える、ライフサイクルに関連する処理コードのトレースが表示されない、これが起こっていますか、?

慎重に、理論的には、その後、このViewModelStoreから取得する優先方法を取得し、考える限り、このクラスは、構成変更の過程で破壊されていないViewModelStoreとして、その後、我々はViewModelには破棄されません作成することを確実にすることができ、我々は確かに漏れますViewModelStoreに関する重要な事柄のうち。

よく見ると過去に戻って、ViewModelProviderの建物は、簡単なようではありません。

new ViewModelProvider(ViewModelStores.of(fragment), factory);
复制代码

ここでViewModelStore断片を作成し、導入ViewModelStoresによってクラスに渡され、間違って何かがなければなりません。

//ViewModelStores
public static ViewModelStore of(@NonNull Fragment fragment) {
  if (fragment instanceof ViewModelStoreOwner) {
    return ((ViewModelStoreOwner) fragment).getViewModelStore();
  }
  return holderFragmentFor(fragment).getViewModelStore();
}
复制代码

ここでViewModelStoreOwner、HolderFragmentうちいくつかのクラスの添加は、のは、それを追跡してみましょう。

public interface ViewModelStoreOwner {
    @NonNull
    ViewModelStore getViewModelStore();
}
复制代码

ちょうどインタフェース定義LifecycleOwner、と同様のViewModelStoreOwnerは、フォーカスを見てとるholderFragmentFor(fragment)方法リターンをHolderFragment

//HolderFragment
public static HolderFragment holderFragmentFor(Fragment fragment) {
  return sHolderFragmentManager.holderFragmentFor(fragment);
}
复制代码

この方法は、カテゴリ、HolderFragmentManagerの方法に加え、神ファナをHolderFragmentManager来ています。

static class HolderFragmentManager {
    private Map<Activity, HolderFragment> mNotCommittedActivityHolders = new HashMap<>();
    private Map<Fragment, HolderFragment> mNotCommittedFragmentHolders = new HashMap<>();

    private ActivityLifecycleCallbacks mActivityCallbacks =
            new EmptyActivityLifecycleCallbacks() {
                @Override
                public void onActivityDestroyed(Activity activity) {
                    HolderFragment fragment = mNotCommittedActivityHolders.remove(activity);
                    if (fragment != null) {
                        Log.e(LOG_TAG, "Failed to save a ViewModel for " + activity);
                    }
                }
            };

    private boolean mActivityCallbacksIsAdded = false;

    private FragmentLifecycleCallbacks mParentDestroyedCallback =
            new FragmentLifecycleCallbacks() {
                @Override
                public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) {
                    super.onFragmentDestroyed(fm, parentFragment);
                    HolderFragment fragment = mNotCommittedFragmentHolders.remove(
                            parentFragment);
                    if (fragment != null) {
                        Log.e(LOG_TAG, "Failed to save a ViewModel for " + parentFragment);
                    }
                }
            };

    void holderFragmentCreated(Fragment holderFragment) {
        Fragment parentFragment = holderFragment.getParentFragment();
        if (parentFragment != null) {
            mNotCommittedFragmentHolders.remove(parentFragment);
            parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
                    mParentDestroyedCallback);
        } else {
            mNotCommittedActivityHolders.remove(holderFragment.getActivity());
        }
    }

    private static HolderFragment findHolderFragment(FragmentManager manager) {
        if (manager.isDestroyed()) {
            throw new IllegalStateException("Can't access ViewModels from onDestroy");
        }

        Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
        if (fragmentByTag != null && !(fragmentByTag instanceof HolderFragment)) {
            throw new IllegalStateException("Unexpected "
                    + "fragment instance was returned by HOLDER_TAG");
        }
        return (HolderFragment) fragmentByTag;
    }

    private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
        HolderFragment holder = new HolderFragment();
        fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
        return holder;
    }

    HolderFragment holderFragmentFor(FragmentActivity activity) {
        FragmentManager fm = activity.getSupportFragmentManager();
        HolderFragment holder = findHolderFragment(fm);
        if (holder != null) {
            return holder;
        }
        holder = mNotCommittedActivityHolders.get(activity);
        if (holder != null) {
            return holder;
        }

        if (!mActivityCallbacksIsAdded) {
            mActivityCallbacksIsAdded = true;
            activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
        }
        holder = createHolderFragment(fm);
        mNotCommittedActivityHolders.put(activity, holder);
        return holder;
    }

    HolderFragment holderFragmentFor(Fragment parentFragment) {
        FragmentManager fm = parentFragment.getChildFragmentManager();
        HolderFragment holder = findHolderFragment(fm);
        if (holder != null) {
            return holder;
        }
        holder = mNotCommittedFragmentHolders.get(parentFragment);
        if (holder != null) {
            return holder;
        }

        parentFragment.getFragmentManager()
                .registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);
        holder = createHolderFragment(fm);
        mNotCommittedFragmentHolders.put(parentFragment, holder);
        return holder;
    }
}
复制代码

私たちは、ソースコードから学ぶことができるHolderFragmentManagerこれらの事を行うには主に次のとおりです。

  1. 我々はViewModelにインスタンスを取得したい場合は、まず構築しますHolderFragment、それを添加我们的宿主(Activity/Fragment)中してそれをキャッシュします。

  2. コールバックホストのライフサイクル、アクティビティの対応登録することにより、耳を傾けると同時にActivityLifecycleCallbacks、フラグメント対応FragmentLifecycleCallbacks、ホスト破壊キャッシュをクリアします。

その名のように、HolderFragmentManagerHolderFragmentを管理する責任があり、それはHolderFragment、次のルックHolderFragment注入ご覧ください。

HolderFragment 次のようにソースを合理化:

public class HolderFragment extends Fragment implements ViewModelStoreOwner {
    private static final String LOG_TAG = "ViewModelStores";

    private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static final String HOLDER_TAG =
            "android.arch.lifecycle.state.StateProviderHolderFragment";

    private ViewModelStore mViewModelStore = new ViewModelStore();
		//看这里看这里看这里
    public HolderFragment() {
        setRetainInstance(true);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        sHolderFragmentManager.holderFragmentCreated(this);
    }
		...
    @Override
    public void onDestroy() {
        super.onDestroy();
        mViewModelStore.clear();
    }
}
复制代码

内部HolderFragmentホールドA ViewModelStoreと我々は前に述べた実現ViewModelStoreOwnerインターフェース、そして最も重要なのはコードです:

public HolderFragment() {
  setRetainInstance(true);
}
复制代码

Fragment.setRetainInstance(true) この方法は、効果を得ることができ、まだ構成の変更後に保存された活動です。

ここでは、原則としてViewModelには、それを明確に実装:真HolderFragmentするretainInstanceを注入することにより、プロパティの使用断片は、内部ViewModelStoreの究極の保証をそれに耐えることがまだ活動の構成変更後のことを確認するため、およびHolderFragment内部ViewModelStoreの生存を確保するためにViewModelに生存キャッシュストレージ、この機能のViewModelにライフサイクル特性を有効にします(再びフラグメント化し!)

図5は、ViewModelにを示しています

キーのViewModelクラスのクラス図:

原則シーケンス図を実装ViewModelに:

6.知識カーディングおよび概要

説明するために、キーの種類

  • ViewModel データの作成と管理活動/フラグメントを担当し、また、外の世界とのコミュニケーション活動/フラグメントを扱うことができる抽象クラス、通常は保存されたビジネス・ロジック、同様のプレゼンター; ViewModelには、多くの場合、LiveDataアクティビティ/フラグメントに暴露され、コンフィギュレーションとアクティビティViewModelに変更は回復にはなりません。
  • AndroidViewModel開催するApplicationのViewModelを。
  • ViewModelStore、のViewModelクラスを格納するための責任がある、と呼び出されること、また、それがクリアされる前のViewModelに通知する責任がありますViewModel.onCleared()
  • ViewModelStoreOwner 、インタフェース定義の抽象的な「ViewModelStore所有者」、同様のLifecycleOwnerの役割は、それはそのHolderFragment、FragmentActivityを達成しているです。
  • HolderFragmentretainInstance財産trueおよび実装しViewModelStoreOwner、保存するために、フラグメントをViewModelStore、とするとき、設定の変更が破棄されていないことを保証するために、
  • HolderFragmentManager 、注射、キャッシュ管理HolderFragmentの仕事の作成を担当。

ViewModelに原理をまとめると

1注入することによってretainInstancetrue活動後、構成変更がまだ生存するとHolderFragment内部ViewModelStoreの生存を確保することが可能であることを保証するために、フラグメントの機能を使用して、HolderFragmentし、それによりビューモデルを実現し、ビューモデルキャッシュ生存に格納究極保証内部ViewModelStoreアクティビティを配置しました機能は変更の場合は破棄されません。

ViewModelには、の使用に注意してください

  1. 不要持有 Activity :ViewModelには破壊される構成アクティビティーを変更することはありませんので、間違いなく、特定のビューでは、このような活動などの活動に関連してこれらのクラスを、保持するViewModelには活動がメモリリークにつながる保持してみましょう、だけでなく、あまりにも、ライフサイクルと指摘していませんノー;
  2. 不能访问 UI:ViewModelには、必要があるだけでデータを管理する責任が UIを訪問していない、が、それを保持することはできません。

7.まとめ

フラグメントの特性を利用してViewModelには、特定のライフサイクルにおけるUI関連のデータを管理する方法を提供してくれる、アクティビティ/断片中から剥離論理データ管理に私たちを助けます。

実際にViewModelには、だけでなく、データを管理するだけでなく、コードのビジネスロジックの処理を格納することができ、また、簡単に別のフラグメントの活動で相互に通信できるようにすることができ、これは私たちの間の通信これまで断片の大きな問題を解決します。

ライフサイクル、LiveData、ビューモデルの深い理解が終了した後、あなたは効果的に私たちは、開発プロセスで遭遇現実的な問題を解決することができます、彼らは確かに非常に強力であることがあります。

我々は非常に経験が車の中で得た、その後のチケットああを購入をお勧めします。

8.参考文献と推奨

  1. developer.android.com/topic/libra...

  2. medium.com/androiddeve...

ます。https://juejin.im/post/5d0111c1e51d45108126d226で再現

おすすめ

転載: blog.csdn.net/weixin_34208185/article/details/93166197