PSLab android application contains nearly 70 experiments one can experiment on using the PSLab device and the other necessary circuit components and devices. These experiments span over areas such as Electronics, Electrical, Physical and High school level. All these experiments are accessible via an android adapter in the repository named “PerformExperimentAdapter”. This adapter houses a tab view with two different tabs; one for the experiment details and the other for actual experiment and resultant graphs.
The adapter extends an inbuilt class FragmentPagerAdapter;
public class PerformExperimentAdapter extends FragmentPagerAdapter
This class displays every page attached to its viewpager as a fragment. The good thing about using fragments is that they have a recyclable life cycle. Rather than creating new views for every instance of an experiment, the similar views can be recycled to use once again saving resources and improving performance. FragmentPagerAdapter needs to override a method to display the correct view on the tab select by user.
@Override public Fragment getItem(int position) { }
Depending on the value of position, relevant experiment documentation and the experiment implementation fragments are displayed determined using the experiment title. Performance can be critical in this place as if it takes too long to process and render a fragment, user will feel a lag.
The previous implementation was using consecutive if statements.
@Override public Fragment getItem(int position) { switch (position) { case 0: if (experimentTitle.equals(context.getString(R.string.diode_iv))) return ExperimentDocFragment.newInstance("D_diodeIV.html"); if (experimentTitle.equals(context.getString(R.string.zener_iv))) return ExperimentDocFragment.newInstance("D_ZenerIV.html"); ... case 1: if (experimentTitle.equals(context.getString(R.string.diode_iv))) return ZenerSetupFragment.newInstance(); if (experimentTitle.equals(context.getString(R.string.zener_iv))) return DiodeExperiment.newInstance(context.getString(R.string.half_wave_rectifier)); ... default: return ExperimentDocFragment.newInstance("astable-multivibrator.html"); } }
This setup was suitable for applications where there is less than around 5 choices to chose between. As the list grows, the elements in the end of the if layers will take more time to load as each of the previous if statements need to be evaluated false in order to reach the bottom statements.
This is when this implementation was replaced using switch case statements instead of consecutive if statements. The theory behind the performance improvement involves algorithm structures; Hash Tables
Hash Tables
Hash tables use a hash function to calculate the index of the destination cell. This operation on average has a complexity of O(1) which means it will take the same time to access any two elements which are randomly positioned.
This is possible because java uses the hash code of the string to determine the index where the target is situated at. This way it is much faster than consecutive if statement calls where in the worst case it will take O(n) time to reach the statement causing a lag in the application.
Current application uses switch cases in the PerformExperimentAdapter;
@Override public Fragment getItem(int position) { switch (position) { case 0: switch (experimentTitle) { case "Diode IV Characteristics": return ExperimentDocFragment.newInstance("D_diodeIV.html"); case "Zener IV Characteristics": return ExperimentDocFragment.newInstance("D_ZenerIV.html"); case "Half Wave Rectifier": return ExperimentDocFragment.newInstance("L_halfWave.html"); } case 1: switch (experimentTitle) { case "Diode IV Characteristics": return ZenerSetupFragment.newInstance(); case "Zener IV Characteristics": return ZenerSetupFragment.newInstance(); case "Half Wave Rectifier": return DiodeExperiment.newInstance(context.getString(R.string.half_wave_rectifier)); } default: return ExperimentDocFragment.newInstance("astable-multivibrator.html"); } }
There is one downfall in using switch case in the context. That is the inability to use string resources directly as Java requires a constant literals in the evaluation statement of a case.
Resources:
- How Switch-Case works : https://stackoverflow.com/questions/22110707/how-is-string-in-switch-statement-more-efficient-than-corresponding-if-else-stat
- Hash Tables : https://en.wikipedia.org/wiki/Hash_table
- Constant Expressions : https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28