【Android】Jetpack全组件实战开发短视频应用App(十四)

前言

项目地址
这一篇主要实现用户的点赞和踩功能
在这里插入图片描述

实现

之前我们一般是在适配器中做点击事件,但是我们使用DataBinding之后,我们就可以直接在xml中实现.我们之前说过xml中是可以写点击事件的,它接受的是一个lambda表达式,表达式里面是一个类点静态方法,如:

            android:onClick="@{()->InterActionPresenter.toggleFeedDiss(lifeCycleOwner,feed)}"

我们就新建一个类InterActionPresenter,里面有我们的点赞和踩对应的方法

public class InterActionPresenter {

    private static final String URL_TOGGLE_FEED_LIK = "/ugc/toggleFeedLike";

    private static final String URL_TOGGLE_FEED_DISS = "/ugc/dissFeed";

    /**
     * 给一个帖子点赞/取消点赞,它和给帖子点踩一踩是互斥的
     */
    public static void toggleFeedLike(LifecycleOwner owner, Feed feed) {

        if (!UserManager.get().isLogin()) {
            LiveData<User> loginLiveData = UserManager.get().login(AppGlobals.getApplication());
            loginLiveData.observe(owner, new Observer<User>() {
                @Override
                public void onChanged(User user) {
                    if (user != null) {
                        toggleFeedLikeInternal(feed);
                    }
                    loginLiveData.removeObserver(this);
                }
            });
            return;
        }
        toggleFeedLikeInternal(feed);
    }

    private static void toggleFeedLikeInternal(Feed feed) {
        ApiService.get(URL_TOGGLE_FEED_LIK)
                .addParam("userId", UserManager.get().getUserId())
                .addParam("itemId", feed.itemId)
                .execute(new JsonCallback<JSONObject>() {
                    @Override
                    public void onSuccess(ApiResponse<JSONObject> response) {
                        if (response.body != null) {
                            boolean hasLiked = response.body.getBoolean("hasLiked").booleanValue();
                            feed.getUgc().setHasLiked(hasLiked);
                        }
                    }

                    @Override
                    public void onError(ApiResponse<JSONObject> response) {
                        showToast(response.message);
                    }
                });
    }

    /**
     * 给一个帖子点踩一踩/取消踩一踩,它和给帖子点赞是互斥的
     */
    public static void toggleFeedDiss(LifecycleOwner owner, Feed feed) {
        if (!UserManager.get().isLogin()) {
            LiveData<User> loginLiveData = UserManager.get().login(AppGlobals.getApplication());
            loginLiveData.observe(owner, new Observer<User>() {
                @Override
                public void onChanged(User user) {
                    if (user != null) {
                        toggleFeedDissInternal(feed);
                    }
                    loginLiveData.removeObserver(this);
                }
            });
            return;
        }
        toggleFeedDissInternal(feed);
    }

    private static void toggleFeedDissInternal(Feed feed) {
        ApiService.get(URL_TOGGLE_FEED_DISS).addParam("userId", UserManager.get().getUserId())
                .addParam("itemId", feed.itemId)
                .execute(new JsonCallback<JSONObject>() {
                    @Override
                    public void onSuccess(ApiResponse<JSONObject> response) {
                        if (response.body != null) {
                            boolean hasLiked = response.body.getBoolean("hasLiked").booleanValue();
                            feed.getUgc().setHasdiss(hasLiked);
                        }
                    }

                    @Override
                    public void onError(ApiResponse<JSONObject> response) {
                        showToast(response.message);
                    }
                });
    }

    private static void showToast(String message) {
        ArchTaskExecutor.getMainThreadExecutor().execute(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(AppGlobals.getApplication(), message, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

简单解释下,不管是点赞还是踩,我们都需要用户登录,我们判断用户等没登录用的UserManager这个类,这个类我们上一篇在QQ登录的时候用过,如果用户没有登录,我们就需要跳转到我们的登录页

当我们请求完成回来之后,我们需要将我们的按钮文本进行改变,这时候我们就需要改变Feed对象里面的Ugc对象相应的属性,这个时候就需要我们的Ugc对象继承自BaseObservable,我们改变的是
在这里插入图片描述
这两个属性,所以我们需要添加他们的get/set方法,同时在get方法上面加上@Bindable注解,在set方法中调用notifyPropertyChanged这个方法

 @Bindable
    public boolean isHasLiked() {
        return hasLiked;
    }

    public void setHasLiked(boolean hasLiked) {
        if (this.hasLiked == hasLiked)
            return;
        if (hasLiked) {
            likeCount = likeCount + 1;
            setHasdiss(false);
        } else {
            likeCount = likeCount - 1;
        }
        this.hasLiked = hasLiked;
        notifyPropertyChanged(BR._all);
    }

    @Bindable
    public boolean isHasdiss() {
        return hasdiss;
    }

    public void setHasdiss(boolean hasdiss) {
        if (this.hasdiss == hasdiss)
            return;
        if (hasdiss) {
            setHasLiked(false);
        }
        this.hasdiss = hasdiss;
        notifyPropertyChanged(BR._all);
    }

这个notifyPropertyChanged方法我们需要传一个fieldid,我们可以通过BR来点出来
【Android】Jetpack全组件实战开发短视频应用App(十四)_第1张图片
这些字段都是哪来的呢?就是我们在xml中声明的变量,类似这种
【Android】Jetpack全组件实战开发短视频应用App(十四)_第2张图片
我们没声明一个variable,databinding编译的时候都会生成一个引用,因为我们要改变的ugc是在Feed中,我们可以用BR.feed也可以用BR._all,这个notifyPropertyChanged就是告诉观察者,我这里有属性改变了,需要重新执行数据绑定,我们简单看下怎么回事,我们以LayoutFeedAuthorBindingImpl这个类为例,这个类是自动生成的
它里面有个setuser方法
【Android】Jetpack全组件实战开发短视频应用App(十四)_第3张图片
这里面就会执行notifyPropertyChanged方法,最后会调用requestRebind这个方法,我们继续往下看,最终会执行

    @Override
    protected void executeBindings() {
        long dirtyFlags = 0;
        synchronized(this) {
            dirtyFlags = mDirtyFlags;
            mDirtyFlags = 0;
        }
        java.lang.String userName = null;
        java.lang.String userAvatar = null;
        com.mooc.ppjoke.model.User user = mUser;

        if ((dirtyFlags & 0x3L) != 0) {



                if (user != null) {
                    // read user.name
                    userName = user.name;
                    // read user.avatar
                    userAvatar = user.avatar;
                }
        }
        // batch finished
        if ((dirtyFlags & 0x3L) != 0) {
            // api target 1

            androidx.databinding.adapters.TextViewBindingAdapter.setText(this.authorName, userName);
            com.mooc.libcommon.view.PPImageView.setImageUrl(this.avatar, userAvatar, true, (int)0);
        }
    }

这里我们看见有setTextsetImageUrl方法,setImageUrl我们知道,这个是我们自己写的方法,我们点进去setText,

   @BindingAdapter("android:text")
    public static void setText(TextView view, CharSequence text) {
        final CharSequence oldText = view.getText();
        if (text == oldText || (text == null && oldText.length() == 0)) {
            return;
        }
        if (text instanceof Spanned) {
            if (text.equals(oldText)) {
                return; // No change in the spans, so don't set anything.
            }
        } else if (!haveContentsChanged(text, oldText)) {
            return; // No content changes, so don't set anything.
        }
        view.setText(text);
    }

这个个静态方法,同时会判断是否改变,改变之后重新调用TextViewsetText方法进行赋值

OK,我们简单分析完之后,回到我们的xml中,我们写下点击事件


        <com.google.android.material.button.MaterialButton
            android:id="@+id/like"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:onClick="@{()->InterActionPresenter.toggleFeedLike(lifeCycleOwner,feed)}"
            android:text="@{feed.ugc.likeCount>0?StringConvert.convertFeedUgc(feed.ugc.likeCount):@string/like}"
            android:textColor="@{feed.ugc.hasLiked?@color/color_theme:@color/color_3d3}"
            android:textSize="@dimen/sp_14"
            app:backgroundTint="@color/color_white"
            app:cornerRadius="0dp"
            app:icon="@{feed.ugc.hasLiked?@drawable/icon_cell_liked:@drawable/icon_cell_like}"
            app:iconGravity="textStart"
            app:iconPadding="4dp"
            app:iconTint="@{feed.ugc.hasLiked?@color/color_theme:@color/color_3d3}"
            tools:icon="@drawable/icon_cell_like"
            tools:iconTint="@color/color_3d3"
            tools:text="1000"
            tools:textColor="@color/color_3d3" />


        <com.google.android.material.button.MaterialButton
            android:id="@+id/diss"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:onClick="@{()->InterActionPresenter.toggleFeedDiss(lifeCycleOwner,feed)}"
            android:text=""
            android:textColor="@{feed.ugc.hasdiss?@color/color_theme:@color/color_3d3}"
            android:textSize="@dimen/sp_14"
            app:backgroundTint="@color/color_white"
            app:cornerRadius="0dp"
            app:icon="@{feed.ugc.hasdiss?@drawable/icon_cell_dissed:@drawable/icon_cell_diss}"
            app:iconGravity="textStart"
            app:iconPadding="4dp"
            app:iconTint="@{feed.ugc.hasdiss?@color/color_theme:@color/color_3d3}"
            tools:icon="@drawable/icon_cell_diss"
            tools:iconTint="@color/color_3d3"
            tools:text="1000"
            tools:textColor="@color/color_3d3" />

这里的lifeCycleOwnerfeed一样,我们在上面声明的

     <variable
            name="feed"
            type="com.mooc.ppjoke.model.Feed" />

        <variable
            name="lifeCycleOwner"
            type="androidx.lifecycle.LifecycleOwner" />

        <import type="com.mooc.ppjoke.model.Feed" />

        <import type="com.mooc.ppjoke.utils.StringConvert" />

        <import type="android.content.Context" />

        <import type="com.mooc.ppjoke.ui.home.InterActionPresenter" />

接着我们需要在Adapter中设置
【Android】Jetpack全组件实战开发短视频应用App(十四)_第4张图片

OK,我们看下效果

【Android】Jetpack全组件实战开发短视频应用App(十四)_第5张图片

你可能感兴趣的:(Jetpack)