目前框架支援的屬性回撥有3種
- 1,預設的屬性回撥 含義: 其實就是某個屬性變化了, 通知你的意思
- 2, List屬性回撥 含義: 就是監聽List屬性的 增刪改。
- 3, SparseArray屬性回撥。 含義: 就是監聽SparseArray屬性的 增刪改。
詳解
-
屬性回撥
-
實際場景:
- 在工作中,有的時候我們想監聽某些資料/ui 的變化。以完成統計功能, 以前在專案中遇到過。
比如新聞類的ui, 頂部有很多tab, 下面是資料流列表。 這時候有這樣一個需求:
要求使用者點選了哪個item,屬於哪個tab. 什麼型別, 在列表中的索引, 這個時候我發現,搞統計還是挺麻煩的。
即使最後我設計了一套通用的框架, 還是感覺不完美。 - 所以後面我想到了資料中介者data-mediator這個框架. 後面會支援這些更加複雜的功能。
- 在工作中,有的時候我們想監聽某些資料/ui 的變化。以完成統計功能, 以前在專案中遇到過。
-
屬性回撥,不一定非要繫結到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支援下專案哈。