Android ViewModel 不断初始化 ArrayList

Posted

技术标签:

【中文标题】Android ViewModel 不断初始化 ArrayList【英文标题】:Android ViewModel keeps initialising ArrayList 【发布时间】:2019-02-27 02:00:02 【问题描述】:

在过去的两天里,我一直在尝试使用 ViewModel 来存储 ArrayList。但是,每次我访问 ViewModel 时,它都会初始化 ArrayList,删除其中存储的数据。

我尝试在 ViewModel 中包含方法来控制 ArrayList 的初始化,但没有帮助。每次访问 ViewModel 时,它都会将 ArrayList 重置为“null”。

为什么会发生这种情况,我该如何阻止它?

ViewModel_Quiz.java

import android.arch.lifecycle.ViewModel;
import java.util.ArrayList;

public class ViewModel_Quiz extends ViewModel 

    ArrayList<String> checkboxStatus;

    public void sendCheckboxStatus(ArrayList<String> arrayList)
        checkboxStatus = arrayList;
    

    public ArrayList<String> getCheckboxStatus()
        return checkboxStatus;
    

FragmentQuiz_Selection.java

import android.arch.lifecycle.ViewModelProviders;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.support.constraint.Group;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;

public class FragmentQuiz_Selection extends Fragment implements View.OnClickListener

private FloatingActionButton fab_start;
//Create member variable for Checkbox loops
private boolean mChecked;
//Create ArrayList for QuizSelection
private ArrayList<String> mQuizSelection = new ArrayList<>();
//Create boolean for Expand/Collapse
//boolean iv_group_instruments = false;
//Create View variable
private View mView;
//Variables for database
private SQLiteDatabase mInstrumentsDB;
private InstrumentsDbHelper instrumentsDb;
//This contains the same data as mQuizSelection. It's used to prepare the database and populate mTotalRows.
private String[] mQuizSelectionArray;
//This is used as part of quizPrep() to populate mTotalRows. This may note need to be a memberVariable.
private int mTotalRows;
//This contains the total number of columns for the user's selection.
private int mTotalColumns;
//This holds all of the column/row pairs for the quiz.
private ArrayList<String> mQuizList = new ArrayList<>();
//This variable is used to interface with MainActivity
private OnQuizStarted mCallback;
//This ArrayList holds the CheckBox status for restoring the user's state
private ArrayList<String> mCheckboxStatus = new ArrayList<>();

public static FragmentQuiz_Selection newInstance() 
    FragmentQuiz_Selection fragment = new FragmentQuiz_Selection();
    return fragment;


//Create an interface to communicate with MainActivity
public interface OnQuizStarted 
    void onQuizStarted (ArrayList<String> arrayList);

// Connect the interface to MainActivity

@Override
public void onAttach(Context context) 
    super.onAttach(context);

    // This makes sure that the container activity has implemented
    // the callback interface. If not, it throws an exception
    try 
        mCallback = (OnQuizStarted) context;
     catch (ClassCastException e) 
        throw new ClassCastException(context.toString()
                + " must implement OnQuizStarted");
    


@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) 

    //Store views in variable
    mView = inflater.inflate(R.layout.fragment_quiz_selection, container, false);

    // Set onClickListeners
    setOnClickListeners();

    //Ensure all Checkboxes are set to 'false'
    ViewGroup constraintLayout = (ViewGroup) mView.findViewById(R.id.quiz_menu_layout);
    loopCheckboxesFalse(constraintLayout);

    //Create onClickListener for 'start' FAButton
    fab_start.setOnClickListener(new View.OnClickListener() 
        //If you click the FAButton, start the Quiz
        @Override
        public void onClick(View view) 
            //Create variable for ConstraintLayout
            ViewGroup constraintLayout = (ViewGroup) mView.findViewById(R.id.quiz_menu_layout);
            quizStart(constraintLayout);
        
    );

    return mView;


//Handle actions when the user is returning to the Fragment
@Override
public void onResume() 
    super.onResume();
    Log.i("LIFECYCLE CHANGE", "Quiz_Selection, onResume has been called!");
    //Get mCheckboxStatus from ViewModel
    ViewModel_Quiz viewmodel = ViewModelProviders.of(this).get(ViewModel_Quiz.class);
    if (viewmodel.getCheckboxStatus() != null && !(viewmodel.getCheckboxStatus().isEmpty())) 
        mCheckboxStatus = viewmodel.getCheckboxStatus();
        setCheckboxStatus(mCheckboxStatus);
    
    //If mChecked is 'true,' show FAButton. If mChecked is 'false,' hide FAButton.
    ViewGroup layout = mView.findViewById(R.id.quiz_menu_layout);
    mChecked = loopCheckboxesBoolean(layout);
    fabButton(mChecked, fab_start);


//Handle actions when the user is leaving, but not necessarily destroying, the Fragment
@Override
public void onPause() 
    super.onPause();
    Log.i("LIFECYCLE CHANGE", "Quiz_Selection, onPause has been called!");
    mCheckboxStatus.clear();
    recordCheckboxStatus(mCheckboxStatus);
    //Send mCheckboxStatus to ViewModel
    ViewModel_Quiz viewmodel = ViewModelProviders.of(this).get(ViewModel_Quiz.class);
    viewmodel.sendCheckboxStatus(mCheckboxStatus);


@Override
public void onClick(View view) 
    if (view instanceof CheckBox) 
        onCheckboxClicked(view);
     else if (view instanceof ImageView) 
        onExpandCollapse(view);
    


//METHOD:   Set Checkbox status for 'onCreate'
private void setCheckboxStatus (ArrayList<String> arrayList) 
    ViewGroup layout = mView.findViewById(R.id.quiz_menu_layout);
    int childCount = layout.getChildCount();
    //Iterate through the layout's CheckBox views
    for (int i = 0; i < childCount; i++) 
        View view = layout.getChildAt(i);
        //If item is a Checkbox, assign it as true or false
        if (view instanceof CheckBox) 
            if (arrayList.get(0) == "y") 
                ((CheckBox) view).setChecked(true);
                arrayList.remove(0);
             else if (arrayList.get(0) == "n") 
                ((CheckBox) view).setChecked(false);
                arrayList.remove(0);
            
        
    


//METHOD:   Store Checkbox status for 'onPause'
private void recordCheckboxStatus (ArrayList<String> arrayList) 
    ViewGroup layout = mView.findViewById(R.id.quiz_menu_layout);
    int childCount = layout.getChildCount();
    //Iterate through the layout's views
    for (int i = 0; i < childCount; i++) 
        View view = layout.getChildAt(i);
        //If item is a Checkbox && Checkbox is 'checked,' add 'y' to the arrayList.
        if (view instanceof CheckBox && ((CheckBox) view).isChecked()) 
            arrayList.add("y");
        //Else if item is a Checkbox && Checkbox is 'not checked,' add 'n' to the arrayList.
         else if (view instanceof CheckBox && !((CheckBox) view).isChecked())
            arrayList.add("n");
        //Else if item is not a Checkbox, skip this view and move to the next one
         else 
    

【问题讨论】:

不是对您的具体问题的直接回答,但我建议在像这样使用ViewModel 时使用LiveData。以下有更多信息,包括在 ViewModel 中使用它 - developer.android.com/topic/libraries/architecture/livedata 谢谢。你能解释一下为什么我在以这种方式使用 ViewModel 时应该使用 LiveData 吗? 【参考方案1】:

你必须在你的 ViewModel 中使用 MutableLiveData。

import android.arch.lifecycle.ViewModel;
import java.util.ArrayList;

public class ViewModel_Quiz extends ViewModel 

    MutableLiveData<Arraylist<String>> checkboxStatus;

    public void sendCheckboxStatus(ArrayList<String> arrayList)
        checkboxStatus.postValue(arrayList);
    

    public ArrayList<String> getCheckboxStatus()
        return checkboxStatus;
    

【讨论】:

以上是关于Android ViewModel 不断初始化 ArrayList的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android/Kotlin App 上通过 Koin 注入在 BaseActivity 中初始化/注入通用 ViewModel

Android 之 ViewModel 的正确用法

在android中使用“by viewModels()”与“ViewModelProvider(this).get(ViewModel::class.java)”进行视图模型初始化

Android 如何保证逻辑业务类只初始化一次

Android 如何保证逻辑业务类只初始化一次

Android 如何保证逻辑业务类只初始化一次