Android DataBinding 的进阶用法
来源:互联网 发布:淘宝oppo手机 编辑:程序博客网 时间:2024/05/21 01:58
一、前言
上一篇文章中我们讲解了关于 Android DataBinding的基本用法,但是只是讲到关于数据的绑定的使用,对于监听器的使用等都还没有讲解,例如 Button 的 onClick()、onLongClick() 等事件用 DataBinding 改怎么用呢?还有在 Fragment 中怎么使用,用到 ListView 该怎么用等等,那么这一篇就讲解下 Databinding 的进阶使用。
二、导入类
在 data 标签里是可以用 import 的,就是说用了 import 的类在写 variable 的时候 type 就不要写全包名,写个类名就好了,这和在 Java 里使用是一样的,lang 包里的也是不用 import 的,例如 用 User 类的时候,本来是这样的:
<variable name="user" type="com.ce.listener.bean.User" />
如果用 import 就可以这样写:
<import type="com.ce.listener.bean.User" /> <variable name="user" type="User" />
那如果两个重名类怎么办,这就要用到 alias 属性了,别名嘛。
<import type="com.ce.advanced.bean.User" alias="User1"/> <variable name="user" type="User1" />
二、绑定监听器
(一)给 Button 添加 onClick 事件
上一篇文章我们还有个 Login 的 Button 还没用到,现在我们给这个 Button 添加个 onClick 事件,添加 onClick 有两种方式,一种是直接调用方法的,另一种是绑定监听器的。
1.直接调用方法
就像以前在 onClick 里写个方法名,然后在 Activity 里实现那个方法一样,比如 onClick=”onLogin”,在 Activity 里就得实现 public void onLogin(View pView){},在这里也是差不多的,对于 onLongClick 等也是适用的,但要注意返回值要对应,比如 onLongClick 的返回值是 boolean 类型的,我们写的方法的返回值就得是 boolean 类型,我们新建个 EventHandlers 类:
import android.view.View;import android.widget.Toast;public class EventHandlers { public void onLogin(View pView) { Toast.makeText(pView.getContext(), "on Login Click", Toast.LENGTH_SHORT).show(); }}
这EventHandlers里面有个 onLogin 方法,如果调用了 onLogin 方法就弹个 Toast, 在 layout 中我们可以这样用:
在 data 里标签里定义个 EventHandlers 类变量
<variable name="event" type="com.ce.advanced.event.EventHandlers" />
给 Button 设置上 onClick,@{变量名::方法}
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:onClick="@{event::onLogin}" android:text="Login" />
在 Activity 中设置 EventHandlers 进去
EventHandlers _Event = new EventHandlers();_ViewDataBinding.setEvent(_Event);
2.绑定监听器
我们现在是要做 login 操作,但上面的方法没有办法获取到 EditText 中的数据,那怎么办,怎么才能把 User 类也传进方法中呢?那就得用到绑定监听器的方法了,新建个Presenter类。
public class Presenter { public void onLogin(User pUser) { Log.v("Presenter", "UserName = " + pUser.getUserName() + ", Password = " + pUser.getPassword()); }}
在 data 标签里定义一个 Presenter 类变量
<variable name="presenter" type="com.ce.advanced.event.Presenter" />
给 Button 设置上 onClick,@{()->变量名.方法名(参数)}。
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:onClick="@{() -> presenter.onLogin(user)}" android:text="Login" />
在 Activity 中设置
_ViewDataBinding.setPresenter(new Presenter());
那我如果要用到当前 View,如何把当前 View 也传进去呢?这也简单,在 Presenter 类中添加一个 onLogin 重载方法。
public void onLogin(View pView, User pUser) { Toast.makeText(pView.getContext(), pUser.getUserName() + " " +ss pUser.getPassword(), Toast.LENGTH_SHORT).show(); }
在给 Button 设置 onClick 的时候就要给前面的括号一个参数,@{(当前 View 变量的名称) -> 变量名.方法名(当前 View 变量的名称, 参数)}。
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:onClick="@{(pView) -> presenter.onLogin(pView, user)}" android:text="Login" />
参数可以是0个至多个的,layout 中传入的参数要和方法的参数要对应,当然方法的返回值也要和事件的返回值要对应,比如:
public void onLogin() { Log.v("Presenter", "onLogin");}
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:onClick="@{() -> presenter.onLogin()}" android:text="Login" />
如果我想要监听 EditText 的输入变化呢,这也是可以的,我们知道在 Java 代码中是用到 addTextChangedListener 这个方法,参数是 TextWatcher 接口。
public void addTextChangedListener(TextWatcher watcher) { if (mListeners == null) { mListeners = new ArrayList<TextWatcher>(); } mListeners.add(watcher);}
在 Presenter 中写个内部类实现 TextWatcher:
public final TextWatcher OnUserNameChange = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { Log.v("Presenter", "beforeTextChanged = " + s); } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { Log.v("Presenter", "onTextChanged = " + s); } @Override public void afterTextChanged(Editable s) { Log.v("Presenter", "afterTextChanged = " + s); } };
在 Layout 中可以这样使用
<EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="User name" android:addTextChangedListener="@{presenter.OnUserNameChange}" android:text="@{user.userName}" />
好了,其他监听器该怎么用如果用到的话再慢慢摸索吧,也是差不多的。
三、双向绑定
不知道大伙儿有没有发现现在在 EditText 里改变文字后,点 Login 按钮会发现还是之前设置的 Text 。
那怎么办,我们现在要对 User 类改造一番,让 User 类继承 BaseObservable 这个类,BaseObservable 类有个 notifyPropertyChanged 方法
/** * Notifies listeners that a specific property has changed. The getter for the property * that changes should be marked with {@link Bindable} to generate a field in * <code>BR</code> to be used as <code>fieldId</code>. * * @param fieldId The generated BR id for the Bindable field. */ public void notifyPropertyChanged(int fieldId) { if (mCallbacks != null) { mCallbacks.notifyCallbacks(this, fieldId, null); } }
看这个方法的注释就知道它会通知 listeners 属性已经改变了,有个条件是 getter 是要用到 Bindable 注解的,传入的参数是用 BR 这个类获取 fieldId,这里是要先对 getter 用 Bindable 注解,如果 BR 类没有那个 fieldId 的话就点 Build -> Rebuild Project 就有了,然后在 setter 调用 notifyPropertyChanged,把 BR 类生成的 fieldId 传进去,对 User 类改造如下。
public class User extends BaseObservable { private String userName; private String password; public User() { } public User(String userName, String password) { this.userName = userName; this.password = password; } @Bindable public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; notifyPropertyChanged(BR.userName); } @Bindable public String getPassword() { return password; } public void setPassword(String password) { this.password = password; notifyPropertyChanged(BR.password); }}
在 Layout 使用的时候呢就多了个 = ,
<LinearLayout xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.ce.advanced.activity.MainActivity"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="User name" android:addTextChangedListener="@{presenter.OnUserNameChange}" android:text="@={user.userName}" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Password" android:text="@={user.password}" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:onClick="@{(pView) -> presenter.onLogin(pView, user)}" android:text="Login" /></LinearLayout>
我的 bean 类已经是有父类的了,不能再继承 BaseObservable,还有你这样做也好麻烦,有没有简单点的?当然有,Google 给我们提供了一系列 ObservableFields。
有对应的类型就用对应的,如果没有的话就用 ObservableField 这个类,其实这些大部分也是继承 BaseObservable 的,我们可以看下继承自 BaseObservable 的子类有哪些
再新建个 User2 类,
public class User2 { public final ObservableField<String> userName = new ObservableField<>(); public final ObservableField<String> password = new ObservableField<>(); public User2() { } public User2(String userName, String password) { this.userName.set(userName); this.password.set(password); }}
不是吧?就这么简单?是的,就这么简单,我们在 Presenter 里增加个 User2 类型的参数的 onLogin 方法,
public void onLogin(View pView, User2 pUser) { Toast.makeText(pView.getContext(), "User2 " + pUser.userName.get() + " " + pUser.password.get(), Toast.LENGTH_SHORT).show();}
在 Layout 中使用是完全一样的,在 data 标签里再定义一个 User2 类变量
<variable name="user2" type="com.ce.advanced.bean.User2" />
<LinearLayout xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.ce.advanced.activity.MainActivity"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="User name" android:addTextChangedListener="@{presenter.OnUserNameChange}" android:text="@={user2.userName}" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Password" android:text="@={user2.password}" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:onClick="@{(pView) -> presenter.onLogin(pView, user2)}" android:text="Login" /> </LinearLayout>
在 Activity 中把 User2 设置进去,
_ViewDataBinding.setUser2(new User2("CE", "123456"));
四、在 Fragment 中使用
在 Fragment 中使用也简单,新建个 fragment_user 布局,
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> </data> <android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.ce.advanced.activity.UserActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" app:title="@string/users_fragment"/> </android.support.design.widget.AppBarLayout> <RelativeLayout android:id="@+id/content_test" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/users_fragment"/> </RelativeLayout> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" app:srcCompat="@drawable/ic_add_white_24dp" /> </android.support.design.widget.CoordinatorLayout></layout>
接着再新建个 UsersFragment 类,
private FragmentUsersBinding mUsersBinding;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setHasOptionsMenu(true); // Inflate the layout for this fragment mUsersBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_user, container, false); return mUsersBinding.getRoot(); }
在 onCreateView 里用 DataBindingUtil 的 inflate,里面也是用的是 LayoutInflater 去 inflate的,FragmentUsersBinding.getRoot() 返回的就是 LayoutInflater 的 inflate 返回的 View,看一下源码吧:
DataBindingUtil.java
public static <T extends ViewDataBinding> T inflate(LayoutInflater inflater, int layoutId, @Nullable ViewGroup parent, boolean attachToParent) { return inflate(inflater, layoutId, parent, attachToParent, sDefaultComponent);}public static <T extends ViewDataBinding> T inflate( LayoutInflater inflater, int layoutId, @Nullable ViewGroup parent, boolean attachToParent, DataBindingComponent bindingComponent) { final boolean useChildren = parent != null && attachToParent; final int startChildren = useChildren ? parent.getChildCount() : 0; final View view = inflater.inflate(layoutId, parent, attachToParent); if (useChildren) { return bindToAddedViews(bindingComponent, parent, startChildren, layoutId); } else { return bind(bindingComponent, view, layoutId); }}
attachToParent 是 false,所以 useChildren 是 false 走的下边的 bind 方法。
static <T extends ViewDataBinding> T bind(DataBindingComponent bindingComponent, View root, int layoutId) { return (T) sMapper.getDataBinder(bindingComponent, root, layoutId);}
接下来进入 DataBinderMapper 的 getDataBinder 方法中。
DataBinderMapper.java
public android.databinding.ViewDataBinding getDataBinder(android.databinding.DataBindingComponent bindingComponent, android.view.View view, int layoutId) { switch(layoutId) { case com.ce.advanced.R.layout.activity_main: return com.ce.advanced.databinding.ActivityMainBinding.bind(view, bindingComponent); case com.ce.advanced.R.layout.activity_user: return com.ce.advanced.databinding.ActivityUserBinding.bind(view, bindingComponent); case com.ce.advanced.R.layout.fragment_user: return com.ce.advanced.databinding.FragmentUserBinding.bind(view, bindingComponent); } return null; }
这里我们传进去的是 fragment_user,所以进入到 FragmentUserBinding.bind 方法中。
FragmentUserBinding.java
public static FragmentUserBinding bind(android.view.View view, android.databinding.DataBindingComponent bindingComponent) { if (!"layout/fragment_user_0".equals(view.getTag())) { throw new RuntimeException("view tag isn't correct on view:" + view.getTag()); } return new FragmentUserBinding(bindingComponent, view);}public FragmentUserBinding(android.databinding.DataBindingComponent bindingComponent, View root) { super(bindingComponent, root, 0); final Object[] bindings = mapBindings(bindingComponent, root, 3, sIncludes, sViewsWithIds); this.fab = (android.support.design.widget.FloatingActionButton) bindings[2]; this.mboundView0 = (android.support.design.widget.CoordinatorLayout) bindings[0]; this.mboundView0.setTag(null); this.toolbar = (android.support.v7.widget.Toolbar) bindings[1]; setRootTag(root); // listeners invalidateAll();}
FragmentUserBinding 的 bind 方法里 new 了个 FragmentUserBinding 对象返回,所以我们在 onCreateView 用 FragmentUsersBinding 去接收,我们在看看 FragmentUsersBinding 的父类 ViewDataBinding 的构造方法。
ViewDataBinding.java
protected ViewDataBinding(DataBindingComponent bindingComponent, View root, int localFieldCount) { this.mBindingComponent = bindingComponent; this.mLocalFieldObservers = new ViewDataBinding.WeakListener[localFieldCount]; this.mRoot = root; if(Looper.myLooper() == null) { throw new IllegalStateException("DataBinding must be created in view\'s UI Thread"); } else { if(USE_CHOREOGRAPHER) { this.mChoreographer = Choreographer.getInstance(); this.mFrameCallback = new FrameCallback() { public void doFrame(long frameTimeNanos) { ViewDataBinding.this.mRebindRunnable.run(); } }; } else { this.mFrameCallback = null; this.mUIThreadHandler = new Handler(Looper.myLooper()); } }}
可以看到 root 是赋给 mRoot 的,好了,源码暂时分析到这里。
再新建个 UserActivity 类继承自 AppCompatActivity,把 UsersFragment 加载进去:
public class UserActivity extends AppCompatActivity implements UsersFragment.OnFragmentInteractionListener{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DataBindingUtil.setContentView(this, R.layout.activity_user); getSupportFragmentManager() .beginTransaction() .replace(R.id.content_user, UsersFragment.newInstance(null, null)) .commitAllowingStateLoss(); } @Override public void onFragmentInteraction(Uri uri) { }}
布局 activity_user:
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <data> </data> <FrameLayout android:id="@+id/content_user" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.ce.advanced.activity.UserActivity"> </FrameLayout></layout>
修改下 Presenter 的 onLogin 的逻辑,点击了 Login 按钮后就跳转到 UserActivity,
public void onLogin(View pView, User2 pUser) { if ("CE".equals(pUser.userName.get()) && "123456".equals(pUser.password.get())) { onSuccess(pView.getContext()); } else { onFail(pView.getContext()); }}private void onSuccess(Context pContext) { Toast.makeText(pContext, "Success", Toast.LENGTH_SHORT).show(); Intent _Intent = new Intent(pContext, UserActivity.class); pContext.startActivity(_Intent);}private void onFail(Context pContext) { Toast.makeText(pContext, "Fail", Toast.LENGTH_SHORT).show();}
这里跳转后没有 finish 掉当前 Activity,如果要做的话就添加个回调去 finish。
五、设置 Toolbar
现在的应用很多都有用到 Toolbar 的,这里也用一下,我们在 UsersFragment 中覆盖 onActivityCreated 方法,我们的 Activity 是继承自 AppCompatActivity 的,所以直接强转为 AppCompatActivity:
@Overridepublic void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ((AppCompatActivity)getActivity()).setSupportActionBar(mUsersBinding.toolbar);}
在继承自 AppCompatActivity 的 Activity 中就直接用 setSupportActionBar(当前Activity的 ViewDataBinding.toolbar的id)。
六、基于 BaseAdapter 的使用
看到 Login 后是不是有点失望,没什么好看的,来个列表 (ListView) 吧,在这里说下 ListView 怎么用 Adapter的,以及 Adapter 里要怎么处理 item 的布局,新建个 item 的布局 list_item.xml:
<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="user" type="com.ce.advanced.bean.User2" /> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="38dp" android:gravity="center" android:text="@{user.userName}"/> </LinearLayout></layout>
这里用的是 User2 类,然后把 userName 设置到 TextView 里
接着再来个 Adapter 继承自 BaseAdapter 的:
public class UserAdapter extends BaseAdapter { private Context mContext; private List<User2> mData; public UserAdapter(Context pContext, List<User2> pData) { this.mContext = pContext; this.mData = pData != null ? pData : new ArrayList<User2>(); } @Override public int getCount() { return mData.size(); } @Override public User2 getItem(int position) { return mData.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { int _LayoutId = R.layout.list_item; ViewHolder _Holder= ViewHolder.getViewHolder(mContext, _LayoutId, convertView, parent); _Holder.mItemBinding.setUser(mData.get(position)); return _Holder.mConvertView; } public void addItem(int pPostion, User2 pUser) { this.mData.add(pPostion, pUser); notifyDataSetChanged(); } private static class ViewHolder{ ListItemBinding mItemBinding; View mConvertView; private ViewHolder(Context pContext, ViewGroup parent, int pLayoutId) { mItemBinding = DataBindingUtil.inflate(LayoutInflater.from(pContext), pLayoutId, parent, false); this.mConvertView = mItemBinding.getRoot(); this.mConvertView.setTag(this); } static ViewHolder getViewHolder(Context pContext, int pLayoutId, View convertView, ViewGroup parent) { if (convertView == null) { return new ViewHolder(pContext, parent, pLayoutId); } return (ViewHolder) convertView.getTag(); } }}
其实和以前的写法也是差不多的,不过加载的时候用的是 DataBindingUtil 去加载的,然后设置数据也方便了。
在 fragment_user 布局的 data 里添加个 Adapter 变量:
<data> <import type="com.ce.advanced.adapter.UserAdapter" /> <variable name="adapter" type="UserAdapter" /> </data>
把 fragment_user 布局中的 TextView 换成 ListView,把 定义的 adapter 变量设置进 ListView 的属性里。
<ListView android:layout_width="match_parent" android:layout_height="match_parent" android:adapter="@{adapter}"></ListView>
覆盖 UsersFragment 类的 onViewCreated 方法把 UserAdapter 对象设置进去,就完成了,用了 DataBinding 是不是觉得简单吧。
@Overridepublic void onViewCreated(View view, @Nullable Bundle savedInstanceState) { mUserAdapter = new UserAdapter(getContext(), getData()); mUsersBinding.setAdapter(mUserAdapter);}private List<User2> getData() { List<User2> _Users = new ArrayList<>(); _Users.add(new User2("Java", "1")); _Users.add(new User2("C", "2")); _Users.add(new User2("C++", "3")); _Users.add(new User2("Python", "4")); _Users.add(new User2("C#", "5")); _Users.add(new User2(".NET", "6")); _Users.add(new User2("JavaScript", "7")); _Users.add(new User2("Assembly", "8")); _Users.add(new User2("PHP", "9")); _Users.add(new User2("Perl", "10")); _Users.add(new User2("Ruby", "11")); _Users.add(new User2("VB", "12")); _Users.add(new User2("Swift", "13")); _Users.add(new User2("R", "14")); _Users.add(new User2("Objective-C", "15")); return _Users;}
想要对 item 进行增加、删除等操作要怎么做?有没有注意到还有个 FloatingActionButton 没用到?还有 UserAdapter 里是有个 addItem 方法的也没用,那就来个增加 item 的吧,再写个 UserFragmentPresenter 类:
public class UserFragmentPresenter { public interface OnUserAddListener { void onUserAdd(); } private OnUserAddListener mOnUserAddListener; public void onUserAdd() { if (mOnUserAddListener != null) { mOnUserAddListener.onUserAdd(); } } public void setOnUserAddListener(OnUserAddListener pOnUserAddListener) { this.mOnUserAddListener = pOnUserAddListener; }}
onUserAdd 方法是给 FloatingActionButton 的 onClick 调用的方法,因为 Adapter 在 UsersFragment,所以我们要写个 OnUserAddListener 接口让 UsersFragment 实现,点击 FloatingActionButton 的时候进行回调。
在 fragment_user 布局的 data 里再添加个变量:
<variable name="presenter" type="com.ce.advanced.event.UserFragmentPresenter" />
给 FloatingActionButton 设置 onClick:
<android.support.design.widget.FloatingActionButton android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin" android:onClick="@{() -> presenter.onUserAdd()}" app:srcCompat="@drawable/ic_add_white_24dp" />
在 UsersFragment 的 onViewCreated 方法里设置
@Overridepublic void onViewCreated(View view, @Nullable Bundle savedInstanceState) { mUserAdapter = new UserAdapter(getContext(), getData(), R.layout.list_item); mUsersBinding.setAdapter(mUserAdapter); UserFragmentPresenter _Presenter = new UserFragmentPresenter(); _Presenter.setOnUserAddListener(this); mUsersBinding.setPresenter(_Presenter);}
让 UsersFragment 实现 UserFragmentPresenter.OnUserAddListener 接口,覆盖 onUserAdd 方法,
@Overridepublic void onUserAdd() { List<User2> _Users = getData(); mUserAdapter.addItem(0, _Users.get(new Random().nextInt(_Users.size())));}
这里就用 UserAdapter 的 addItem 方法随机添加点数据进去。
七、基于RecyclerView.Adapter 的使用
什么?现在 ListView 已经 out 了?都流行用 RecyclerView 了,还在用 ListView。
好了,说下在 RecyclerView 怎么用吧,先来个 Adapter:
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.MyViewHolder> { private Context mContext; private List<User2> mData; public UserAdapter(Context pContext, List<User2> pData) { this.mContext = pContext; this.mData = pData != null ? pData : new ArrayList<User2>(); } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { int _LayoutId = R.layout.list_item; return MyViewHolder.getViewHolder(mContext, _LayoutId, parent); } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.mItemBinding.setUser(mData.get(position)); } @Override public int getItemCount() { return mData.size(); } public void addItem(int pPostion, User2 pUser) { mData.add(pPostion, pUser); notifyItemInserted(pPostion); } static class MyViewHolder extends RecyclerView.ViewHolder { private ListItemBinding mItemBinding; private MyViewHolder(ListItemBinding pItemBinding) { super(pItemBinding.getRoot()); this.mItemBinding = pItemBinding; } static MyViewHolder getViewHolder(Context pContext, int pLayoutId, ViewGroup parent) { ListItemBinding _ItemBinding = DataBindingUtil.inflate(LayoutInflater.from(pContext), pLayoutId, parent, false); return new MyViewHolder(_ItemBinding); } }}
其实这里也没什么好说的了,在 fragment_user 布局中的 data 里添加两个变量
<variable name="adapter2" type="com.ce.advanced.recycler.UserAdapter" /><variable name="layoutManager" type="android.support.v7.widget.RecyclerView.LayoutManager" />
一个是 Adapter,一个是 LayoutManager,把 ListView 改成 RecyclerView 并将 Adapter 和 LayoutManager 设置进去:
<android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="match_parent" android:layoutManager="@{layoutManager}" android:adapter="@{adapter2}"></android.support.v7.widget.RecyclerView>
把 UsersFragment 的 onViewCreated 的 UserAdapter 换成 RecyclerView 的 Adapter,并设置 LayoutManager,这里用的是 LinearLayoutManager:
@Overridepublic void onViewCreated(View view, @Nullable Bundle savedInstanceState) { mUserAdapter = new UserAdapter(getContext(), getData()); mUsersBinding.setLayoutManager(new LinearLayoutManager(getContext())); mUsersBinding.setAdapter2(mUserAdapter); UserFragmentPresenter _Presenter = new UserFragmentPresenter(); _Presenter.setOnUserAddListener(this); mUsersBinding.setPresenter(_Presenter);}
八、后记
其实还有一些还没讲到,但时间安排不来写那么多,像转换器、在布局中使用表达式等,大伙儿用到再去研究,或者以后有空再写一篇。
源码地址
- Android DataBinding 的进阶用法
- Android DataBinding的基本用法
- Android进阶六:Databinding的双向绑定
- Android进阶---android databinding 使用
- Android进阶四:Databinding的使用(基础篇)
- Android DataBinding 基础用法一
- Android DataBinding 基础用法二
- Android DataBinding (一) 基本用法
- Android之MVVM开发模式和DataBinding的简单用法
- Android里的DataBinding
- DataBinding系列(二):DataBinding的基本用法
- DataBinding用法
- Android数据绑定框架DataBinding用法
- Android数据绑定框架DataBinding用法
- Android的DataBinding原理介绍
- android DataBinding 的简单使用
- DataBinding的用法(简洁易懂)
- databinding使用进阶
- VR实训项目场景搭建阶段性报告
- typedef用法
- Android爱读app开发记录之四---实现排行榜界面
- 找到一本不错的Linux电子书,附《Linux就该这么学》章节目录。
- 1e11以内小于等于这个数的素数的个数
- Android DataBinding 的进阶用法
- H.264的基本概念
- webapi做为后端接口时在跨域调用时的注意点
- Leetcode051--判断回文数(忽律大小写和非字符)
- Ajax要点及实例
- Eclipse 设置问题
- 监控文件事件inotify
- js作用域
- javascript笔记