如何解决Android/java - 分解一大类充满计算的最佳实践
我正在开发一个简单的助眠应用程序,该应用程序允许用户选择每分钟的起始呼吸次数、每分钟的目标呼吸次数和总持续时间。然后,该应用会打开和关闭昏暗的灯光,以匹配他们选择的每分钟呼吸次数,减慢 5 分钟以上以达到他们的目标,然后一直持续到所选的持续时间。
为了做到这一点,我只是在扩展 android.app.Activity 的类的 OnCreate 方法中编写了一大堆计算,但几个月后我又回来了,我现在担心可读性/最佳实践,所以我现在想我应该将其分解为多个函数/类,或者创建一个由易于测试的函数组成的 utils 类,每个函数都执行部分计算。
这是onCreate:
public class Lightpulse extends Activity {
public Lightpulse(){
}
//Hides the status bar to allow true black background
public void hideStatusBar() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
getwindow().getDecorView()
.setsystemUIVisibility(View.SYstem_UI_FLAG_LAYOUT_STABLE
| View.SYstem_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYstem_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYstem_UI_FLAG_HIDE_NAVIGATION
| View.SYstem_UI_FLAG_FULLSCREEN
| View.SYstem_UI_FLAG_IMMERSIVE_STICKY
);
}
}
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.light_pulse);
//prevent the screen from automatically locking before the light pulse duration is over
getwindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
hideStatusBar();
//Enable stop button
Button stopButton = findViewById(R.id.stop_button);
stopButton.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
//Get data passed to Lightpulse activity from home UI
Intent intent = getIntent();
//Set background to selected colour
final ImageView lightpulseImage = findViewById(R.id.image_pulsing_light);
lightpulseImage.setBackgroundColor(intent.getIntExtra("colour",0));
//Get total duration,start breath duration,and goal breath duration in milliseconds.
int duration = Integer.valueOf(intent.getStringExtra("duration").substring(0,2))*60000;
Integer startBreathDuration = 60000/intent.getIntExtra("startBPM",0);
Integer goalBreathDuration = 60000/intent.getIntExtra("goalBPM",0);
//Calculate difference in milliseconds between start and goal duration.
Integer BreathDelta = goalBreathDuration - startBreathDuration;
//Calculate the average breath length when moving from start to goal. This is just the midpoint.
int averageBreathDuration = (startBreathDuration + goalBreathDuration)/2;
Log.i("debug","onCreate: Start Breath duration: " + startBreathDuration + " Goal Breath duration: " + goalBreathDuration + " Breath Delta: " + BreathDelta + " Average Breath DUration: " + averageBreathDuration + " total duration: " + duration);
//Transition period is 5 mins,need to calculate the number of breaths in 5 mins if all breaths were at average
Integer breathsInFiveMinutesAverage = 300000/averageBreathDuration;
Log.i("debug","onCreate: Average breaths in 5 minutes: " + breathsInFiveMinutesAverage);
//Calculate how much to decrease breath duration by each time,in order to be consistent and move to goal breath duration in 5 mins
Integer breathDurationShift = BreathDelta/breathsInFiveMinutesAverage;
Log.i("debug","onCreate: Breath duration shift: " + breathDurationShift);
//Instantiate animatorSet for playing sequential animators
AnimatorSet pulseSet = new AnimatorSet();
//Instantiate animator list to store pulsing light animators
List<Animator> animations = new ArrayList<>();
//Integer for tracking how long the transition set of animators takes in milliseconds
Integer totalTimeForFirstAnimations = 0;
//Mutable breath duration integer for transition from start to goal BPM in for loop
int breathDuration = startBreathDuration;
//For loop to create the initial set of animators for the transition between start and goal BPM,over 5 minutes
for(int i = 0; i<breathsInFiveMinutesAverage; i++){
Log.i("debug","onCreate: " + breathDuration);
Log.i("debug","onCreate colour is: " + intent.getIntExtra("colour",0));
//Create the animators to fade in and out one time and add them to the list. Exhale/inhale duration is split 60/40
final ObjectAnimator fadeInAnimator = ObjectAnimator
.ofFloat(lightpulseImage,View.ALPHA,0f,1f)
.setDuration(Math.round(breathDuration*0.8));
animations.add(fadeInAnimator);
final ObjectAnimator fadeOutAnimator = ObjectAnimator
.ofFloat(lightpulseImage,1f,0f)
.setDuration(Math.round(breathDuration*1.2));
animations.add(fadeOutAnimator);
//update the duration for the next animation by adding on the prevIoUsly calculated shift
breathDuration = breathDuration + breathDurationShift;
//update total time for transition animations
totalTimeForFirstAnimations = totalTimeForFirstAnimations + breathDuration;
}
Log.i("debug","onCreate: Total time for first set of animations: " + totalTimeForFirstAnimations);
//Calculate remaining time after transition is done,for debugging
int remainingDuration = duration-totalTimeForFirstAnimations;
//Calculate how many breaths can be done in the remaining time at the goal breath duration
int numberOfRepeatsRemaining = remainingDuration/goalBreathDuration;
Log.i("debug","onCreate: remaining duration: " + remainingDuration + " Number of repeats: " + numberOfRepeatsRemaining);
Log.i("debug","onCreate: Goal breath duration: " + goalBreathDuration);
long totalTimeOfRemainingAnimations = 0;
//Create breathe in and out animators which repeat for the remaining number of breaths,with 5 extra of each added to allow the screen to automatically lock before the process is finished
for(int i = 0; i<(numberOfRepeatsRemaining)+5; i++){
final ObjectAnimator fadeInAnimator = ObjectAnimator
.ofFloat(lightpulseImage,1f)
.setDuration(Math.round(goalBreathDuration*0.8));
animations.add(fadeInAnimator);
final ObjectAnimator fadeOutAnimator = ObjectAnimator
.ofFloat(lightpulseImage,0f)
.setDuration(Math.round(goalBreathDuration*1.2));
animations.add(fadeOutAnimator);
totalTimeOfRemainingAnimations = totalTimeOfRemainingAnimations + Math.round(goalBreathDuration*0.8) + Math.round(goalBreathDuration*1.2);
}
Log.i("debug","onCreate: total time of final animations " + totalTimeOfRemainingAnimations);
Log.i("debug","onCreate: animations list size: " + animations.size());
//Calculate the total time of animations in milliseconds,for debugging
int totalAnimationTime = totalTimeForFirstAnimations + (numberOfRepeatsRemaining*goalBreathDuration);
Log.i("debug","onCreate: animations total time in milliseconds: " + totalAnimationTime);
//After the chosen duration is over,allow the screen to lock.
final Handler screenOffHandler = new Handler();
screenOffHandler.postDelayed(new Runnable() {
@Override
public void run() {
Log.i("debug","times up");
getwindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//End the activity once the screen has been given time to lock
final Handler screenOffHandler = new Handler();
screenOffHandler.postDelayed(new Runnable() {
@Override
public void run() {
Log.i("debug","Exiting light pulse activity");
finish();
}
},30000);
}
},duration);
//Add the animator list to the animatorSet,and play them sequentially
pulseSet.playSequentially(animations);
pulseSet.start();
}
}
在 HomeFragment 类中,此处是调用该活动的位置:
//set up start button
final Button startButton = root.findViewById(R.id.start_button);
startButton.setonClickListener(new View.OnClickListener() {
//when pressed,Lightpulse activity is started,and is provided with the selected values for duration,start BPM,goal BPM,and light colour
@Override
public void onClick(View v) {
Intent intent = new Intent(getActivity(),Lightpulse.class);
intent.putExtra("startBPM",homeviewmodel.getStartingBPM().getValue());
intent.putExtra("goalBPM",homeviewmodel.getGoalBPM().getValue());
intent.putExtra("colour",homeviewmodel.getColour().getValue());
intent.putExtra("duration",spinner.getSelectedItem().toString());
startActivity(intent);
}
});
有没有推荐的方法来解决这个问题?我想为此编写一个单元测试套件,但很多计算重复使用相同的变量,这增加了很多复杂性。
解决方法
我建议使用 MVVM 架构模式。您正在主线程上进行大量计算。这是科特林。类似的东西:
class LightPulseViewModel: ViewModel() {
fun calculateBreathsDuration(duration: Int,startBreathsPerMinute: Int,goalBreathsPerMinute: Int): Int {
var value = 0
//do your work
return value
}
fun calculateAnimationTime(): Long {
var value = 0L
//do your work
return value
}
}
然后在 LightPulse 中:
public class LightPulse extends Activity {
public LightPulse(){
}
LightPulseViewModel viewModel;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.light_pulse);
viewModel = ViewModelProvider(this).get(LightPulseViewModel::class.java);
///whereever you need to do calculations
Integer breathsduration = viewModel.calculateBreathsDuration(Integer.valueOf(intent.getStringExtra("duration").substring(0,2))*60000,60000/intent.getIntExtra("startBPM",0),60000/intent.getIntExtra("goalBPM",0))
//do the same for animation duration calculations here.
}
}
有关 MVVM 模式的更多信息:https://www.journaldev.com/20292/android-mvvm-design-pattern
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。