Data-Mediator专题之属性回调

本文介绍了一个数据中介者框架,支持默认、List及SparseArray三种属性回调。可用于监听UI或数据变化,实现统计功能等。文章提供了示例代码,展示了如何使用属性回调、List属性编辑器及SparseArray属性编辑器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目前框架支持的属性回调有3种

  • 1,默认的属性回调 含义: 其实就是某个属性变化了, 通知你的意思
  • 2, List属性回调 含义: 就是监听List属性的 增删改。
  • 3, SparseArray属性回调。 含义: 就是监听SparseArray属性的 增删改。

详解

  • 属性回调

  • 实际场景:

    • 在工作中,有的时候我们想监听某些数据/ui 的变化。以完成统计功能, 以前在项目中遇到过。
      比如新闻类的ui, 顶部有很多tab, 下面是数据流列表。 这时候有这样一个需求:
      要求用户点击了哪个item,属于哪个tab. 什么类型, 在列表中的索引, 这个时候我发现,搞统计还是挺麻烦的。
      即使最后我设计了一套通用的框架, 还是感觉不完美。
    • 所以后面我想到了数据中介者data-mediator这个框架. 后面会支持这些更加复杂的功能。
  • 属性回调,不一定非要绑定到view的属性上(比如setText, setTextColor, setBackground等等)。 它也可以是事件点击的属性, 后面也会支持。
    换句话说, 以后它可以做很多后台的一些操作。

  • 回归正题, 如何使用属性回调?
    在demo中有这样一个简单的例子。

    public class TestPropertyChangeActivity extends BaseActivity {
   
       @BindView(R.id.tv_desc)
       TextView mTv_desc;
   
       @BindView(R.id.bt_set_text_on_TextView)
       Button mBt_changeProperty;
       @BindView(R.id.bt_set_text_on_mediator)
       Button mBt_temp;
   
       DataMediator<StudentModule> mMediator;
   
       @Override
       protected int getLayoutId() {
           return R.layout.ac_test_double_bind;
       }
   
       @Override
       protected void onInit(Context context, Bundle savedInstanceState) {
           mBt_changeProperty.setText("click this to change property");
           mBt_temp.setVisibility(View.GONE);
   
           //为数据模型创建  中介者。
           mMediator = DataMediatorFactory.createDataMediator(StudentModule.class);
           //添加属性callback
           mMediator.addDataMediatorCallback(new DataMediatorCallback<StudentModule>() {
               @Override
               public void onPropertyValueChanged(StudentModule data, Property prop, Object oldValue, Object newValue) {
                   Logger.w("TestPropertyChangeActivity","onPropertyValueChanged","prop = "
                           + prop.getName() + " ,oldValue = " + oldValue + " ,newValue = " + newValue);
                  //改变文本         
                   mTv_desc.setText(String.valueOf(newValue));
               }
           });
           mMediator.getDataProxy().setName("heaven7");
       }
   
       @OnClick(R.id.bt_set_text_on_TextView)
       public void onClickSetTextOnTextView(View v){
           mMediator.getDataProxy().setName("time: " + System.currentTimeMillis());
       }
   }

复制代码

仅仅,属性改变的时候改变一下文本。很简单吧。

  • List属性编辑器

  • 当一个属性是List类型时,会自动 生成beginXXXEditor的方法返回该编辑器, 它可以方便的操作list数据。 数据模型和代理均有。其中XXX是属性的名称
  • 一般用于绑定列表控件,比如android RecyclerView. 下面是一个demo:
      public class TestRecyclerListBindActivity extends BaseActivity {
    
        private static final Random sRan = new Random();
        
        @BindView(R.id.rv)
        RecyclerView mRv;
        
        private Binder<RecyclerListBindModule> mBinder;
        private TestRecyclerListAdapter<StudentModule> mAdapter;
        
        @Override
        protected int getLayoutId() {
            return R.layout.ac_test_recycler_list_bind;
        }
        
            @Override
            protected void onInit(Context context, Bundle savedInstanceState) {
         //初始化adapter
             initAdapter();
         //创建binder
             mBinder = DataMediatorFactory.createBinder(RecyclerListBindModule.class);
         //绑定列表
             onBindListItems(mBinder);
            }
        
            //添加一个item
            @OnClick(R.id.bt_add)
            public void onClickAddItem(View v){
                mBinder.getDataProxy().beginStudentsEditor()
                        .add(0, createItem());
            }
        
            //添加一组items
            @OnClick(R.id.bt_add_all)
            public void onClickAddItems(View v){
                List<StudentModule> list = createItems();
                mBinder.getDataProxy().beginStudentsEditor()
                        .addAll(list);
            }
        
            //删除一个 item
            @OnClick(R.id.bt_remove)
            public void onClickRemoveItem(View v){
                mBinder.getDataProxy().beginStudentsEditor()
                        .remove(0);
            }
        
            //替换所有items
            @OnClick(R.id.bt_replace)
            public void onClickReplaceItem(View v){
                mBinder.getDataProxy().setStudents(createItems());
            }
        
            protected void onBindListItems(Binder<RecyclerListBindModule> mBinder) {
                //通用的绑定方法. 这里用于绑定列表
                mBinder.bindList(RecyclerListBindModule.PROP_students,
                        mAdapter);
            }
        
            protected void initAdapter() {
                mRv.setLayoutManager(new LinearLayoutManager(this));
                mRv.setAdapter(mAdapter = new TestRecyclerListAdapter<StudentModule>(
                        R.layout.item_test_recycler_list, null) {
                    @Override
                    protected void onBindData(Context context, int position,
                                              StudentModule item, int itemLayoutId, ViewHelper helper) {
                        helper.setText(R.id.tv_name, item.getName())
                                .setText(R.id.tv_age, ""+item.getAge());
                    }
                });
            }
        
            private static StudentModule createItem(){
                StudentModule data = DataMediatorFactory.createData(StudentModule.class);
                data.setAge(sRan.nextInt(10001));
                data.setName("google__" + sRan.nextInt(100));
                return data;
            }
            @NonNull
            private static List<StudentModule> createItems() {
                List<StudentModule> list = new ArrayList<>();
                //just mock data
                final int count = sRan.nextInt(10) + 1;
                for (int i =0 ; i< count ; i++){
                    list.add(createItem());
                }
                return list;
            }
    
        private static abstract class TestRecyclerListAdapter<T extends ISelectable>
             extends QuickRecycleViewAdapter<T> implements
            BaseListPropertyCallback.IItemManager<T> {
    
            public TestRecyclerListAdapter(int layoutId, List<T> mDatas) {
                super(layoutId, mDatas);
            }
    
             @Override
            public void addItems(List<T> items) {
               //增加
                getAdapterManager().addItems(items);
            }
    
            @Override
            public void addItems(int index, List<T> items) {
            //增加
                getAdapterManager().addItems(index, items);
            }
    
            @Override
            public void removeItems(List<T> items) {
            //删除
                getAdapterManager().removeItems(items);
            }
    
            @Override
            public void replaceItems(List<T> items) {
            //替换所有
                getAdapterManager().replaceAllItems(items);
            }
    
            @Override
            public void onItemChanged(int index, T oldItem, T newItem) {
            //改变元素
                getAdapterManager().setItem(index, newItem);
            }
        }
    }
复制代码

复杂么? 不复杂,第一步绑定了列表。然后改变数据的时候回调到了BaseListPropertyCallback.IItemManager

SparseArray属性编辑器

  • 当属性类型是SparseArray时,会自动生成SparseArray属性编辑器: beginXXXEdiator, XXX是属性名称.
  • 下面是一个示例程序:
public class TestSparseArrayActivity extends BaseActivity {

  private static final String TAG = "TestSparseArray";
  @BindView(R.id.tv_sa)
  TextView mTv_sa;

  private DataMediator<TestBindModule> mDm;
  private Set<Integer> mIndexes = new HashSet<>();

  @Override
  protected int getLayoutId() {
      return R.layout.ac_test_sparse_array;
  }

  @Override
  protected void onInit(Context context, Bundle savedInstanceState) {
      mDm = DataMediatorFactory.createDataMediator(TestBindModule.class);
      // 这里直接用属性回调。也可以用binder.bind(String property, SparseArrayPropertyCallback<? super T> callback)方法
      mDm.addDataMediatorCallback(DataMediatorCallback.createForSparse(
              TestBindModule.PROP_cityData2.getName(), new CallbackImpl()));

  }

  // put 操作
  @OnClick(R.id.bt_put)
  public void onClickPut(View v){
      final StudentModule stu = createStu(-1);
      mDm.getDataProxy().beginCityData2Editor()
              .put((int)stu.getId(), stu)
              .end();
  }

  // 移除操作(通过key)
  @OnClick(R.id.bt_remove_key)
  public void onClickRemoveByKey(View v){
      if(!mIndexes.isEmpty()){
          final Integer index = mIndexes.iterator().next();
          mDm.getDataProxy().beginCityData2Editor()
                  .remove(index);
          mIndexes.remove(index);
      }else{
          mTv_sa.setText("");
          Logger.w(TAG , "onClickRemoveByKey", "already empty");
      }
  }

  // 移除操作(通过value)
  @OnClick(R.id.bt_remove_value)
  public void onClickRemoveByValue(View v){
      if(!mIndexes.isEmpty()){
          final Integer index = mIndexes.iterator().next();
          mDm.getDataProxy().beginCityData2Editor()
                  .removeByValue(createStu(index));
          mIndexes.remove(index);
      }else{
          mTv_sa.setText("");
          Logger.w(TAG , "onClickRemoveByValue", "already empty");
      }
  }

  //清空操作
  @OnClick(R.id.bt_clear)
  public void onClickClear(View v){
      if(!mIndexes.isEmpty()){
          mDm.getDataProxy().beginCityData2Editor().clear();
          mIndexes.clear();
      }else{
          mTv_sa.setText("");
          Logger.w(TAG , "onClickClear", "already empty");
      }
  }
  private StudentModule createStu(int index) {
      if(index < 0){
          index = new Random().nextInt(5);
      }
      mIndexes.add(index);
      return DataMediatorFactory.createData(StudentModule.class)
              .setId(index).setName("google_" + index).setAge(index);
  }

  private void setLogText(String method, String msg){
      mTv_sa.setText(method + ": \n  " + msg + "\n\n now is: \n"
              + mDm.getData().getCityData2().toString());
  }

  private class CallbackImpl implements SparseArrayPropertyCallback<TestBindModule>{

      @Override
      public void onEntryValueChanged(TestBindModule data, Property prop, Integer key,
                                      Object oldValue, Object newValue) {
          final String msg = "oldValue = " + oldValue + " ,newValue = " + newValue;
          Logger.i(TAG , "onEntryValueChanged", msg);
          setLogText("onEntryValueChanged", msg);
      }
      @Override //添加key-value
      public void onAddEntry(TestBindModule data, Property prop, Integer key, Object value) {
          final String msg = "key = " + key + " ,value = " + value;
          Logger.i(TAG , "onAddEntry", msg);
          setLogText("onAddEntry", msg);
      }
      @Override //移除key-value
      public void onRemoveEntry(TestBindModule data, Property prop, Integer key, Object value) {
          final String msg = "key = " + key + " ,value = " + value;
          Logger.i(TAG , "onRemoveEntry", msg);
          setLogText("onRemoveEntry", msg);
      }
      @Override //清空
      public void onClearEntries(TestBindModule data, Property prop, Object entries) {
          final String msg = entries.toString(); //here entries is SparseArray
          Logger.i(TAG , "onClearEntries", msg);
          setLogText("onClearEntries", msg);
      }
      @Override //一般的属性改变
      public void onPropertyValueChanged(TestBindModule data, Property prop,
                                         Object oldValue, Object newValue) {
          final String msg = "oldValue = " + oldValue + " ,newValue = " + newValue;
          Logger.i(TAG , "onPropertyValueChanged", msg);
          setLogText("onPropertyValueChanged", msg);
      }
      @Override
      public void onPropertyApplied(TestBindModule data, Property prop, Object value) {
          final String msg = "value = " + value;
          Logger.i(TAG , "onPropertyApplied", msg);
          setLogText("onPropertyApplied", msg);
      }
  }
}

复制代码

想要体验最新的特性 ?

请到github/data-mediator体验。 如果觉得不错,请star支持下项目哈。

欢迎大家star, fork,contribute ,提issue. 它会越来越棒。

Thanks for reading !

技术源于分享!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值