如何在ViewModel中保存图像以处理方向变化?

时间:2018-09-12 14:27:36

标签: android viewmodel

我的活动包含一个imageview和一个按钮,单击该按钮时imageview内部的图像已更改(工作正常)。

但是当屏幕方向改变时,imageview内的图像丢失了(因为重新创建了活动)。

我在某篇文章中读到ViewModel可以保留方向,并且与onSaveInstanceState相比,它可以存储大量数据(位图)。

还有很多其他选项可以恢复同一张图像,但是我想使用ViewModel来获得同一张图像而不受方向变化的影响。

那么,如何使用ViewModel获得相同的图像?

谢谢。

2 个答案:

答案 0 :(得分:1)

使用ViewModel与TextView和ImageView一起使用以承受方向变化的简单示例

示例说明:

布局包含一个TextView,ImageView和一个Button。最初,文本和图像是在布局内部的TextView和ImageView上设置的。单击按钮时,将文本(以编程方式)和图像(来自drawable)设置为适当的视图。

假设设备已旋转,因此由于活动重新创建而丢失了单击按钮时设置的文本和图像,因此会加载在xml文件中设置的文本和图像。

为解决此问题,我们使用ViewModel来处理配置更改。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/my_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Android" />

    <ImageView
        android:id="@+id/my_image"
        android:layout_width="96dp"
        android:layout_height="96dp"
        android:layout_margin="20dp"
        android:src="@drawable/ic_android_black_24dp" />

    <Button
        android:id="@+id/my_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:text="Update text and image" />

</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

    TextView mText;
    ImageView mImageView;
    Button mButton;

    MyViewModel mViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mText = findViewById(R.id.my_text);
        mImageView = findViewById(R.id.my_image);
        mButton = findViewById(R.id.my_button);

        mViewModel = ViewModelProviders.of(this).get(MyViewModel.class);

        if (mViewModel.getText() != null) {
            mText.setText(mViewModel.getText());
        }

        if (mViewModel.getImage() != null) {
            mImageView.setImageDrawable(mViewModel.getImage());
        }

        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mText.setText("Happy Coding...");
                mImageView.setImageDrawable(getResources().getDrawable(R.drawable.ic_face));
            }
        });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        mViewModel.setText(mText.getText().toString());
        mViewModel.setImage(mImageView.getDrawable());

    }
}

MyViewModel.java

public class MyViewModel extends ViewModel {

    private String text;
    private Drawable image;

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Drawable getImage() {
        return image;
    }

    public void setImage(Drawable image) {
        this.image = image;
    }
}

关于ViewModel的一些技巧:

  1. ViewModel类旨在以生命周期感知的方式保存和管理与UI相关的数据。这使数据能够承受配置更改(例如屏幕旋转)的影响。
  2. ViewModels将UI实施与应用数据分开。 ViewModel的生命周期从首次创建关联的UI控制器开始,一直到完全销毁为止。
  3. 切勿将UI控制器或上下文直接或间接存储在ViewModel中。这包括将View存储在ViewModel中。直接或间接引用UI控制器会破坏将UI与数据分离的目的,并可能导致内存泄漏。
  4. ViewModel还可以与另一个架构组件(如LiveData,Room)很好地配合使用。使用LiveData的另一个好处是它可以观察到:当数据更改时,它可以触发UI更新。使用下面的链接了解更多信息。

链接: https://developer.android.com/topic/libraries/architecture/viewmodel

https://developer.android.com/topic/libraries/architecture/livedata.html

CodeLab链接: https://codelabs.developers.google.com/codelabs/android-room-with-a-view/#0

我不是专业开发人员。上面的代码对我有用。欢迎提出任何更正或建议。

谢谢;)

答案 1 :(得分:0)

您的ViewModel应该具有方法changeImage,该方法可以更改ViewModel的内部状态。您必须以某种方式指示有关此更改的活动。为此,最好使用val imageId = MutableLiveData<Int>()

changeImage更改此值。在“活动”中,您可以订阅更改并在imageId更改时应用新图像。