微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Android/java - 分解一大类充满计算的最佳实践

如何解决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 举报,一经查实,本站将立刻删除。