【问题标题】:Android application architecture am i doing this correctly? [closed]Android 应用程序架构我这样做正确吗? [关闭]
【发布时间】:2020-03-08 12:54:21
【问题描述】:

我在这里关注本指南https://developer.android.com/jetpack/docs/guide?hl=en

为了学习关注点分离,我创建了一个简单的应用程序,它从 API 获取一些数据并将其显示在屏幕上的活动中。

我的活动如下,它的职责是向用户显示信息。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button myButt;
    private MainViewModel mvw;
    private TextView myView;
    private MutableLiveData<Orders> mld;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mvw = new ViewModelProvider(this).get(MainViewModel.class);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myButt = findViewById(R.id.button);
        myView = findViewById(R.id.textview);
        myButt.setOnClickListener(this);

        mvw.getMld().observe(this, new Observer<Orders>() {
            @Override
            public void onChanged(Orders orders) {
                Log.i("livedata","got an updt");
                myView.setText(mvw.extractDate(orders));
            }
        });
    }

    @Override
    public void onClick(View view) {
        switch(view.getId()){
            case R.id.button:
                Log.i("tag","hello");
                mvw.updateData();
        }
    }
}

跟随 ViewModel,它关注的是从存储库类中获取数据,并在将数据显示在 Activity 中之前对该数据进行一些计算。

public class MainViewModel extends ViewModel {
    private GetOrder getOrderRepo;
    private MutableLiveData<Orders> mld;

    public MainViewModel(){
        getOrderRepo = new GetOrder();
        mld = getOrderRepo.getAllOrders();
    }

    public MutableLiveData<Orders> getMld() {
        return mld;
    }

    public void setMld(MutableLiveData<Orders> mld) {
        this.mld = mld;
    }





    public void updateData(){
        getOrderRepo.getAllOrders(); //discard the return value
    }

    public String extractDate(Orders orders){
        ArrayList<Order> listOfOrders = orders.getOrders();
        String date = listOfOrders.get(0).getOrderTime();
        return date;
    }

}

接下来是它处理来自 API 的 GET 请求并将其放入 MutableLiveData 容器“allOrders”的存储库

public class GetOrder {
    private ApiService mAPIService;
    MutableLiveData<Orders> allOrders;
    private Orders orders;
    public GetOrder(){
        mAPIService = ApiUtils.getAPIService();
    }
    public MutableLiveData<Orders> getAllOrders(){
        Log.i("func","starting func");
        allOrders = new MutableLiveData<Orders>();
        mAPIService.getOrders().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Orders>() {
                    @Override
                    public void onCompleted() {
                        Log.i("func","onComplete");

                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.i("onError",e.toString());

                    }

                    @Override
                    public void onNext(Orders orders) {
                        Log.i("Repo",orders.toString());
                        allOrders.setValue(orders);
                    }
                });
        return allOrders;
    }
}

这是一个正确的实现吗?还是我误会了什么?

我担心的一个问题是按钮有 mvw.orderData().observe(this, new Observer() 因为 this 每次都会创建一个新的观察者。还是每次 onChanged 后它都会死掉?

反馈后更新

【问题讨论】:

    标签: java android retrofit


    【解决方案1】:

    您在这里实现的是 MVVM 架构。模型(存储库)-视图(活动)-VM(视图模型)。基本结构看起来不错,但我发现有一些地方可以改进,以便更好地遵循最佳做法。

    1. 正如您所说,您正在为每次按钮单击创建一个新的观察者。 您应该改为观察 onCreate 中的 LiveData。在您的 ViewModel 中添加一个函数,告诉存储库更新数据并在 onClick 方法中调用它。
    2. 您应该将 MutableLiveData 实现为私有并将其包装在 LiveData 中,然后在 Activity 中观察。所以它不会发生突变。 ViewModel 还应该存储获取的 MutableLiveData。

    更新(2): 检查MainActivityViewModel under this link。您在 ViewModel 中设置的 MutableLiveData 应该是私有的。

     private MutableLiveData<List<String>> fruitList;
    

    然后通过普通 LiveData 返回 MutableLiveData。此 LiveData 不可变,不能为 null,因此可以安全地暴露给其他类,例如 MainActivity,您可以在其中观察它。

    LiveData<List<String>> getFruitList() {
            if (fruitList == null) {
                fruitList = new MutableLiveData<>();
                loadFruits();
            }
            return fruitList;
        } 
    

    loadFruits() 函数将是您的情况下来自存储库的 api 调用。

    1. 您应该使用 ViewModelProvider 和/或 ViewModelFactory 实例化 ViewModel。 Here 是更详细的解释。它应该看起来像这样:

      private val viewModel = ViewModelProvider(this).get(MainViewModel::class.java)

    现在可以感知生命周期。如果您愿意,您可以稍后在片段中注入相同的实例。

    1. 只是为了好玩:我喜欢你的按钮变量被称为 myButt :D

    【讨论】:

    • 感谢您的回复。 :) 我认为我在 (1) 和 (3) 上正确理解了您,因此我更新了原始帖子中的代码。但是在(2)我有点困惑。 ViewModel 现在存储正在获取的数据。但是我不太明白您所说的“您应该将 MutableLiveData 实现为私有并将其包装在 LiveData 中,然后在 Activity 中观察”是什么意思。您的意思是 MutableLiveData 也应该作为私有变量存在于 Activity 中吗?在这种情况下,“将其包装在 LiveData 中”是什么意思?
    • private 表示 ViewModel 中的私有变量,这样 MutableLiveData 不会暴露。我将更新第 2 点。
    【解决方案2】:

    ViewModel 应该负责存储数据。

    因此,更好的方法是在 ViewModel 中使用 MutableLiveData&lt;Orders&gt; allOrders; 而不是 Repository。这样存储库只负责获取数据。它不应该存储它。

    然后,在您的活动中,您应该像这样观察allOrders 实时数据:mvw.allOrders.observe(...) in onCreate()。

    点击按钮后,您只需调用 Repository 方法即可使用 ViewModel 的方法 orderData() 获取/更新 allOrders LiveData。

    【讨论】:

      猜你喜欢
      • 2012-12-12
      • 1970-01-01
      • 2011-03-31
      • 2017-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-06
      相关资源
      最近更新 更多