In a recent webinar, we welcomed Olivier Le Goaër, Associate professor at Université de Pau et des Pays de l’Adour (Pau, France), to discuss greenIT for mobile applications (replay is available in French here). Indeed, Olivier started in 2019 to work on a project to make native mobile apps more sustainable, environmentally, and socially acceptable.
He aims to build a repository of best practices for developers that can be detected in the source code so they’re all actionable and low-level. So he voluntarily excluded rules and best practices that can’t be detected, for instance, if they’re too high level. At this date (Feb 2023), this knowledge base only targets Android, but an announcement was made about iOS support, meaning new rules will come on iOS. He came up with a repository of 42 coding rules.
Note: make sure register to our next live sessions for more best coding practices.
To provide insights into the content of this repository, let’s browse some of the code smells you might find in your Android code.
You can request tasks to be executed in the app with the WorkRequest class:
WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class).build();
WorkManager.getInstance(myContext).enqueue(myWorkRequest);
But we can also use Constraints on these WorkRequest, for instance, to indicate this task should be run only when the device is charging (plugged):
Constraints constraints = new Constraints.Builder().setRequiresCharging(true).build();
WorkRequest myWorkRequest = new OneTimeWorkRequest.Builder(MyWork.class).setConstraints(constraints).build();
WorkManager.getInstance(myContext).enqueue(myWorkRequest);
It allows delaying computations for later when it makes sense and so sparing energy.
The Android API provides services to get the GPS coordinates of a device, and listens for regular updates of their values:
import android.location.LocationManager;
LocationManager locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
But there exists an alternative with an API maintained by Google, claimed to be less consuming:
import com.google.android.gms.location.FusedLocationProviderClient;
FusedLocationProviderClient fusedClient = LocationServices.getFusedLocationProviderClient(this);
fusedClient.requestLocationUpdates(mRequest, mCallback, null);
Frame rate has a direct impact on energy consumption. 60 fps is the default value, so be careful no putting a value higher if it’s not relevant:
Surface s = mySurfaceView.getHolder().getSurface();
s.setFrameRate(90f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);
In case it’s acceptable for you, decrease this value to 30 for instance:
s.setFrameRate(30f, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE);
Android has native smart mechanisms to optimize battery consumption. So unless you have good reasons, we should not ask permission to ignore them:
By default, your OS will turn the screen off when users get idle with their devices. You can tune your Android app to always keep the screen on, but this will have a tremendous impact on the battery, so you should avoid it if your context allows it:
...
You can register to a sensor to listen to its values (such as the Accelerometer):
sensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE);
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, accelerometer, 20000);
But it’s important not to forget to unregister; otherwise, your app will continue to receive and compute data even in the background. So to avoid this, you need to unregister:
...
sensorManager.unregisterListener(this);
Similar to the previous example, when calling the registerListener method:
sensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE);
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(this, accelerometer, 20000);
You can choose to overload the call with a 4th parameter called maxReportLatencyUs:
sensorManager.registerListener(this, accelerometer, 20000, 190000);
The documentation describes this as the “Maximum time in microseconds that events can be delayed before being reported to the application. A large value allows reducing the power consumption associated with the sensor”. A value of 0 means calling the first method above. Think of sending events as a single batch instead of multiple small batches.
To avoid “software obesity”, meaning embedding too many unnecessary components, you should try to restrict the version ranges of the SDK versions:
android {
defaultConfig {
applicationId “com.example.app"
minSdkVersion 7
targetSdkVersion 23
versionCode 1
versionName “1.0”
}
}
This one is not Android-specific but concerns almost all mobile applications that embed images. WebP is an optimized format that should be favored for every image.
$> ls
…/res/
…/res/drawable/
background.png => prefer background.webp
logo.jpeg => prefer logo.webp
This knowledge base of best practices can be theoretically implemented in static analysis tools. For instance, an implementation called ecoCode Mobile exists for SonarQube., if you want to give it a try. This catalog is also available on our public Hub of best practices, and can be used in Promyze.
If, in your context, greenIT is a significant concern and your organization aims at raising developers’ skills on that topic, Promyze can be an excellent alley to centralize and share your best greenIT practices in your context.
Also, make sure register to our next live sessions for more best coding practices.
Promyze, the collaborative platform dedicated to improve developers’ skills through best practices sharing and definition.
Crafted from Bordeaux, France.
©2023 Promyze – Legal notice
NEW: Introducing AI for generating coding practices and discussions for your Promyze workshops |
Social media