I started a few months ago to program in android doing my first app that consists of taking orders like a waiters app.
As it was the first app you can imagine that i wasn't aiming for the optimization but that was a big mistake. I've deployed app in some restaurants and till this moment all was going well.
The issue:
Now the app was installed in a restaurant where they take a lot of orders for a single table they can get up to 10 minutes where they take orders and yesterday i've got a call where they said that the app was crashing on tables with a lot of people.
Now i'm trying to simulate what happened in my company.
The App:
The app consist of the Main screen where the user can choose to enter in settings or in the orders then there is another "login" activity and then the "main" where there is an alert that asks for the number of table then the waiter takes order and send it.
After sending i'm just "resetting" the activity or better by clearing the recyclerView out of items and settings all values to 0 but i think that it's produce a "little" memory leak.
Conclusion:
Now i would have as more as possible suggestions on how can i improve my app performance or better how could i prevent memory leak or even if it's possible to "recreate" the activity in someway after the waiters send the receipt so i could "save" some memory or idk.
Actually here is a screen of profiling, i don't know it it's could help
Good practices to avoid memory leaks IMHO:
avoid storing android context statically in helper or data classes
remember to unregister broadcast receivers once their job it's finished. A good practice is to register inside onResume() method and unregister inside onPause() method
prefer the usage of LiveData for your "model" classes
use LeakCanary library to detect any potential leak
be careful with the usage of static variables, remember to set them to null once are no longer useful to the application, that way they would be eligible to be garbage collected.
You can find an interesting article about this topic on Medium
First of all you seem to not have a CrashReport library on your app. So first thing to do is to add Crashlytics to your app.
Get clear, actionable insight into app issues with this powerful crash reporting solution for Android
Then if you think you have leaks on your app, I suggest you use CanaryLeak
A memory leak detection library for Android and Java.
Once Crashlytics in place you will know where the issue comes from. It can give you as far as the line of code that crashes your app.
Do you have any subscribers to events which is not unsubscribed? This is a common pitfall for memory leaks. I suggest that you use a memory profiler to profile the memory usage. This article gives you an introduction if you are using android studio:
https://developer.android.com/studio/profile/memory-profiler
As highlighted by the others, without specifics, it is hard to know what is the cause of the memory leak.
I wrote apps for Android tablet at restaurants in Beijing (Lily's American Diners), and I struggled with leaks for a long time. The problem is you have tablets Android tablets running for 14 hours a day so you have to have very robust architecture so things do leak and get torn down by the OS.
1) Canaryleak and Crashylytics are good ideas. I used ACRA.
2) Try to avoid popups, global variables, all the obvious things.
3) I use a background service to handle uploading data to the server, downloading menus from the server, printing to POS printers.
4) For network operations, use OKHTTP, it makes all the Async network operations cleaner.
5) For image loading, use Square Picasso. it makes all the image cashing cleaner.
6) In your lifecycle architecture,minimize activities. I use 1 single instance activity for the splash screen initial load and 1 single instance activity if they choose to do the manager operations, setttings, etc., then, there is 1 activity that runs the whole day long and handles everything. Within that activity, I use a ViewFlipper to quickly change "pages" (views) for each of the following operations:
a) choosing items from the menu
b) showing the ticket of selected items
c) showing large pics of the dish or special options for each dish
d) showing a successful sent order
e) showing an unsuccessfully sent order
f) showing the choose table screen for customers or waiters, whoever does it.
g) showing daily specials
The other big issue is persistent storage so orders and menus don't get lost, etc during the long running operation of these kinds of apps. i made extensive use of shared preferences.
Good luck.
There are many different possibilities, for example:
Database remains opened
Data cannot encapsulate properly.
From Shared Preference
These are common possibilities from where the data may leak.
Related
I am working on a note taking app and i am storing various images and texts using room persistence. I was wondering if it is better to keep updating the database every time user performs an action (like update the existing note) or is it better to do it at the end when the activity terminates or moves on to another activity.
What are the pros and cons of both the options.
Is there any better way than that ?
In my opinion you should update it on every action. Looks like this way google keep works to provide syncronization with server. And you should consider that your app can be closed without calling even onPause (e.g. due to some system crash), so this approach is more safe. So I don't really see any cons in updating database on every action.
IMHO one important thing is to never assume the users just stay within same app for more than 5 minute. They will switch to another app or do lock screen then leave your app for 30 minute and demand same exact screen when they come back to your app. If the activity already cleared by OS then... you know the rest.
So I'll definitely go with the first approach(update db for every action).
The best practice is to update your database on every change. If you worry about performance it doesn't have a sensible impact on your app performance. In applications with hundreds of database transactions per second like multipart download managers maybe it impacts the CPU and disk usage but your task is to slow for performance issues. Although you could use onStop() method to save data on the database before the user exit based on Android document but this work has no efficiency in your case and Android doesn't guarantee to call onStop in every situation.
I have an android app that needs to store critical information coming from a sensor. The sensor updates data every 5 ms. I need to persist each of these data points on internal memory in text files.
In the current scenario, I am collecting data points for 2 seconds in memory and then writing to the file at the end of 2 seconds to save battery life. However, under situations where the app crashes, I am loosing the critical data points.
Does anyone have any suggestions on how to handle this?
Is it a good idea to write the data point to the file every 5ms. Would this significantly reduce the battery life and increase the load on the CPU? If anyone has come across a similar situation, can you please share how you resolved the issue?
I would suggest you to study the reason of your app crash. If your app is crashing because of internal exceptions there is a better way of dealing with this thing.
Write a good exception management and use this blocks to write data to internal memory whenever there is an exception generated. Re-start the app after the data has been successfully written.
It you app is crashing because of external reasons and you are unable to catch exceptions, you have to think of some other way.
As your App is critical, I would look into setting up a DefaultUncaughtExceptionHandler by calling Thread.setDefaultUncaughtExceptionHandler in your Application class. This way in the handler, you can write all unsaved data, AND you can restart the app for continued handling of your critical data. I would put some seconds counter in there, to prevent an infinite loop of crashes. The Open Source ACRA library uses Thread.setDefaultUncaughtExceptionHandler, so you may get some idea from there on how to use it.
An additional idea is to write the data using a service in a separate process, search for "Remote Service". This way, even if the app crashes, the service will still be alive. You will have to setup some functionality on how to share the data between the app and the service. If the app is really critical, I would setup 2 remote services, one that gets the info from the sensor (and caches it as a backup until confirmed that it's written), and one that caches the data and writes it every few seconds. Each service should also have a DefaultUncaughtExceptionHandler as above. This is in addition to the actual app, that will have the user interface. Though it is a little waste of resources, but for critical data it is not wasted.
i donot think there's a good method. What more important is to avoid crash maybe
Instead of writing to a file every 5 ms, which will be a costly operation, you can save data to SharedPreferences every 5 ms and every 2 sec, save the data from SharedPreferences to a file. SharedPreferences content won't be deleted even if app crashes and hence you will not have any data loss.
I have a bug that I am unable to reproduce on command or from the emulator, but seems to happen after leaving the app alone for a long time in the physical device.
All fragments continue to be responsive, but messages seem not to be passed from one fragment to another.
My best guess, is that some sort of garbage collecting might be breaking the links. Very vague question, but I'm desperate:
What could lead to such a bug that happens "after a long time" (ie, hours)? What should I be looking for, in the code I write, if I suspect that the app isn't "restoring" successfully?
Also, adb logcat when physical device is connected via usb debug should show up any error messages that I print with log.e(), correct?
For future googlers and other novice coders -- Today i learned, Save references to fragments you create. Or, don't make fragments local variables. I didn't need the reference to the fragment, only the contained view. As a result, the fragment got garbage collected and a new one recreated on restore, hence breaking the communication link.
Sound like the activity (/fragment) is not save in the memory anymore - Android framework may destroy your activity any time it's in the background or backstack, and you should write your activities so they behave correctly when this happens. In order to beat this override onSaveInstanceState method.
You can cause it happen and try to reproduce it via developer options -> Don't keep activities
Does anybody know how big the overhead for services in Android is.
And if there are any other argument helping me with the following design decision.
I have two SQLite Dbs, one storing actual data (basically read only product inventory), the other storing settings, lists of selected items, etc.
Now I created a service to take care of manageing these databases, for two main reasons:
I want to be able to "save on close" (settings), which is possible with the onDestroy
It takes some time to load the data, so a quick close of the app keeps the data in memory
From a design perspective, I could either:
Create one service handling both DBs
Create two services, each handling one DB
It feels cleaner to create a seperate service for each DB, e.g. extending a generic base class to take care of shutdown, timers, etc. It also allows me to configure them independent (which is NOT required right now).
On the other hand, I do not want to start going down this road, and then, when I am used to doing stuff like this in "services" discovering that there is a limit of 3 or 5 services.
So how is the Overhead of e.g. 5 running services, vs. one service hosting 5 different features? Any ideas?
The number of services effectively supported by Android should be nothing to worry about in your situation. Having seen lists of running services in some task managers, I tend to say that up to ~100 "running" services should be no problem on most devices.
However, I'm not sure if what you're trying to do actually should be implemented in a service. Can you elaborate why you think you need a service?
I want to be able to "save on close" (settings), which is possible with the onDestroy
Can't you do this in your normal Activity lifecycle callbacks?
It takes some time to load the data, so a quick close of the app keeps the data in memory
What do you mean by "quick close"? Are you trying to build some sort of cache for the DB data?
From the Android dev docs...
Use services sparingly
http://developer.android.com/training/articles/memory.html#Services
If services are RemoteServices then they are launched in a separate process which add overhead and is memory intensive.
Try using a single service for both the scenarios.
I understand why an always-on service is normally an anti-pattern in Android, but my app really seems to be begging for one:
On first load, the app has to go through potentially thousands of small entities from the database to construct the initial state. There's not much data brought into memory (most is lazy loaded later), but that first scan is unavoidable by the nature of the app. This scan can take at worst 6-7 seconds with slow hardware and a big dataset, average is probably around 3. The app is a "impulse use in short bursts" type of thing, so those repeated loads are really not desirable.
I think this begs for a background service to be perpetually alive and holding that state, thus avoiding that load time. It will always be ready to be killed, and not in the foreground, so should the system or user decide that they have it out for the service, no harm is done. But if the service is left in peace, the app will start instantly, and in my case that does a lot for the user experience.
Am I still wrong?
I think this begs for a background service to be perpetually alive and holding that state, thus avoiding that load time.
As the British say, bollocks.
On first load, the app has to go through potentially thousands of small entities from the database to construct the initial state.
Then fix that. Either simplify this work, or persist the initial state in a simpler form for later reuse (e.g., JSON).
If it is OK for you to use a cached result of this work that is held in RAM, it is OK for you to use a cached result of this work that is held in an easier-to-read-in persistent data structure.
An "always-on" service would essentially act like a daemon process and there are plenty of services on Android phones that never turn off.
In this case, though, it seems a better solution would be to simply have a splash screen and/or wait dialog that sits there until the data is loaded. It seems like a bad idea to me to take up resources when the app isn't running just so the app will load faster when the user finally opens it. If the average use of the app is much smaller than the load time, then it would probably be even better to speed up the scan in some way.
People use taskkillers to kill such kind of services. My view is, that when you make the user aware of why your service is running (say, this will load the app quicker), he will understand it and not kill it. You could also ofcourse add an option to use the service or not.