android - ViewModel 永远不应该引用视图。如果你这样做,那么你会得到内存泄漏。如何不违反这条规则?
问题描述
ViewModel 绝不能引用视图、生命周期或任何可能持有对活动上下文的引用的类。
视图模型不应该引用视图。如果你这样做,那么你会得到内存泄漏。
public class FirstActivityViewModel extends ViewModel {
private int displayWidth;
private int displayHeight;
private double widthMultiplier;
private double heightMultiplier;
private int testedWidth = 1200;
private int testedHeight = 1920;
public void setDisplayCorrectedSizes(RelativeLayout relativeLayout){
displayWidth = relativeLayout.getWidth();
widthMultiplier = ((double) displayWidth) / ((double) testedWidth);
displayHeight = relativeLayout.getHeight();
heightMultiplier = ((double) displayHeight) / ((double) testedHeight);
}
public double getWidthMultiplier(){
return widthMultiplier;
}
public double getHeightMultiplier(){
return heightMultiplier;
}
}
还是这样的代码违反了该规则?
public class FirstActivityViewModel extends ViewModel {
private RelativeLayout relativeLayout;
private int displayWidth;
private int displayHeight;
private double widthMultiplier;
private double heightMultiplier;
private int testedWidth = 1200;
private int testedHeight = 1920;
public void setDisplayCorrectedSizes(RelativeLayout relativeLayout){
displayWidth = relativeLayout.getWidth();
widthMultiplier = ((double) displayWidth) / ((double) testedWidth);
displayHeight = relativeLayout.getHeight();
heightMultiplier = ((double) displayHeight) / ((double) testedHeight);
this.relativeLayout = relativeLayout;
}
public double getWidthMultiplier(){
return widthMultiplier;
}
public double getHeightMultiplier(){
return heightMultiplier;
}
}
还是双方都违规?
我只是想了解我是否以正确的方式理解它。
……………………………………………………………………………………………………………………………………
这是我想从视图替换为 ViewModel 的整个代码。
void actionsForUISizesOptimizationProcess(){
RelativeLayout relativeLayout2 = findViewById(R.id.rootLayoutSmallBoard);
int displayWidth = relativeLayout2.getWidth();
int displayHeight = relativeLayout2.getHeight();
int testedWidth = 1200;
double widthMultiplier = ((double) displayWidth) / ((double) testedWidth);
int testedHeight = 1920;
double heightMultiplier = ((double) displayHeight) / ((double) testedHeight);
// firstActivityViewModel.setDisplayCorrectedSizes(relativeLayout2);
// double widthMultiplier = firstActivityViewModel.getWidthMultiplier();
// double heightMultiplier = firstActivityViewModel.getHeightMultiplier();
if (limitOfOnWindowFocusChangedOperationForSmallBoard == 0) { /
//Log.i("userTest2020", "display width = " + displayWidth + "\n" + "display height = " + displayHeight);
int viewWidth;
int viewHeight;
viewWidth = (int) getResources().getDimension(R.dimen.tv10WidthSmallBoard);
viewHeight = (int) getResources().getDimension(R.dimen.tv10HeightSmallBoard);
tvSmallBoardResolutionInfoValue.getLayoutParams().width = (int) (viewWidth * widthMultiplier);
tvSmallBoardResolutionInfoValue.getLayoutParams().height = (int) (viewHeight * heightMultiplier);
viewWidth = (int) getResources().getDimension(R.dimen.tv11WidthSmallBoard);
viewHeight = (int) getResources().getDimension(R.dimen.tv11HeightSmallBoard);
tvSmallBoardScoreValue.getLayoutParams().width = (int) (viewWidth * widthMultiplier);
tvSmallBoardScoreValue.getLayoutParams().height = (int) (viewHeight * heightMultiplier);
viewWidth = (int) getResources().getDimension(R.dimen.btn1WidthSmallBoard);
viewHeight = (int) getResources().getDimension(R.dimen.btn1HeightSmallBoard);
btnSmallBoardGetTheResolutionInfo.getLayoutParams().width = (int) (viewWidth * widthMultiplier);
btnSmallBoardGetTheResolutionInfo.getLayoutParams().height = (int) (viewHeight * heightMultiplier);
viewWidth = (int) getResources().getDimension(R.dimen.btnNewRoundWidthSmallBoard);
viewHeight = (int) getResources().getDimension(R.dimen.btnNewRoundHeightSmallBoard);
btnNewRoundSmallBoard.getLayoutParams().width = (int) (viewWidth * widthMultiplier);
btnNewRoundSmallBoard.getLayoutParams().height = (int) (viewHeight * heightMultiplier);
ImageView ivBtnGreen = findViewById(R.id.ivNewRoundSmallBoard);
viewWidth = (int) getResources().getDimension(R.dimen.ivNewRoundWidthSmallBoard);
viewHeight = (int) getResources().getDimension(R.dimen.ivNewRoundHeightSmallBoard);
ivBtnGreen.getLayoutParams().width = (int) (viewWidth * widthMultiplier);
ivBtnGreen.getLayoutParams().height = (int) (viewHeight * heightMultiplier);
FrameLayout flNewBoard = findViewById(R.id.newRoundViewGroupSmallBoard);
viewWidth = flNewBoard.getWidth();
viewHeight = flNewBoard.getHeight();
flNewBoard.getLayoutParams().width = (int) (viewWidth * widthMultiplier);
flNewBoard.getLayoutParams().height = (int) (viewHeight * heightMultiplier);
FrameLayout flBiggerBoard = findViewById(R.id.biggerBoardViewGroupSmallBoard);
viewWidth = (int) getResources().getDimension(R.dimen.BiggerBoardViewGroupSmallBoard);
flBiggerBoard.getLayoutParams().width = (int) (viewWidth * widthMultiplier);
viewHeight = (int) getResources().getDimension(R.dimen.btnNextBoardHeightSmallBoard);
btnNextBoardSmallBoard.getLayoutParams().height = (int) (viewHeight * heightMultiplier);
ImageView ivNextBoard = findViewById(R.id.ivNextBoardSmallBoard);
viewHeight = (int) getResources().getDimension(R.dimen.ivNextBoardHeightSmallBoard);
ivNextBoard.getLayoutParams().height = (int) (viewHeight * heightMultiplier);
limitOfOnWindowFocusChangedOperationForSmallBoard = 1;
}
}
为什么我认为我必须将此代码替换为 ViewModel?见这里https://android.jlelse.eu/mvvm-how-view-and-viewmodel-should-communicate-8a386ce1bb42(第一条规则)为什么我不知道该怎么做?另一方面,还有另一条规则:视图模型不应该引用视图。如果你这样做,那么你会得到内存泄漏。
解决方案
在避免内存泄漏方面,您的第二个FirstActivityViewModel
是违反规则。您有一个 Java 字段,其中包含对RelativeLayout
. 如果FirstActivity
由于配置更改而被销毁并重新创建,直到setDisplayCorrectedSizes()
被第二个活动实例调用,您的视图模型正在泄漏第一个活动实例。
更一般地说,我会避免使用这些方法中的任何一种。视图模型负责准备要呈现到屏幕的数据,但是关于像素和大小的问题是 UI 层的工作,而不是视图模型,恕我直言。
此外,您可能希望迁移到 FWIW,ConstraintLayout
因为它比 is 更强大且维护得更好RelativeLayout
。
推荐阅读
- android - 如何在 IconMode Android 中改变颜色?
- redis - 来自 Windows 命令/powershell 脚本的 Redis 集群运行状况检查
- git - How to enable spellcheck in vim on git-commit
- react-native - Get string from array of string
- matplotlib - How to use mode='expand' and center a figure-legend label given only one label entry?
- java - 单击片段时如何显示加载栏
- python - 从 JSON 字符串中删除反斜杠并打印键的值
- javascript - 在一个 React 函数中做多件事
- python - 添加一个新列,其中一些值被操作
- java - 如何在 Java 中将本地时间转换为 LDAP 时间戳