ViewModel绝不能引用可能包含对activity上下文引用的视图,生命周期或任何类。
视图模型永远不应引用视图。如果这样做,就会导致内存泄漏。
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;
}
}
还是两人都在违规?
我只想知道我是否以正确的方式去理解它。
。。。。。。。。。。。。。。。。。。。。。
下面是我想从view替换到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-communication-8a386ce1bb42(第一条规则),为什么我不知道怎么做?因为另一方面,还有另一条规则:视图模型永远不应该引用视图。如果这样做,就会导致内存泄漏。
在避免内存泄漏方面,您的第二个FirstActivityViewModel
违反了规则。您有一个保存对RelativeLayout
的引用的Java字段。如果FirstActivity
由于配置更改而被销毁并重新创建,则在第二个activity实例调用SetDisplayCorretedSize()
之前,您的viewmodel正在泄漏第一个activity实例。
更一般说来,我会避免这两种方法中的任何一种。viewmodel负责准备要呈现到屏幕上的数据,但是像素和大小是UI层的工作,而不是viewmodel。
另外,FWIW,您可能希望迁移到ConstraintLayout
,因为它是比RelativeLayout
更强大,维护更好的选项。
理论上,第二个违反了规则,而第一个没有,但理想情况下,viewModel从不关心视图。在编写单元测试时,使用相对布局作为参数会有问题。我们的目的应该是尽可能地将viewModel从视图中分离出来。我建议重写您的第二种方法,如下所示
null
public void setDisplayCorrectedSizes(int displayWidth, int displayHeight){
widthMultiplier = ((double) displayWidth) / ((double) testedWidth);
heightMultiplier = ((double) displayHeight) / ((double) testedHeight);
}