android 架构组件

Mvvm

Model–View–ViewModel (数据双向绑定)
model: 数据层
view: 视图层
Viewmodel: 数据和视图逻辑处理

架构原则

https://developer.android.google.cn/jetpack/docs/guide
分离关注点
基于界面的类(Actitivy fragment)应仅包含处理界面和操作系统交互的逻辑
通过模型驱动界面
模型是负责处理应用数据的组件 和view和应用组件独立

持久性是理想之选,原因如下:

如果 Android 操作系统销毁应用以释放资源,用户不会丢失数据。
当网络连接不稳定或不可用时,应用会继续工作。


截屏2020-10-19下午2.36.47.png

为了实现mvvm,andorid推出了相应的组件
DataBinding ViewModel LiveData,下面分别介绍一下:

ViewModel

  1. ViewModel数据不受系统配置更改影响(如在旋转设备时重新创建 Activity)
  2. ViewModel不是单纯的数据类
  3. ViewModel为组件提供数据,共享数据
  4. ViewModel包含数据处理逻辑
  5. ViewModel转发用户请求来修改数据(获取网络,数据库数据)

https://developer.android.google.cn/topic/libraries/architecture/viewmodel

viewmodel生命周期


viewmodel.png
  1. ViewModel的简单使用:
class StudentViewModel : ViewModel() {
    var age = 21
    var name = "王牡丹"
    fun change(){
        age++
        name = "王甜甜"
    }

}
Activity中 
var student=ViewModelProvider(this).get(StudentViewModel::class.java)
点击事件改变student属性,屏幕旋转数据不会丢失

下面看下源码,ViewModel的源码很简单,并没有生命周期的处理,只做了清理数据和给数据打标签

public abstract class ViewModel {
    // Can't use ConcurrentHashMap, because it can lose values on old apis (see b/37042460)
    @Nullable
    private final Map<String, Object> mBagOfTags = new HashMap<>();
    private volatile boolean mCleared = false;

 /* 当ViewModel不再使用并将被销毁时,将调用此方法。
 *可以用来清除数据,防止防止这个视图模型的泄漏*/
    @SuppressWarnings("WeakerAccess")
    protected void onCleared() {
    }

    @MainThread
    final void clear() {
        mCleared = true;
      //因为clear()是final,所以这个方法仍然在模拟对象上调用
      //在这些情况下,mBagOfTags是null。但它永远是空的
      //因为setTagIfAbsent和getTag不是final,所以我们可以跳过
      //清除它
          if (mBagOfTags != null) {
            synchronized (mBagOfTags) {
                for (Object value : mBagOfTags.values()) {
                    // see comment for the similar call in setTagIfAbsent
                    closeWithRuntimeException(value);
                }
            }
        }
        onCleared();
    }

 
    @SuppressWarnings("unchecked")
    <T> T setTagIfAbsent(String key, T newValue) {
        T previous;
        synchronized (mBagOfTags) {
            previous = (T) mBagOfTags.get(key);
            if (previous == null) {
                mBagOfTags.put(key, newValue);
            }
        }
        T result = previous == null ? newValue : previous;
        if (mCleared) {
            // It is possible that we'll call close() multiple times on the same object, but
            // Closeable interface requires close method to be idempotent:
            // "if the stream is already closed then invoking this method has no effect." (c)
            closeWithRuntimeException(result);
        }
        return result;
    }

    /**
     * Returns the tag associated with this viewmodel and the specified key.
     */
    @SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
    <T> T getTag(String key) {
        if (mBagOfTags == null) {
            return null;
        }
        synchronized (mBagOfTags) {
            return (T) mBagOfTags.get(key);
        }
    }

    private static void closeWithRuntimeException(Object obj) {
        if (obj instanceof Closeable) {
            try {
                ((Closeable) obj).close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

下面看一下获取ViewModel的ViewModelProvider源码:
构造函数:

 public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }

 public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

可以看到,构造函数只是给两个变量赋了值,没做其他操作
ViewModelStore源码,可以看出,只是一个Map

public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }

    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

Factory一个接口,用来生成ViewModel

  public interface Factory {
        @NonNull
        <T extends ViewModel> T create(@NonNull Class<T> modelClass);
    }

下面看get()方法

   public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        ...
       //key = "androidx.lifecycle.ViewModelProvider.DefaultKey"+class的规范名
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

//如果存在就直接在store中获取,如果没有就创建,并put进去
   public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);

        if (modelClass.isInstance(viewModel)) {
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

看到这里,只是数据被储存了起来,但是如何保证数据不受配置影响呢
仔细想一下,我们的ViewModelStore来自Activity,我们看一下Activity源码:
首先,我们看到了实现了了关于ViewModel的接口

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,···
      

在以往的积累里,在数据切换时会有onRetainCustomNonConfigurationInstance这个函数被调用

2020-10-22 14:02:41.129 11026-11026/? E/BaseActivity: onCreate
2020-10-22 14:02:41.321 11026-11026/? E/BaseActivity: onStart
2020-10-22 14:02:41.343 11026-11026/? E/BaseActivity: onResume
选装屏幕
2020-10-22 14:02:53.897 11026-11026/com.example.testjetpack E/BaseActivity: onPause
2020-10-22 14:02:53.906 11026-11026/com.example.testjetpack E/BaseActivity: onStop
2020-10-22 14:02:53.906 11026-11026/com.example.testjetpack E/BaseActivity: onRetainCustomNonConfigurationInstance
2020-10-22 14:02:53.908 11026-11026/com.example.testjetpack E/BaseActivity: onDestroy
2020-10-22 14:02:53.955 11026-11026/com.example.testjetpack E/BaseActivity: onCreate
2020-10-22 14:02:54.020 11026-11026/com.example.testjetpack E/BaseActivity: onStart
2020-10-22 14:02:54.031 11026-11026/com.example.testjetpack E/BaseActivity: onResume

源码中可以看到,这个方法已经废弃

 /**
     * Use this instead of {@link #onRetainNonConfigurationInstance()}.
     * Retrieve later with {@link #getLastCustomNonConfigurationInstance()}.
     *
     * @deprecated Use a {@link androidx.lifecycle.ViewModel} to store non config state.
     */
    @Deprecated
    @Nullable
    public Object onRetainCustomNonConfigurationInstance() {
        return null;
    }

我们继续看他被调用的地方,这是一个final方法,不能被继承,它的注释告诉我们如果想保持自己的配置状态请使用ViewModel

    @Override
    @Nullable
    public final Object onRetainNonConfigurationInstance() {
       //为了兼容老版本
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
         //不重新获取,从老的配置中获取
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }

        if (viewModelStore == null && custom == null) {
            return null;
        }

        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }

看到这里,有一些自己的思考,如果想要数据不受生命周期影响,那就需要是系统级别的储存数据(Application ActivityThead)

下面看一下ViewModelStore的由来:

   //由getViewModelStore()从NonConfigurationInstances惰性地重新创建
    private ViewModelStore mViewModelStore;
   //只是有几个变量,没有任何方法
  //Activity中
   static final class NonConfigurationInstances {
        Object activity;//其实这个就是我们保存的数据
        HashMap<String, Object> children;
        FragmentManagerNonConfig fragments;
        ArrayMap<String, LoaderManager> loaders;
        VoiceInteractor voiceInteractor;
    }
//ComponentActivity
   static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
    }

那么看下它的使用位置:发现在attach()中被初始化

Activity中:
NonConfigurationInstances mLastNonConfigurationInstances;

final void attach(Context context, ActivityThread aThread,  ...
            NonConfigurationInstances lastNonConfigurationInstances...
           ) {
        ...
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
       ...
        mLastNonConfigurationInstances = lastNonConfigurationInstances;
        ···
        }

虽然没看到ViewModelStore被创建,但是可以看到储存它的NonConfigurationInstances是系统级别的
继续跟NonConfigurationInstances的走向(debug调试)

    public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();
       //第一次进入这个应该是null
        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }

        if (viewModelStore == null && custom == null) {
            return null;
        }

        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }

看下getViewModelStore()

public ViewModelStore getViewModelStore() {
        if (getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

getViewModelStore()应该是被系统级别调用的,下面为ViewModel的整个走向


截屏2020-10-22下午1.49.01.png

既然ViewModel是系统级别的,那么在ondestory()的时候
如何保障只有在配置改变的时候才会保留,非配置改变则被清除
清除的逻辑并没有在ondestory()中,而是在构造函数的时候监听了生命周期变化,源码如下:

    public ComponentActivity() {
        Lifecycle lifecycle = getLifecycle();
        ......  
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                   //根据是否配置状态改变
                    if (!isChangingConfigurations()) {
                        //清除
                        getViewModelStore().clear();
                    }
                }
            }
        });
      ......
    }

Livedata:

LiveData :是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。

这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

简单使用:当点击的时候,名字会发生变化

class NameViewModel : ViewModel(){
    val currentName: MutableLiveData<String> by lazy{//延迟初始化
        MutableLiveData<String>()
    }
}

Activity中使用

private NameViewModel model;
    model = new ViewModelProvider(this).get(NameViewModel.class);
    final Observer<String> nameObserver = new Observer<String>(){
        @Override
        public void onChanged(@Nullable final String newName){
            nameTextView.setText(newName);
        }
    };
//注册观察者
    model.getCurrentName().observe(this,nameObserver);
//livedata数据发生变化,触发nameObserver
   button.setOnClickListener { v-> model.currentName.value = "司凤" }

源码分析

MutableLiveData 继承 LiveData源码

1. observe(activity,nameObserver)方法:


    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
//如果生命周期destroyed 不添加
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
       //储存观察者
        owner.getLifecycle().addObserver(wrapper);
    }

参数1 LifecycleOwner是一个接口,而Activity继承此接口,具体实现方法在 FragmentActivity中。
(ComponentActivity也有实现 ,用于那些没有切换到Fragments 1.1.0的应用程序行为由androidx.activity.ComponentActivity提供。)


  public interface LifecycleOwner {
      @NonNull
       Lifecycle getLifecycle();
  } 

ComponentActivity中代码,FragmentActivity中逻辑相同

 private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

observe方法,就是将观察者储存,已待后续使用。

2. 接下来看触发观察者的方法:

button.setOnClickListener { v-> model.currentName.value = "司凤" }
LiveData 中 setvalue()方法

  @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

dispatchingValue(null)

   void dispatchingValue(@Nullable ObserverWrapper initiator) {
       if (mDispatchingValue) {
           mDispatchInvalidated = true;
           return;
       }
       mDispatchingValue = true;
       do {
           mDispatchInvalidated = false;
           if (initiator != null) {
               considerNotify(initiator);
               initiator = null;
           } else {
               for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                       mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                   considerNotify(iterator.next().getValue());
                   if (mDispatchInvalidated) {
                       break;
                   }
               }
           }
       } while (mDispatchInvalidated);
       mDispatchingValue = false;
   }

considerNotify()

    private void considerNotify(ObserverWrapper observer) {
//当前observer不活跃,就是不更新
        if (!observer.mActive) {
            return;
        }
        // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
        //
        // we still first check observer.active to keep it as the entrance for events. So even if
        // the observer moved to an active state, if we've not received that event, we better not
        // notify for a more predictable notification order.
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
       //调用了onChanged方法
        observer.mObserver.onChanged((T) mData);
    }

以上是当数据变化可观察到实现原理

3. LiveData 仅更新处于活跃生命周期状态的应用组件观察者。生命周期感知能力是在哪里体现的?

其实上面源码中,有两处关于生命周期的判断
1.注册的时候

  public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
      ...
    //如果生命周期destroyed 不添加
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
    ...
  }

2.触发事件的时候

   private void considerNotify(ObserverWrapper observer) {
  //当前observer不活跃,就是不更新
        if (!observer.mActive) {
            return;
        }
}

LiveData官网介绍中有着一段话:
https://developer.android.google.cn/reference/androidx/lifecycle/LifecycleOwner
https://developer.android.google.cn/reference/androidx/lifecycle/Lifecycle
https://developer.android.google.cn/reference/androidx/lifecycle/Lifecycle.State#DESTROYED
您可以注册与实现LifecycleOwner接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle对象的状态变为 DESTROYED() 时,便可移除此观察者。 这对于 Activity 和 Fragment 特别有用,因为它们可以放心地观察 LiveData 对象而不必担心泄露(当 Activity 和 Fragment 的生命周期被销毁时,系统会立即退订它们)。
( model.getCurrentName().observe(activity,nameObserver);)

下面具体看下lifecycleOwner的实现

上面又说到LifecycleOwner是一个接口,而Activity实现,那LifecycleOwner是个什么呢?

主要的实现点都在 LifecycleOwner Lifecycle getLifecycle(),

 public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

LifecycleRegistry extends Lifecycle

FragmentActivity 这个是常用的
final LifecycleRegistry mFragmentLifecycleRegistry = new LifecycleRegistry(this);
下面看一下Lifeycle源码

public abstract class Lifecycle {

    /**
     * Lifecycle coroutines extensions stashes the CoroutineScope into this field.
     *
     * @hide used by lifecycle-common-ktx
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    @NonNull
    AtomicReference<Object> mInternalScopeRef = new AtomicReference<>();

    /**添加生命周期观察者,当生命周期改变将notyfity */
    @MainThread
    public abstract void addObserver(@NonNull LifecycleObserver observer);

    /**  移除生命周期观察者*/
    @MainThread
    public abstract void removeObserver(@NonNull LifecycleObserver observer);

    /**返回当前生命周期状态*/
    @MainThread
    @NonNull
    public abstract State getCurrentState();

    @SuppressWarnings("WeakerAccess")
    public enum Event {
        /**
         * Constant for onCreate event of the {@link LifecycleOwner}.
         */
        ON_CREATE,
        /**
         * Constant for onStart event of the {@link LifecycleOwner}.
         */
        ON_START,
        /**
         * Constant for onResume event of the {@link LifecycleOwner}.
         */
        ON_RESUME,
        /**
         * Constant for onPause event of the {@link LifecycleOwner}.
         */
        ON_PAUSE,
        /**
         * Constant for onStop event of the {@link LifecycleOwner}.
         */
        ON_STOP,
        /**
         * Constant for onDestroy event of the {@link LifecycleOwner}.
         */
        ON_DESTROY,
        /**
         适配任何状态
         * An {@link Event Event} constant that can be used to match all events.
         */
        ON_ANY
    }

    /**
     * Lifecycle states. You can consider the states as the nodes in a graph and
     * {@link Event}s as the edges between these nodes.
      生命周期状态。您可以将状态视为图中的节点,而{@link事件}则视为这些节点之间的边。

     */
    @SuppressWarnings("WeakerAccess")
    public enum State {
        /**
         * Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch
         * any more events. For instance, for an {@link android.app.Activity}, this state is reached
         * <b>right before</b> Activity's {@link android.app.Activity#onDestroy() onDestroy} call.
        在onDestroy()之前调用
         */
        DESTROYED,

        /**
         * Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is
         * the state when it is constructed but has not received
         * {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet.
         初始化状态,在onCreate()之前
         */
        INITIALIZED,

        /**
         * Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state
         * is reached in two cases:
         * <ul>
         *     <li>after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call;
         *     <li><b>right before</b> {@link android.app.Activity#onStop() onStop} call.
         * </ul>
       onCreate()之后,onStop()之前
         */
        CREATED,

        /**
         * Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state
         * is reached in two cases:
         * <ul>
         *     <li>after {@link android.app.Activity#onStart() onStart} call;
         *     <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.
         * </ul>
        onStart()之后 onPause()之前
         */
        STARTED,

        /**
         * Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state
         * is reached after {@link android.app.Activity#onResume() onResume} is called.
         */
        RESUMED;

        /**
         * Compares if this State is greater or equal to the given {@code state}.
         *
         * @param state State to compare with
         * @return true if this State is greater or equal to the given {@code state}
       如果此状态大于或等于给定的{@code状态},则返回true

         */
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }
}

生命周期状态的改变:
在FragmentActitivty中,每个节点调用下面代码,更改状态 mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);

一个Activity 对应一个 mObserverMap,也就是当前的变化,只通知当前页面?
解决mvp 内存泄漏 可以用livedata

问题livedata 如何和Retrofit一起使用
1.我们可以把livedata作为参数传入,使用livedata.setValue()把数据设置进去

  1. retrofit 返回值返回livedata(默认是Call) ,自定义calladapter

DataBinding

https://developer.android.google.cn/jetpack/androidx/releases/databinding

https://developer.android.google.cn/topic/libraries/data-binding

开启dataBinding

android {
    ...
    dataBinding {
        enabled = true
    }

android {
    ...
    buildFeatures {
        dataBinding true
    }
}

简单使用:
Activity中

 var binding = DataBindingUtil.setContentView<ActivityDataBindingBinding>(this,R.layout.activity_data_binding)
//绑定数据,注意此处只是单向绑定,数据变化,xml中不会变更
//此类型的对象拥有永不改变的数据(最好)
binding.student = getStudent()

activity_data_binding.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="student"
            type="com.example.testjetpack.bean.Student" />
      <!--<variable .....可以多个 --> 

    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".DataBindingActivity"
        android:gravity="center">

       <!--  android:text="@{student.name}"
布局表达式应保持精简,因为它们无法进行单元测试,并且拥有的 IDE 支持也有限。
为了简化布局表达式,可以使用自定义[绑定适配器](https://developer.android.google.cn/topic/libraries/data-binding/binding-adapters)。--> 

        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{student.name}"
            />

        <TextView
            android:id="@+id/age"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(student.age)}"
            />

  ......

    </LinearLayout>
</layout>

其中ActivityDataBindingBinding为编译期间自动生成,其位置在


截屏2020-10-22下午2.19.53.png
截屏2020-10-22下午2.20.41.png

在Fragment RecyclerView中可以这样:

 ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());

 ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
    // or
 ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

双向绑定,使用可观察到数据(这个如果和LiveData一起使用,功能有点重复,但是使用方向上也有些区别,实战没有,暂时无法感知)

 var binding = DataBindingUtil.setContentView<ActivityDataBindingBinding>(this,R.layout.activity_data_binding)
        //一个纯净的student改变 ui并不会跟着改变,需要继承 BaseObservable 或者 参数需要是Observable类型
        var student = Student(ObservableField("王甜甜"), ObservableInt(21))
        binding.student = student
        binding.button.setOnClickListener {
            //一定要使用set方法,直接=无效
            student.name.set("王一博")
        }

未完待续
注解

自定义方法名称

@BindMethods 映射类中的方法和属性名字,自定义方法的实现,也可以改变现有类的方法和属性的对应关系
注解声明的位置可以是任意类(但是type不要写Activity,会有问题 报错找不到ActivityBindingImpl类)

@BindingMethods({
        @BindingMethod(type = TextView.class,
                attribute = "android:test",
                method = "setText"),
})
public class LoginActivity extends BaseActivity{}

TextView类,将xml android:test 对应其setText方法

自定义处理逻辑 (使用了DataBindingComponent,就不能在其他地方定义@BindingAdapter)

@BindingAdapter

1.基础使用

 @BindingAdapter("android:paddingLeft")
    fun setPaddingLeft(view: View, padding: Int) {
        view.setPadding(padding,
                    view.getPaddingTop(),
                    view.getPaddingRight(),
                    view.getPaddingBottom())
    }
    

参数1: 持有属性的View
参数2: 属性的取值

  1. 多个属性值处理
Activity中:
 @BindingAdapter("imageUrl", "error")
    fun loadImage(view: ImageView, url: String, error: Drawable) {
        Picasso.get().load(url).error(error).into(view)
    }

xml布局:
<ImageView 
app:imageUrl="@{venue.imageUrl}"
 app:error="@{@drawable/venueError}" />

事件处理脚本只能与具有一种抽象方法的接口或抽象类一起使用
@BindingAdapter(
"android:onViewDetachedFromWindow",
"android:onViewAttachedToWindow",
requireAll = false//以指定并非必须为每个属性都分配绑定表达式
)

自定义转换: 属性值或许不是我们需要的类型,需要转换

https://www.jianshu.com/p/9bd2f3069d2e

DataBinding 源码分析
DataBindingUtils

 public static <T extends ViewDataBinding> T setContentView(@NonNull Activity activity,
            int layoutId, @Nullable DataBindingComponent bindingComponent) {
       //activity设置布局文件
        activity.setContentView(layoutId);
        View decorView = activity.getWindow().getDecorView();
        ViewGroup contentView = (ViewGroup) decorView.findViewById(android.R.id.content);
        return bindToAddedViews(bindingComponent, contentView, 0, layoutId);
    }

错误:
view must have a tag
因为的的布局 总布局是在BaseActivityWithtitle中

@Override
    public void setContentView(int layoutResID) {
        int layoutId = layoutResID;
        if (layoutId != -1) {
            LinearLayout content_view = (LinearLayout) View.inflate(this, R.layout.base_title_bar, null);
            fl_root_content = content_view.findViewById(R.id.fl_root_content);
            fl_root_content.addView(View.inflate(this, layoutId, null));
           //contentView并不是我们的布局,而是R.layout.base_title_bar,这个被共有,所以出错
            setContentView(content_view);
            initTitleBar();
        }

livedata只更新具有活跃生命周期的
Observable 会更新全部

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272