Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Android MVVM架构并观察来自API的数据更改

Android MVVM架构并观察来自API的数据更改
EN

Stack Overflow用户
提问于 2019-11-30 19:21:52
回答 3查看 1.7K关注 0票数 0

我是Android MVVM架构的新手。我有一个在本地运行的API,里面有数据(“交易”)。我只想向API发出一个请求,并在文本字段中显示该数据。当前数据不会在第一次加载片段时显示,但如果我转到另一个活动,然后返回到它加载的片段。

这里有3个重要的类别。

DashboardViewModel.java:

代码语言:javascript
运行
AI代码解释
复制
package com.example.android_client.ui.dashboard;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import com.example.android_client.models.Deal;
import com.example.android_client.repository.Repository;

import java.util.List;

public class DashboardViewModel extends ViewModel {

    private MutableLiveData<String> mText;
    private Repository repository;
    private MutableLiveData<List<Deal>> deals = null;

    public void init() {
        if(this.deals == null) {
            this.repository = Repository.getInstance();
            this.deals = this.repository.getDeals();
        }
    }

    public DashboardViewModel() {
        this.mText = new MutableLiveData<>();
    }

    public LiveData<List<Deal>> getDeals() {
        return this.deals;
    }
}

DashboardFragment.java:

代码语言:javascript
运行
AI代码解释
复制
package com.example.android_client.ui.dashboard;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProviders;

import com.example.android_client.R;
import com.example.android_client.models.Deal;

import java.util.List;

public class DashboardFragment extends Fragment {

    private DashboardViewModel dashboardViewModel;

    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
        final TextView textView = root.findViewById(R.id.text_dashboard);
        dashboardViewModel = ViewModelProviders.of(this).get(DashboardViewModel.class);
        dashboardViewModel.init();
        dashboardViewModel.getDeals().observe(this, new Observer<List<Deal>>() {
            @Override
            public void onChanged(List<Deal> deals) {
                if (deals != null && !deals.isEmpty()) {
                    System.out.println(deals.get(0).toString());
                    textView.setText(deals.get(0).toString());
                }
            }
        });
        return root;
    }
}

和Repository.java:

代码语言:javascript
运行
AI代码解释
复制
package com.example.android_client.repository;

import androidx.lifecycle.MutableLiveData;

import com.example.android_client.models.Deal;
import com.google.gson.Gson;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class Repository {

    private static Repository instance;
    private ArrayList<Deal> dealsList = new ArrayList<>();
    private final OkHttpClient client = new OkHttpClient();

    public static Repository getInstance() {
        if(instance == null) {
            instance = new Repository();
        }
        return instance;
    }

    private Repository() {}

    public MutableLiveData<List<Deal>> getDeals() {
        setDeals();
        MutableLiveData<List<Deal>> deals = new MutableLiveData<>();
        deals.setValue(dealsList);
        return deals;
    }

    private void setDeals() {
        Request request = new Request.Builder()
                .url("http://10.0.2.2:8000/api/deals?<params here>")
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                e.printStackTrace();
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                try (ResponseBody responseBody = response.body()) {
                    if (!response.isSuccessful()) {
                        throw new IOException("Unexpected code " + response);
                    }
                    String jsonDeals = responseBody.string(); // can only call string() once or you'll get an IllegalStateException
                    Deal[] deals = new Gson().fromJson(jsonDeals, Deal[].class);
                    dealsList = new ArrayList<>(Arrays.asList(deals));
                }
            }
        });

    }
}

在单步执行Repository类中的代码时,我可以看到在加载片段时调用了setDeals(),并且回调中的请求已排队。当getDeals()第一次返回时,它(在MutableLiveData对象中)返回一个包含0个交易的列表。

回调中的onResponse直到片段被加载后才会运行。在调试时,我可以看到数据在对象中(所有Gson内容都可以正常工作),但是不会再次调用onChanged (设置文本视图)。

我没有正确地观察到deals上的变化吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-11-30 19:58:31

您的代码无法正常工作,因为只要调用getDeals(),就会创建一个新的实时数据实例,并将api响应值通知给其他实时数据实例。必须将接口响应值设置为getDeals()返回的同一个MutableLiveData实例

我并不是说它是最好的体系结构解决方案,但是如果您创建一个可变的实时数据作为类属性,并在调用getDeals()时返回它。很可能,它会起作用。

此外,一个好的做法是返回一个LiveData而不是一个MutableLiveData,这样就不允许外部组件修改内部值。

请看一下下面的代码片段。

OBS:可能有一些语法错误,因为我还没有编译它

代码语言:javascript
运行
AI代码解释
复制
    import com.example.android_client.models.Deal;
    import com.google.gson.Gson;
    import org.jetbrains.annotations.NotNull;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;

    import okhttp3.Call;
    import okhttp3.Callback;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;
    import okhttp3.ResponseBody;

        public class Repository {

        private static Repository instance;
        private ArrayList<Deal> dealsList = new ArrayList<>();
        private final OkHttpClient client = new OkHttpClient();
        private MutableLiveData<List<Deal>> _deals = new MutableLiveData<>();                         
        private LiveData<List<Deal>> deals = _deals


        public static Repository getInstance() {
            if(instance == null) {
                instance = new Repository();
            }
            return instance;
        }

        private Repository() {}

        public LiveData<List<Deal>> getDeals() {
            setDeals();
            return deals;
        }

        private void setDeals() {
            Request request = new Request.Builder()
                    .url("http://10.0.2.2:8000/api/deals?<params here>")
                    .build();

            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                    e.printStackTrace();
                }

                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                    try (ResponseBody responseBody = response.body()) {
                        if (!response.isSuccessful()) {
                            throw new IOException("Unexpected code " + response);
                        }
                        String jsonDeals = responseBody.string(); // can only call string() once or you'll get an IllegalStateException
                        Deal[] deals = new Gson().fromJson(jsonDeals, Deal[].class);
                        dealsList = new ArrayList<>(Arrays.asList(deals));
                        _deals.setValue(dealsList);

                    }
                }
            });

        }

}
When 
票数 2
EN

Stack Overflow用户

发布于 2019-11-30 19:39:46

我想这会有帮助的。在网络调用的onResponse中的MutableLiveData上试用postValue。请更改您的存储库类,如下所示:

代码语言:javascript
运行
AI代码解释
复制
package com.example.android_client.repository;
import androidx.lifecycle.MutableLiveData;

import com.example.android_client.models.Deal;
import com.google.gson.Gson;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

public class Repository {

private static Repository instance;
private ArrayList<Deal> dealsList = new ArrayList<>();
private final OkHttpClient client = new OkHttpClient();
MutableLiveData<List<Deal>> deals = new MutableLiveData<>();

public static Repository getInstance() {
    if(instance == null) {
        instance = new Repository();
    }
    return instance;
}

private Repository() {}

private MutableLiveData<List<Deal>> getDeals() {
    Request request = new Request.Builder()
            .url("http://10.0.2.2:8000/api/deals?<params here>")
            .build();

    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(@NotNull Call call, @NotNull IOException e) {
            e.printStackTrace();
        }

        @Override
        public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
            try (ResponseBody responseBody = response.body()) {
                if (!response.isSuccessful()) {
                    throw new IOException("Unexpected code " + response);
                }
                String jsonDeals = responseBody.string(); // can only call string() once or you'll get an IllegalStateException
                Deal[] deals = new Gson().fromJson(jsonDeals, Deal[].class);
                dealsList = new ArrayList<>(Arrays.asList(deals));
                deals.postValue(dealsList);
            }
        }
    });
 return deals;
}
}
票数 2
EN

Stack Overflow用户

发布于 2019-11-30 19:31:48

在您的存储库类中,在函数中获取交易。您正在初始化实时数据。在后台线程中请求url,并在尚未从服务器接收到的实时数据上发布值。

为了解决这个问题,在仓库的构造函数中创建livedata实例,并在onResponse回调中创建livedata的postvalue。

//很抱歉写得不好,是从手机上发的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59119461

复制
相关文章
.NET/C# 使用 Span 为字符串处理提升性能
2018-07-21 16:51
walterlv
2018/09/18
3.4K0
.NET/C# 使用 Span 为字符串处理提升性能
JS,如果改变span标签的是否隐藏属性
----------------------------------Hongten--------------------------------------------
Hongten
2018/09/13
10.9K0
js 验证用户名和密码是否为空
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>My JSP 'userValidate.jsp' starting page</title> <script type="text/javascript">
week
2018/08/27
5.6K0
js验证
$("#passwordStart").bind("input propertychange",checkLength); $("#passwordEnd").bind("input propertychange",checkPasswod); //长度check function checkLength(){ var passwordStart = $.trim($("#passwordStart").val()); if(passwordStart.length<4 || password
斯文的程序
2019/11/07
7.7K0
CentOS 为Apache 使用LDAP 身份验证
Apache 中可以通过mod_authz_ldap 模块为LDAP 提供了良好的的支持。
星哥玩云
2022/06/28
1.1K0
Android Span在项目中的几种使用方式
1.字符串中 改变字体颜色和大小 2.字符串中 改变文字颜色 并 添加点击事件 3.字符串中 增加外框和改变文字颜色及字体大小 1.改变文字颜色 ForegroundColorSpan /\*\* \* 自定义颜色 \* \* @param content 全部文本 \* @param keyWord 需要变色的关键字 \* @param color 颜色 \*/ public static SpannableStringBuilder getSpan(String conte
Jingbin
2019/03/21
1.2K0
解读 --- Span<T>
Span<T> 是C# 中的一种结构体,它是一种内存安全的类型,可以用来表示连续的内存区域。Span<T> 可以被用于访问和操作数组、堆上分配的内存和栈上分配的内存。使用 Span<T> 可以避免不必要的内存拷贝,从而提高性能。
Niuery Diary
2023/10/22
2550
解读 --- Span<T>
使用Span实现各种酷炫效果
前一段时间一直在做富文本展示和文本处理,主要用到了Html.fromHtml()实现加载网页,但实现整段文本的某些特殊如个别文字的点击,改背景色、前景色等效果,就用到了我们今天要用到的Span这个类。
蜻蜓队长
2018/08/03
2K0
使用Span实现各种酷炫效果
解读 --- Span<T>
Span<T> 是C# 中的一种结构体,它是一种内存安全的类型,可以用来表示连续的内存区域。Span<T> 可以被用于访问和操作数组、堆上分配的内存和栈上分配的内存。使用 Span<T> 可以避免不必要的内存拷贝,从而提高性能。
Niuery Diary
2023/10/22
1950
解读 --- Span<T>
Android Span在项目中的几种使用方式
1.字符串中 改变字体颜色和大小 2.字符串中 改变文字颜色 并 添加点击事件 3.字符串中 增加外框和改变文字颜色及字体大小 1.改变文字颜色 ForegroundColorSpan /** * 自定义颜色 * * @param content 全部文本 * @param keyWord 需要变色的关键字 * @param color 颜色 */ public static SpannableStringBuilder getSpan(String content, String k
Jingbin
2019/03/22
7050
assume,用于EDA验证为断言,用于Formal验证为约束
用这句话来概括assume这个SVA语法在EDA验证与Formal验证中的区别再好不过了。为什么assume在EDA验证中是断言,而在Formal验证中是约束呢?同样是因为“水土异也”罢了。
AsicWonder
2021/03/16
2.9K0
assume,用于EDA验证为断言,用于Formal验证为约束
(收藏)JS验证
1 /* 2 函数名:检验表单的函数 3 作者:xuwen 日期:2007-2-10 4 参数 _obj:验证的对象 type:验证的类型 errmsg:错误的提示信息 flag:焦点的状态 5 表单失去焦点时调用:onblur=checkInput(this,'isUserName','用户名为数字,下划线组成',1) 6 表单提交时调用:f1 = checkInput(frm.UserName,'isUserName','用户名为数字,下划线组成
用户1172164
2018/01/12
5.4K0
Js输入验证
1.文本框只能输入数字代码(小数点也不能输入) <input onkeyup="this.value=this.value.replace(/\D/g,'')" onafterpaste="this.value=this.value.replace(/\D/g,'')"> 2.只能输入数字,能输小数点. <input onkeyup="if(isNaN(value))execCommand('undo')" onafterpaste="if(isNaN(value))execCommand('undo')"
用户7657330
2020/08/14
9.4K0
JS输入验证
验证职能输入手机号 先替换非数字 <input type="text" name="userPhone" placeholder="请输入手机号" class="" onkeyup="value=
码客说
2019/10/22
7.5K0
span不如div的地方
页面中产生格式化的效果,我一般比较喜欢用span,因为其本身就是inline的,但是,在进行精细控制时就不行了,比如我想要这个效果,每行由三个部分构成:时间,柱状图,数值,分布用span表示,用br换
用户1075292
2018/01/23
1.9K0
span不如div的地方
数学符号Span的含义
Span的概念比较好理解,就是若干个向量通过线性组合得到的一个向量空间(满足向量空间的所有要求)。Span列向量是矩阵中所有的列span成的空间。
狼啸风云
2019/12/10
5.7K0
Confluence 6 为登录失败配置使用验证码
如果你具有 Confluence 管理员的权限,你可以限制 Confluence 登录失败的最大尝试次数。在给予最大登录失败尝试(默认为 3 次)次数后,Confluence 将会在用户进行再次尝试的时候显示验证码输入框。这个能够避免用户通过登录页面进行密码暴利破解。
HoneyMoose
2019/01/30
1.1K0
Confluence 6 为登录失败配置使用验证码
使用JS将table表格导出为excel
之前都是用Java在后端做的导出,这次表格数据做的比较麻烦,就直接在前端把table导出了,非常方便。
sunonzj
2022/06/21
8.1K0
使用JS将table表格导出为excel
点击加载更多

相似问题

切换不会变回,span ng-bind不会更新为指定的文本

13

Span不会在div中更新

51

使用js更改span文本

329

使用ajax更新span内容

22

Google不会更新.js文件

14
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档