GVKun编程网logo

android-从LiveData.observe()向适配器添加项目的最佳实践(android recyclerview适配器)

11

本文将介绍android-从LiveData.observe()向适配器添加项目的最佳实践的详细情况,特别是关于androidrecyclerview适配器的相关信息。我们将通过案例分析、数据研究等多

本文将介绍android-从LiveData.observe()向适配器添加项目的最佳实践的详细情况,特别是关于android recyclerview适配器的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于android -------- LiveDataBus的使用、Android BaseAdapter DataSetObserver通知机制、Android Data Binding 系列 (二) -- Binding 与 Observer 实现原理、Android jetpack 之 LiveData的知识。

本文目录一览:

android-从LiveData.observe()向适配器添加项目的最佳实践(android recyclerview适配器)

android-从LiveData.observe()向适配器添加项目的最佳实践(android recyclerview适配器)

我有DAO方法返回了LiveData< List< Category>&gt ;:

LiveData<List<Category>> listLiveData = categoryDao.getAll();

之后,我需要将此数据设置为我的适配器:

listLiveData.observe(this, categories -> {
      if (categories == null || categories.isEmpty()) {
            price.setVisibility(View.VISIBLE);
            recyclerView.setVisibility(View.INVISIBLE);
        } else {
            categoryAdapter = new CategoryAdapter(categories);
            categoryAdapter.setonItemClickListener(new ClickHandler());
            recyclerView.setAdapter(categoryAdapter);
        }
 });

如果数据库中没有数据,则显示更新按钮(从服务器获取数据并插入到数据库中).
如果我有数据,我将创建适配器并为其设置数据.

之后,如果我向数据库插入一些类别,则会得到以下信息:

>触发观察方法并获取所有类别
>使用此数据创建新的适配器

我认为这是非常不好的做法(为更新每个项目创建一个新的适配器),我可以采取一些措施:

>更改我的适配器并添加方法addData(List< Category> Categories);

在onCreateView中,我创建适配器:categoryAdapter = new CategoryAdapter(new ArrayList());

然后当我在观察方法中获取数据时,将其添加到适配器中:

adapter.addData(categories); 

并在addData方法中循环检查每个项目,如果不存在,则添加到列表并通知数据.

>变更方法

实时数据listLiveData = categoryDao.getAll();

LiveData<Category> category = categoryDao.getLast();

并添加此项以观察方法.但是我有2个问题:1-如何首先添加所有数据?我必须实现2个方法getAll(调用创建适配器)和getLast(调用数据库中的每个插入). 2.如何编写此getLast方法?

>正确的方法,你会建议我:)

解决方法:

>第一步是正确的,您应该仅在Fragment或Activity的生命周期中创建适配器一次,并在需要更改数据集时将值(列表)设置为adapter.
>您应该使用getAll()方法,这是最佳实践,因为您的数据在本地数据库中,并且不需要花费更长的时间.如果数据集较长,则应使用分页,其中仅限制为no.一次提取的商品数量.这可以通过在sqlite中使用LIMIT子句查询来实现.
>然后使用notifyDatasetChanged()方法.如果要为新插入的项目显示平滑的动画,请使用DiffUtil类比较列表并相应地通知适配器.

要知道如何使用DiffUtil,请检查https://medium.com/@iammert/using-diffutil-in-android-recyclerview-bdca8e4fbb00

希望这可以帮助.

android -------- LiveDataBus的使用

android -------- LiveDataBus的使用

LiveData是17年GoogleIO大会上提出来的一个新技术。相对于通信总线类型的框架EventBus和RxBus来说,它更简单,更简洁、更解耦。


LiveEventBus是一款Android消息总线,基于LiveData,具有生命周期感知能力,支持Sticky,支持AndroidX,支持跨进程,支持跨APP


LiveDataBus优点

LiveDataBus的实现及其简单

相对EventBus复杂的实现,LiveDataBus只需要一个类就可以实现


LiveDataBus可以减小APK包的大小

LiveDataBus只依赖Android官方组件LiveData,本身实现只一个类。EventBus 57Kb、RxJava 2.2M


LiveDataBus 依赖方支持更好

LiveDataBus只依赖Android官方组件LiveData,相比RxBus依赖的RxJava和RxAndroid,依赖方支持更好


LiveDataBus具有生命周期感知


LiveDataBus具有生命周期感知,在Android系统中使用调用者不需要调用反注册,相比EventBus和RxBus使用更为方便,并且没有内存泄漏风险。


LiveEventBus的特点

生命周期感知,消息随时订阅,自动取消订阅
支持Sticky粘性消息
支持AndroidX
支持跨进程通信
支持跨APP通信
支持设置LifecycleObserver(如Activity)接收消息的模式:

1.整个生命周期(从onCreate到onDestroy)都可以实时收到消息
2.激活状态(Started)可以实时收到消息,非激活状态(Stoped)无法实时收到消息,需等到Activity重新变成激活状态,方可收到消息


在工程中引用
implementation ''com.jeremyliao:live-event-bus:1.4.2''

配置
在 Application.onCreate 方法中配置:

LiveEventBus.get()
        .config()
        .supportBroadcast(this)
        .lifecycleObserverAlwaysActive(true);

具有生命周期感知能力,LifecycleOwner销毁时自动取消订阅,不需要调用removeObserver

保证 with() 中的key值相同,(注册/接收)和发起通信

注册:

LiveEventBus.get().with("LiveDataBusDemo1",String.class).observe(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
Log.i("aaa",s);
}
});


发起通信

LiveEventBus.get().with("LiveDataBusDemo1").post("LiveDataBus1");

 

以Forever模式订阅和取消订阅消息,Forever模式订阅消息,需要手动调用removeObserver取消订阅

注册

private Observer<String> observer = new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
Log.i("aaa",s);
textView.setText("observeForever注册的观察者收到消息: " + s);
}
};

LiveEventBus.get()
.with("LiveDataBusDemo2", String.class)
.observeForever(observer);

 

发起通信

LiveEventBus.get().with("LiveDataBusDemo2").post("LiveDataBus2");

 

手动取消订阅消息

LiveEventBus.get()
.with("LiveDataBusDemo2", String.class)
.removeObserver(observer);

 

 

Sticky模式(可以接收 前面/未注册之前 发起通信的信息)

支持在订阅消息的时候设置Sticky模式,这样订阅者可以接收到之前发送的消息,当然也支持后面发送的信息

以Sticky模式订阅消息,具有生命周期感知能力,LifecycleOwner销毁时自动取消订阅,不需要调用removeObserver

 

注册

LiveEventBus.get()
.with("LiveDataBusDemo3", String.class)
.observeSticky(this, new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
Log.i("aaa",s);
textView.setText("observeSticky注册的观察者收到消息: " + s);
}
});

 


发起通信(你可以在注册之前和注册之后分辨发起通知看效果)

LiveEventBus.get().with("LiveDataBusDemo3").post("LiveDataBus3");


observeStickyForever,Forever模式订阅消息,需要手动调用removeObserver取消订阅,和上面的一样


注册

private Observer<String> observer = new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
Log.i("aaa",s);
textView.setText("observeStickyForever注册的观察者收到消息: " + s);
}
};


LiveEventBus.get()
.with("LiveDataBusDemo4", String.class)
.observeStickyForever(observer);

 

 


发起通信

LiveEventBus.get().with("LiveDataBusDemo4").post("LiveDataBus4");

 

手动取消订阅消息

LiveEventBus.get()
.with("LiveDataBusDemo4", String.class)
.removeObserver(observer);

 

混淆规则

-dontwarn com.jeremyliao.liveeventbus.**
-keep class com.jeremyliao.liveeventbus.** { *; }
-keep class android.arch.lifecycle.** { *; }
-keep class android.arch.core.** { *; }

 

参考文档:
https://github.com/JeremyLiao/LiveEventBus

Android BaseAdapter DataSetObserver通知机制

Android BaseAdapter DataSetObserver通知机制

一.BaseAdapter内部设有观察者机制

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
   
    private final DataSetObservable mDataSetObservable = new DataSetObservable();

    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

    public void unregisterDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.unregisterObserver(observer); //刷新界面和数据
    }

    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged(); //刷新界面
    }


    public void notifyDataSetInvalidated() {
        mDataSetObservable.notifyInvalidated();
    }
    /**
    *一下省略到一大片成员变量 
    *方法数(何止一二个)
    *变量(反正已知的不多)
    */
    }

其中我们看到了

--观察者集合容器

DataSetObservable

--观察者

public abstract class DataSetObserver {

    public void onChanged() {
        // Do nothing
    }

    public void onInvalidated() {
        // Do nothing
    }
}

二,应用

首先:这些观察者普遍存在于BaseAdapter,FragmentPagerAdapter,PagerAdapter,RecyclerView.Adapter中,主要是为了配合适配器更新数据


应用一.RecylerView中的EmptyView

public class RecyclerViewEmptySupport extends RecyclerView {
    private View emptyView;

    private AdapterDataObserver emptyObserver = new AdapterDataObserver() {


        @Override
        public void onChanged() {
            Adapter<?> adapter =  getAdapter();
            if(adapter != null && emptyView != null) {
                if(adapter.getItemCount() == 0) {
                    emptyView.setVisibility(View.VISIBLE);
                    RecyclerViewEmptySupport.this.setVisibility(View.GONE);
                }
                else {
                    emptyView.setVisibility(View.GONE);
                    RecyclerViewEmptySupport.this.setVisibility(View.VISIBLE);
                }
            }

        }
    };

    public RecyclerViewEmptySupport(Context context) {
        super(context);
    }

    public RecyclerViewEmptySupport(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public RecyclerViewEmptySupport(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setAdapter(Adapter adapter) {
        super.setAdapter(adapter);

        if(adapter != null) {
            adapter.registerAdapterDataObserver(emptyObserver);
        }

        emptyObserver.onChanged();
    }

    public void setEmptyView(View emptyView) {
        this.emptyView = emptyView;
    }}

xml

<com.maff.utils.RecyclerViewEmptySupport android:id="@+id/list1"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    /><TextView android:id="@+id/list_empty"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Empty"
    />

Activity

RecyclerViewEmptySupport list = 
    (RecyclerViewEmptySupport)rootView.findViewById(R.id.list1);
    list.setLayoutManager(new LinearLayoutManager(context));
    list.setEmptyView(rootView.findViewById(R.id.list_empty));

应用二,我们可以通过注册观察者,判断数据变化我们可以减少判断,特别在加载网络数据的时候

应用三,我们可以在数据变化时开始某一类动画

Android Data Binding 系列 (二) -- Binding 与 Observer 实现原理

Android Data Binding 系列 (二) -- Binding 与 Observer 实现原理

写在前面

上篇文章 Android Data Binding 系列 (一) -- 详细介绍与使用 介绍了 Data Binding 的基础及其用法,本文接上篇,结合 DataBindingDemo 来学习下 Data Binding 的实现。

绑定实现

Activity 在 inflate layout 时,通过 DataBindingUtil 来生成绑定,从代码看,是遍历 contentView 得到 View 数组对象,然后通过数据绑定 library 生成对应的 Binding 类,含 Views、变量、listeners 等。生成类位于 build/intermediates/classes/debug/...package.../databinding/xxx.java 下,具体如何生成这里暂不作深入。

绑定过程

  • 首先,会在父类(ViewDataBinding)中实例化回调或 Handler,用于之后的绑定操作;
private static final boolean USE_CHOREOGRAPHER = SDK_INT >= 16;

if (USE_CHOREOGRAPHER) {
    mChoreographer = Choreographer.getInstance();
    mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            mRebindRunnable.run();
        }
    };
} else {
    mFrameCallback = null;
    mUIThreadHandler = new Handler(Looper.myLooper());
}
  • 接着,通过调用 mapBindings(...) 遍历布局以获得包含 bound、includes、ID Views 的数组对象,再依次赋给对应 View
final Object[] bindings = mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds);
this.mboundView0 = (android.widget.LinearLayout) bindings[0];
this.mboundView0.setTag(null);
  • 然后,调用 invalidateAll() -> requestRebind() -> ... -> mRebindRunnable.run() - 执行 Runnable
// 用于动态重新绑定 Views
private final Runnable mRebindRunnable = new Runnable() {
    @Override
    public void run() {
        synchronized (this) {
            mPendingRebind = false;
        }
        .....
        executePendingBindings();
    }
};
  • 最后,通过该 Runnable 会执行到 executePendingBindings() -> ... -> executeBindings(),在这里会执行绑定相关操作。
@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;   // mDirtyFlags 变量更新的标志
        mDirtyFlags = 0;
    }
    .....
}

设置变量 (数据对象)

普通 Java bean 对象

  • 首先,通过 mDirtyFlags 标识变量 (所有变量共用)
synchronized(this) {
    mDirtyFlags |= 0x1L;
}
  • 然后,调用 notifyPropertyChanged(...) 来通知更新(若有回调)
public void notifyPropertyChanged(int fieldId) {
    if (mCallbacks != null) {
        mCallbacks.notifyCallbacks(this, fieldId, null);
    }
}
  • 最后,调用 requestRebind() -> ... -> executeBindings() 再次执行绑定操作,将数据更新到 Views 上
@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    .....
}

Observable 对象

  • 在设置变量时,会先调用 updateRegistration(..) 注册一个 Observable 对象的监听
public void setContact(com.connorlin.databinding.model.ObservableContact contact) {
    updateRegistration(0, contact);
    this.mContact = contact;
    synchronized(this) {
        mDirtyFlags |= 0x1L;
    }
    notifyPropertyChanged(BR.contact);
    super.requestRebind();
}
  • 其他步骤同普通 Java bean 对象

ObservableFields 对象

  • 前期步骤同普通 Java Bean 对象

  • 与 Observable 对象不同的是,Observable 对象的监听是在 executeBindings() 中注册的

@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    ...
    if ((dirtyFlags & 0xfL) != 0) {
        if ((dirtyFlags & 0xdL) != 0) {
            if (contact != null) {
                // read contact.mName
                mNameContact = contact.mName;
            }
            updateRegistration(0, mNameContact);

            if (mNameContact != null) {
                // read contact.mName.get()
                mNameContact1 = mNameContact.get();
            }
        }
        ...
    }
    ...
}

注册 Observable 对象监听

  • 入口 updateRegistration(0, contact)
protected boolean updateRegistration(int localFieldId, Observable observable) {
    return updateRegistration(localFieldId, observable, CREATE_PROPERTY_LISTENER);
}

private boolean updateRegistration(int localFieldId, Object observable,
        CreateWeakListener listenerCreator) {
    ...
    // 确保不重复监听,先移除再添加观察监听
    unregisterFrom(localFieldId);
    registerTo(localFieldId, observable, listenerCreator);
    return true;
}

protected void registerTo(int localFieldId, Object observable,
        CreateWeakListener listenerCreator) {
    if (observable == null) {
        return;
    }

    // 创建对象监听并存到mLocalFieldObservers中
    WeakListener listener = mLocalFieldObservers[localFieldId];
    if (listener == null) {
        // CREATE_PROPERTY_LISTENER -> create(...)
        listener = listenerCreator.create(this, localFieldId);
        mLocalFieldObservers[localFieldId] = listener;
    }

    // 将监听绑定到Observable对象上
    listener.setTarget(observable);
}

每个 Observable 对象都会添加一个观察监听,保存在数组 mLocalFieldObservers 中,并以 localFieldId 索引。

  • CREATE_PROPERTY_LISTENER 为何物?
private static final CreateWeakListener CREATE_PROPERTY_LISTENER = new CreateWeakListener() {
    @Override
    public WeakListener create(ViewDataBinding viewDataBinding, int localFieldId) {
        // 返回从WeakPropertyListener实例中获取的监听器(WeakListener)
        return new WeakPropertyListener(viewDataBinding, localFieldId).getListener();
    }
}

private static class WeakPropertyListener extends Observable.OnPropertyChangedCallback
        implements ObservableReference<Observable> {
    final WeakListener<Observable> mListener;

    public WeakPropertyListener(ViewDataBinding binder, int localFieldId) {
        mListener = new WeakListener<Observable>(binder, localFieldId, this);
    }

    @Override
    public WeakListener<Observable> getListener() {
        return mListener;
    }

    @Override
    public void addListener(Observable target) {
        // WeakPropertyListener 继承于 Observable.OnPropertyChangedCallback,
        // 所以 this 其实就是 Observable对象的属性监听器
        target.addOnPropertyChangedCallback(this);
    }

    ...
}

private static class WeakListener<T> extends WeakReference<ViewDataBinding> {
    private final ObservableReference<T> mObservable;
    protected final int mLocalFieldId;
    private T mTarget;

    ...

    public void setTarget(T object) {
        unregister();
        mTarget = object;
        if (mTarget != null) {
            // mObservable 是上面的 WeakPropertyListener对象
            // mTarget 是绑定到listener上得Observable对象
            mObservable.addListener(mTarget);
        }
    }

    ...
}

CREATE_PROPERTY_LISTENER 实际上只是一个接口实例,注册时会调用它的 create() 方法创建一个弱引用 listener,它的作用是将 listener 绑定到 Observable 对象上, 绑定时,会调用 listener.setTarget(...) 将 Observable 对象传给 WeakPropertyListener 实例,然后,WeakPropertyListener 会为 Observable 对象添加 OnPropertyChangedCallback

  • addOnPropertyChangedCallback 实现

addOnPropertyChangedCallback 在 BaseObservable 中实现,首先会实例化一个 PropertyChangeRegistry 对象,同时创建一个用来通知 Observable 对象重新绑定更新的回调 CallbackRegistry.NotifierCallback。然后将 OnPropertyChangedCallback 添加到 PropertyChangeRegistry 的回调列表中

@Override
public synchronized void addOnPropertyChangedCallback(OnPropertyChangedCallback callback) {
    if (mCallbacks == null) {
        mCallbacks = new PropertyChangeRegistry();
    }
    mCallbacks.add(callback);
}

这样,注册 Observable 对象的监听就完毕了。

更新 (重新绑定) Observable 对象

设置或更新 Observable 对象时都会调用 notifyPropertyChanged()notifyChange() 来通知更新,那到底是如何更新的呢?

  • 回调过程
public void notifyPropertyChanged(int fieldId) {
    // mCallbacks 是 PropertyChangeRegistry对象,在 addOnPropertyChangedCallback 时实例化
    // 如果注册了Observable对象监听,那么mCallbacks不为null
    if (mCallbacks != null) {
        mCallbacks.notifyCallbacks(this, fieldId, null);
    }
}

// baseLibrary
private void notifyCallbacks(T sender, int arg, A arg2, int startIndex, int endIndex, long bits) {
    long bitMask = 1L;
    for(int i = startIndex; i < endIndex; ++i) {
        if((bits & bitMask) == 0L) {
            // mNotifier 是实例化PropertyChangeRegistry时创建的
            // mNotifier 即 CallbackRegistry.NotifierCallback
            this.mNotifier.onNotifyCallback(this.mCallbacks.get(i), sender, arg, arg2);
        }
        bitMask <<= 1;
    }
}

// PropertyChangeRegistry.NOTIFIER_CALLBACK
public void onNotifyCallback(Observable.OnPropertyChangedCallback callback, Observable sender,
        int arg, Void notUsed) {
    // callback 是为Observable对象添加的OnPropertyChangedCallback,即WeakPropertyListener
    callback.onPropertyChanged(sender, arg);
}

// WeakPropertyListener
public void onPropertyChanged(Observable sender, int propertyId) {
    // binder 即生成的Binding类对象
    ViewDataBinding binder = mListener.getBinder();
    ...
    binder.handleFieldChange(mListener.mLocalFieldId, sender, propertyId);
}

private void handleFieldChange(int mLocalFieldId, Object object, int fieldId) {
    // onFieldChange 实现在生成的Binding类中
    boolean result = onFieldChange(mLocalFieldId, object, fieldId);
    if (result) {
        // 如果对象属性变化,将重新绑定
        requestRebind();
    }
}

通过 notifyPropertyChanged 调用到 mNotifier 回调, mNotifier 通知 OnPropertyChangedCallback Observable 对象属性发生变化,然后在 onPropertyChanged 中又转给 ViewDataBinding 对象 (生成的 Binding 类) 处理。

  • 判断是否需要重新绑定并执行,在生成的 Binding 类中实现
// 生成的Binding类中得方法
protected boolean onFieldChange(int localFieldId, Object object, int fieldId) {
    // 如果变量不是Observable类型或没有添加 Bindable注解,就不会判断,直接返回false
    switch (localFieldId) {
        case 0 :
            return onChangeContact((com.connorlin.databinding.model.ObservableContact) object, fieldId);
    }
    return false;
}

private boolean onChangeContact(com.connorlin.databinding.model.ObservableContact contact, int fieldId) {
    switch (fieldId) {
        case BR.name: {
            synchronized(this) {
                    mDirtyFlags |= 0x4L;// 通过mDirtyFlags判断对象是否变化
            }
            return true;
        }
        ...
    }
    return false;
}

至此,更新过程完毕。

整个注册与更新过程可以用一张流程图来概括:

事件处理

事件处理的原理很简单,在生成 Binding 类中会实现 View 事件的监听,在构造时实例化 View 的事件监听,然后在绑定时将事件监听对象赋值给对应 View,这样,点击时就会触发相应的监听。

这里以 DataBindingDemo 中 EventActivity 部分为例:

  • 生成的 Binding 类并实现 View 的事件监听
public class ActivityEventBinding extends android.databinding.ViewDataBinding
    implements android.databinding.generated.callback.OnCheckedChangeListener.Listener,
        android.databinding.generated.callback.OnClickListener.Listener {
    // Checkbox check监听
    private final android.widget.CompoundButton.OnCheckedChangeListener mCallback3;
    private final android.view.View.OnClickListener mCallback2;
    private final android.view.View.OnClickListener mCallback1;
    // listeners
    private OnClickListenerImpl mAndroidViewViewOnCl;
    ...
    // Listener Stub Implementations
    public static class OnClickListenerImpl implements android.view.View.OnClickListener{
        private com.connorlin.databinding.handler.EventHandler value;
        public OnClickListenerImpl setValue(com.connorlin.databinding.handler.EventHandler value) {
            this.value = value;
            return value == null ? null : this;
        }
        @Override
        public void onClick(android.view.View arg0) {
            this.value.onClickFriend(arg0);
        }
    }
    ...
}
  • 实例化 View 的事件监听
public ActivityEventBinding(android.databinding.DataBindingComponent bindingComponent, View root) {
    super(bindingComponent, root, 0);
    ...
    // listeners
    mCallback3 = new android.databinding.generated.callback.OnCheckedChangeListener(this, 3);
    mCallback2 = new android.databinding.generated.callback.OnClickListener(this, 2);
    mCallback1 = new android.databinding.generated.callback.OnClickListener(this, 1);
    invalidateAll();
}
  • 在执行绑定中绑定 View 事件监听
@Override
protected void executeBindings() {
    ...
    if ((dirtyFlags & 0x6L) != 0) {
        if (handler != null) {
            // read handler::onClickFriend
            androidViewViewOnCli = (((mAndroidViewViewOnCl == null)
                ? (mAndroidViewViewOnCl = new OnClickListenerImpl()) : mAndroidViewViewOnCl).setValue(handler));
        }
    }
    // batch finished
    if ((dirtyFlags & 0x6L) != 0) {
        this.mboundView1.setOnClickListener(androidViewViewOnCli);
    }
    if ((dirtyFlags & 0x4L) != 0) {
        this.mboundView2.setOnClickListener(mCallback1);
        this.mboundView3.setOnClickListener(mCallback2);
        android.databinding.adapters.CompoundButtonBindingAdapter.setListeners(
            this.mboundView4, mCallback3, (android.databinding.InverseBindingListener)null);
    }
}
  • 触发事件并执行

ViewStub

原理类似,只是利用 ViewStubProxy 来延迟绑定。

  • 使用 layout 中的 ViewStub 实例化一个 ViewStubProxy 对象赋给 viewstub 变量,并与 Bingding 关联
public ActivityViewStubBinding(android.databinding.DataBindingComponent bindingComponent, View root) {
    super(bindingComponent, root, 0);
    final Object[] bindings = mapBindings(bindingComponent, root, 2, sIncludes, sViewsWithIds);
    ...
    this.viewStub = new android.databinding.ViewStubProxy((android.view.ViewStub) bindings[1]);
    this.viewStub.setContainingBinding(this);
    ...
}
  • 实例化 ViewStubProxy 的同时会注册 inflate 监听
private OnInflateListener mProxyListener = new OnInflateListener() {
    @Override
    public void onInflate(ViewStub stub, View inflated) {
        mRoot = inflated;
        mViewDataBinding = DataBindingUtil.bind(mContainingBinding.mBindingComponent,
                inflated, stub.getLayoutResource());
        mViewStub = null;

        if (mOnInflateListener != null) {
            mOnInflateListener.onInflate(stub, inflated);
            mOnInflateListener = null;
        }
        mContainingBinding.invalidateAll();
        mContainingBinding.forceExecuteBindings();
    }
};

public ViewStubProxy(ViewStub viewStub) {
    mViewStub = viewStub;
    mViewStub.setOnInflateListener(mProxyListener);
}
  • inflate ViewStub
if (!mActivityViewStubBinding.viewStub.isInflated()) {
    mActivityViewStubBinding.viewStub.getViewStub().inflate();
}

当 ViewStub infate 时,执行 mProxyListener,其中会生成 ViewStub 的 Binding,并强制执行主 Binding 重绑

  • 绑定 ViewStub
@Override
protected void executeBindings() {
    long dirtyFlags = 0;
    synchronized(this) {
        dirtyFlags = mDirtyFlags;
        mDirtyFlags = 0;
    }
    // batch finished
    if (viewStub.getBinding() != null) {
        viewStub.getBinding().executePendingBindings();
    }
}

这样,ViewStub 绑定就结束了。

本篇完,敬请期待下篇...


我的简书账号是 ConnorLin,欢迎关注!

我的简书专题是 Android 开发技术分享,欢迎关注!

我的个人博客 欢迎关注!

原创文章,欢迎转载,转载请注明出处!

欢迎您扫一扫上面的微信公众号,订阅我的博客!

Android jetpack 之 LiveData

Android jetpack 之 LiveData

首先,LiveData是什么
LiveData是一种可以被观察的数据存储器类,它可以感知其他组件(比如Activity,Fragment)的生命周期,并只更新处于活跃状态的组件. 当我们的应用组件处于 STARTEDRESUMED 状态,LiveData则会认为该组件处于活跃状态

开始使用LiveData,LiveData一般搭配viewmodel一起使用
首先我们会创建一个viewmodel,在viewmodel里面在创建LiveData,并提供getter方法进行访问.

class Nameviewmodel : viewmodel() {
    //LiveData是一个抽象类,一般使用它的 mutablelivedata 实现
    val currentName: mutablelivedata<String> by lazy {
        mutablelivedata<String>()
    }
}

接着在Activity的onCreate()方法中获取我们的Numviewmodel (在依赖了Android KTX 中的 Fragment KTX模块后, 可以直接使用viewmodels和activityviewmodels属性委托绑定到viewmodel),接着为LiveDta注册观察者

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    //获取viewmodel对象
    val model = viewmodelProvider(this,
        viewmodelProvider.NewInstanceFactory()).get(Nameviewmodel::class.java)
    //创建观察者对象
    val nameObserver = Observer<String> { name ->
        //更新UI
    }
    //通过observe()来注册观察者
    model.currentName.observe(this, nameObserver)
}

在注册观察者之后系统会立即调用onChange()方法,来提供currentName中的最新值,如果LiveData对象尚未在currentName中设置值,则onChange()方法不会被调用.
现在已经创建了LiveData对象并且设置了观察者.我们只需要更新LiveData对象就可以完成对onChange()方法的调用.LiveData提了 setValue(T) 和 postValue(T) 两个方法来更新值,第一个用来在主线程上使用,第二个用来在工作线程上使用.

button.setonClickListener {
    model.currentName.setValue("乌鸡哥")
}

LiveData 是怎么工作的
首先我们看下LiveData是如何注册一个观察者的

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    //该方法一定要在主线程上调用
    assertMainThread("observe");
    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);
}

observe()方法的第一个参数是一个接口,提供了一个获取Lifecycle的方法,该对象可以对我们应用组件(如Activity,Fragment)的生命周期进行监听.LiveData能感知组件生命周期的能力就它带来的.  第二个参数就是我们的观察者对象.
从上面的代码可以看出.如果该观察者所在的组件已经销毁,则什么也不会做. 
紧接着,把我们传入的owner 和 observer 做了一个包装. 这个包装类实现了GenericLifecycleObserver这个接口.
然后把我们的观察者都存储到mObservers这个SafeIterableMap里.在这里做了一个判断,即一个观察者只能观察一个LiveData对象.
最后把我们的包装类和Lifecycle做了关联,这时我们的LiveData就获得了应用组件的生命周期感知能力.

那这个包装类是什么

class LifecycleBoundobserver extends ObserverWrapper implements GenericLifecycleObserver {
    @NonNull
    final LifecycleOwner mOwner;

    LifecycleBoundobserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);
        mOwner = owner;
    }

    //判断该组件是否是活跃状态,大于等于STARTED时返回true
    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    //当组件的生命周期发生改变时调用
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        activeStateChanged(shouldBeActive());
    }

    @Override
    boolean isAttachedTo(LifecycleOwner owner) {
        return mOwner == owner;
    }

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}

.当观察者所在的组件生命周期发生改变后,会回调onStartChange,在里面会首先检查组件是不是已经销毁,销毁的话需要移除LiveData的观察者,还要移除包装类和Lifecycle的关联.

@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    assertMainThread("removeObserver");
    ObserverWrapper removed = mObservers.remove(observer);
    if (removed == null) {
        return;
    }
    removed.detachObserver();
    removed.activeStateChanged(false);
}

在里面首先会从mObservers这个SafeIterableMap里面移除LiveData的观察者. 接着调用detachObserver移除包装类和Lifecycle的关联.最后调用activeStateChanged(false)

如果组件没有销毁,则会直接调用activeStateChanged(shouldBeActive())

void activeStateChanged(boolean newActive) {
    //如果状态没改变,什么也不做    
    if (newActive == mActive) {
        return;
    }
    // immediately set active state, so we'd never dispatch anything to inactive
    // owner
    //更新状态
    mActive = newActive;
    //当前LiveData没有任何活跃的观察者时为true
    boolean wasInactive = LiveData.this.mActiveCount == 0;
    LiveData.this.mActiveCount += mActive ? 1 : -1;
    if (wasInactive && mActive) {
        onActive();
    }
    if (LiveData.this.mActiveCount == 0 && !mActive) {
        onInactive();
    }
    if (mActive) {
        dispatchingValue(this);
    }
}

在里面就是判断了一下LiveData里面是否还有活跃的观察者.,从上面的代码看到,只有LiveData里面的活跃观察者从0变成1的时候才会调用onActive,并且只有活跃的观察者变成0的时候才会调用onInactive.最后判断了一个这个观察者是否是活跃的,如果是活跃的会调用dispatchingValue来向这一个观察者发送事件. 

使用setValue来通知观察者更新数据

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    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;
}
private void considerNotify(ObserverWrapper observer) {
    //观察者不是活跃的,什么也不做
    if (!observer.mActive) {
        return;
    }
    ...
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}

在观察者调用onChanged方法之前,仍会有很多的判断.比如检查观察者是不是活跃的.是不是已经通知过了. 我们的LiveData里又一个mVersion.这个mVersion在每次的setValue操作后都会自增. 而我们的ObserverWapper 也会有一个mLastVersion.比较这两个值就可以确定我们的观察者是否已经回调了onChanged.

LiveData还有一个observeForever方法.只需传递一个观察者对象就好.使用这个方法来注册观察者会是LiveData失去生命周期感知能力.我们需要自己在合适的生命周期回调方法中移除观察者

扩展LiveData
我们可以扩展一个LiveData来监听一些服务

class MoneyLiveData : LiveData<BigDecimal>(){
    //金钱的管理类
    private val manager = MoneyManager()
    private val listener = { money: BigDecimal ->
        value = money
    }
    override fun onActive() {
        super.onActive()
        manager.registerListener(listener)
    }
    override fun onInactive() {
        super.onInactive()
        manager.removeListener(listener)
    }
}

这里包含一些重要的方法,onActive() 会在有活跃的观察者时调用, onInactive() 会在没有任何活跃的观察者时调用. setValue(T)会更新LiveData实例的值并将结果告知所有活跃的观察者,可以在Activity的onCreate()方法中使用

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val moneyLiveData: MoneyLiveData = ...
    moneyLiveData.observe(this, Observer<BigDecimal> { money ->
        //更新UI
    })
}

转换LiveData
有时候我们会希望将LiveData对象分派给观察者之前改变里面存储的值,map(),又或者转换成别的LiveData对象,switchMap()

val oldLiveData: LiveData<String> = OldLiveData()
//使用 Transformations 的map() 来在对前一个LiveData的值进行修改
val newLiveData: LiveData<String> = Transformations.map(oldLiveData) {
    oldString -> "newString"
}
newLiveData.observe(this, Observer { Log.d("TAG", it)})

val oldLiveData: LiveData<String> = mutablelivedata<String>()
val newLiveData: LiveData<String> = mutablelivedata<String>()
//使用 Transformations 的switchMap()来对前一个LiveData转换为一个新的LiveData
val liveData = Transformations.switchMap(oldLiveData) { newLiveData}
liveData.observe(this, Observer { Log.d("TAG", it)})

 

我们今天的关于android-从LiveData.observe()向适配器添加项目的最佳实践android recyclerview适配器的分享已经告一段落,感谢您的关注,如果您想了解更多关于android -------- LiveDataBus的使用、Android BaseAdapter DataSetObserver通知机制、Android Data Binding 系列 (二) -- Binding 与 Observer 实现原理、Android jetpack 之 LiveData的相关信息,请在本站查询。

本文标签: