【问题标题】:Is this the right way to have a button that retries an API call on an Android app?这是在 Android 应用程序上重试 API 调用的按钮的正确方法吗?
【发布时间】:2019-04-30 02:43:28
【问题描述】:

我正在处理的项目从中间没有 Room 的 API 获取用户列表(仅网络架构)。我实际上让代码按照我想要的方式工作,但我想知道这是否是正确的方法。下面我将标记出我有疑问的地方。

我的 UI 是一个由 ListAdapter 支持的 RecyclerView。我有一个 ViewModel (mainViewModel),它正在观察 Repository 类提供的用户列表,还有一个布尔值来显示或不显示“再试一次”按钮。

在 MainActivity.java 我有

// Observing the boolean that represents if the api call failed
mainViewModel.getCallFailure().observe(this, new Observer<Boolean>() {
    @Override
    public void onChanged(Boolean aBoolean) {
        if (aBoolean) {
            tryAgainButton.setVisibility(View.VISIBLE);
        } else {
            tryAgainButton.setVisibility(View.GONE);
        }
    }
});

// Setting up onClickListener
tryAgainButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mainViewModel.retryCall(); // HERE IS WHERE I'M HAVING DOUBTS
    }
});

MainViewModel.java 有

public class MainViewModel extends ViewModel {

    ...

    public LiveData<Boolean> getCallFailure(){
        return userRepo.getCallFailure();
    }

    // THIS IS THE METHOD I'M CALLING FROM THE UI
    public void retryCall(){
        userRepo.getRetryCallback();
    }
}

最后,Repository.java 是

public class Repository {
    private Call<UsersResponse> retryCall;
    private Callback<UsersResponse> callback;
    private final MutableLiveData<Boolean> callFailure = new MutableLiveData<>();

    public LiveData<List<UserModel>> getListUsers(){
        final MutableLiveData<List<UserModel>> users = new MutableLiveData<>();
        callFailure.setValue(false);

        (Api.getClient().getUsersList()).enqueue(new Callback<UsersResponse>() {
            @Override
            public void onResponse(Call<UsersResponse> call, Response<UsersResponse> response) {
                users.setValue(response.body().getUsersList());
                callFailure.setValue(false);
            }

            @Override
            public void onFailure(Call<UsersResponse> call, Throwable t) {
                Log.d("Response GET", t.toString());
                callFailure.setValue(true);
                setCallback(this);
                retryCall = call.clone();
            }
        });

        return users;
    }

    private void setCallback(Callback<UsersResponse> usersResponseCallback) {
        callback = usersResponseCallback;
    }

    public LiveData<Boolean> getCallFailure(){
        return callFailure;
    }

    public void getRetryCallback(){
        retryCall.enqueue(callback);
    }
}

我试图只提及我认为相关的代码,我管理 ProgressDialog 的方式与我在存储库中处理布尔值 callFailure 的方式相同,并且它正在创造奇迹。但老实说,在 MainActivity.java 文件中调用 mainViewModel.retryCall(); 感觉有些不对劲,我非常感谢任何建议!

【问题讨论】:

    标签: java android retrofit retrofit2 viewmodel


    【解决方案1】:

    在我使用 MVVM 制作的项目中,我的活动和片段会通知我的 ViewModel,就像您公开(通过调用类似触发器的方法)并通过 LiveData 观察结果。

    对我来说奇怪的一件事是您的存储库存储了一部分状态(重试和失败)。在我的项目中,我将此逻辑放在 ViewModel 中,并且我的存储库在这里执行简单的操作(如网络调用)。但这更多是个人选择。


    编辑:以下是我根据您的代码执行此操作的方法(也许存在更好的方法)。

    基本上,我更喜欢在 ViewModel 中管理 LiveData 对象,而不是在 Repository 中,因为在我看来,Repository 层只是应用程序和数据(在网络中或在数据库中)和状态之间的桥梁UI 的一部分(如重试按钮可见性)必须由 ViewModel 管理。

    Repository.java:

    public class Repository {
        public void getListUsers(Callback<UserResponse> callback) {
            (Api.getClient().getUsersList()).enqueue(callback);
        }
    }
    

    MainViewModel.java:

    public class MainViewModel extends ViewModel {
    
        ...
    
        private final MutableLiveData<Boolean> callFailure = new MutableLiveData<>();
        private final MutableLiveData<List<UserModel>> users = new MutableLiveData<>();
    
        public LiveData<Boolean> getCallFailure() {
            return callFailure;
        }
    
        public LiveData<Boolean> getUsers() {
            return users;
        }
    
        // THIS IS THE METHOD I'M CALLING FROM THE UI
        public void retryGetUsers() {
            callFailure.setValue(false);
            getUsers();
        }
    
        private void getUsers() {
            userRepo.getListUsers(new Callback<UserResponse>(){
                @Override
                public void onResponse(Call<UsersResponse> call, Response<UsersResponse> response) {
                    users.setValue(response.body().getUserList());
                }
    
                @Override
                public void onFailure(Call<UsersResponse> call, Throwable t) {
                    callFailure.setValue(true);
                }
            });
        }
    }
    

    【讨论】:

    • 我明白了,但只是为了确保我完全理解你的观点:通过我的 ViewModel 从我的 UI 触发我的 repo 中的事件没有错,还有其他方法吗?我想不出来,发现这很简单。其次,您能详细说明一下将重试和失败存储在 ViewModel 中吗?
    • 1 - 我看不到任何其他触发 ViewModel 的方法... 2 - 我用一些代码更新了答案以说明我的想法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-25
    • 2022-12-16
    • 1970-01-01
    • 2013-06-18
    • 2011-11-29
    • 2015-11-24
    • 2023-03-03
    相关资源
    最近更新 更多