今天在将项目从findViewById转到MVVM的databinding时,发现有的view绑定了数据,但是数据变了,view并不会跟着改变

现场还原

将用户信息的头像uri绑定到ImageView,理论上来说,userInfoAll.UserInfo.avatar发生了改变,就会调用load方法重新设置头像,但是并没有发生

<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable name="userInfoAll" type="com.learning.reading.fragment.word.bean.UserInfoAll" />
    </data>
    ... ...
	<ImageView
		android:id="@+id/iv_myinfo_head"
	    android:layout_width="60dp"
	    android:layout_height="60dp"
	    android:layout_margin="10dp"
	    android:background="@null"
	    app:imgUri="@{userInfoAll.UserInfo.avatar}"/>
    ... ...
    @BindingAdapter("app:imgUri")
    public static void load(ImageView imageView, String uri) {
        if (TextUtils.isEmpty(uri)) return;
        Glide.with(imageView.getContext())
                .load(PICTURE_PATH + uri)
                .placeholder(R.drawable.icon_head)
                .error(R.drawable.icon_head)
                .into(imageView);
    }

原因分析

来看一下UserInfoAll的数据结构。

public class UserInfoAll {

    private static UserInfoAll instance = new UserInfoAll();

    public static synchronized UserInfoAll getInstance() {
        if (instance == null)
            instance = new UserInfoAll();
        return instance;
    }
    
    public static void setData(UserInfoAll userInfoAll) {
        instance.setUser(userInfoAll.user);
        instance.setUserInfo(userInfoAll.userInfo);
    }

    private User user;
    private UserInfo userInfo;

    public UserInfoAll() {
        user = new User();
        userInfo = new UserInfo();
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
        // ... 其余用户信息 ...
    }

    public UserInfo getUserInfo() {
        return userInfo;
    }

    public void setUserInfo(UserInfo userInfo) {
        this.userInfo = userInfo;
        // ... 其余用户信息 ...
    }
    
    // 存储用户关键信息
    public class User {
        private long id;    // 用户id
		// ... 其余用户关键信息 ...
		
        public User() {
            this.id = -1;
            // ... 初始化其余用户信息 ...
        }
        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }
		// 其余用户关键信息...getter...setter...方法
    }

	// 存储用户附属信息
    public class UserInfo extends BaseObservable{
        private String avatar; // 用户头像的url地址
        // ... 其余用户信息 ...

        public UserInfo() {
            this.updateTime = "";
			// ... 设置其余用户附属信息 ...
        }

        @Bindable
        public String getAvatar() {
            return avatar;
        }

        public void setAvatar(String avatar) {
            this.avatar = avatar;
            notifyPropertyChanged(BR.avatar);
        }
		// 其余用户附属信息...getter...setter...方法
    }

UserInfoAll主要包含两个类,User.class 存储用户的关键信息,用户id、手机号等;UserInfo.class 存储用户附属信息,头像url、个人说明等。
因为整个APP只需要保存这一份用户信息数据,所以采用单例模式。
UserInfoAll赋值分为两步

  1. 打开APP进行数据绑定时是第一次getInstance,这时new了一个UserInfoAll,调用了默认的构造函数(分别new了一个User和new了一个UserInfo,调用了如代码所示的各自的构造函数)。
  2. 从服务器获取用户信息成功之后,会调用setData方法,重新给UserInfoAll的单例赋值。

看起来好像没有问题,但ImageView的数据确实没有刷新,问题只会出在上面两个步骤。
步骤一不会有问题,看步骤二。
步骤二传进来一个新的UserInfoAll对象,然后分别对单例的User和UserInfo进行赋值,这个赋值其实是将单例的这两个对象的引用,指向了新传进来的UserInfoAll的User和UserInfo,这个过程是没有调用UserInfo.setAvatar(Stirng)方法的

那么我们是不是可以猜测,databinding绑定的数据监听是通过set和get方法实现的(没看源码,猜的,你们有兴趣的自己去研究,搞懂了记得给我讲讲)步骤二对User和UserInfo的赋值实际上没有调用到UserInfo.setAvatar(Stirng)方法,所以监听器没有监听到变化,导致数据没有刷新?

修改代码

public class UserInfoAll {

    private static UserInfoAll instance = new UserInfoAll();

    public static synchronized UserInfoAll getInstance() {
        if (instance == null)
            instance = new UserInfoAll();
        return instance;
    }
    
    public static void setData(UserInfoAll userInfoAll) {
        instance.setUser(userInfoAll.user);
        instance.setUserInfo(userInfoAll.userInfo);
    }

    private User user;
    private UserInfo userInfo;
    private String token;

    public UserInfoAll() {
        user = new User();
        userInfo = new UserInfo();
        token = "";
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user.setId(user.id);
        // ... 其余用户信息 ...
    }

    public UserInfo getUserInfo() {
        return userInfo;
    }

    public void setUserInfo(UserInfo userInfo) {
        this.userInfo.setAvatar(userInfo.avatar);
        // ... 其余用户信息 ...
    }
    
    // 存储用户关键信息
    public class User {
        private long id;    // 用户id
		// ... 其余用户关键信息 ...
		
        public User() {
            this.id = -1;
            // ... 初始化其余用户信息 ...
        }
        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }
		// 其余用户关键信息...getter...setter...方法
    }

	// 存储用户附属信息
    public class UserInfo extends BaseObservable{
        private String avatar; // 用户头像的url地址
        // ... 其余用户信息 ...

        public UserInfo() {
            this.updateTime = "";
			// ... 设置其余用户附属信息 ...
        }

        @Bindable
        public String getAvatar() {
            return avatar;
        }

        public void setAvatar(String avatar) {
            this.avatar = avatar;
            notifyPropertyChanged(BR.avatar);
        }
		// 其余用户附属信息...getter...setter...方法
    }

再试一下果然好了

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐