In my home screen replacement app, I have to get a list of all installed apps to put them inside the app drawer. Hence, the following method gets run on every app;
public static App fromResolveInfo (Context context, PackageManager pacMan, AppManager appManager, ResolveInfo resInf)
{
String label = resInf.loadLabel (pacMan).toString ();
String packageName = resInf.activityInfo.applicationInfo.packageName;
String activityName = resInf.activityInfo.name;
App app = new App (context, appManager);
app.setLabel (label);
app.setPackageName (packageName);
app.setActivityName (activityName);
AppIcon icon = null;
if (appManager.isIconPackLoaded ())
icon = appManager.getIconPack ().getIconForApp (app);
if (icon == null)
icon = appManager.getIconPack ().getFallbackIcon (resInf.loadIcon (pacMan));
app.setIcon (icon);
return app;
}
The problem is that there is a bottleneck here, and it's not he loading of the icons as I had originally anticipated. The first line of the method (String label = resInf.loadLabel (pacMan).toString ();) can take up anywhere between 0 and 250 milliseconds (on a relatively high-end device). On older devices, this becomes a real issue.
In my tests, I have noticed that when a slower device is multitasking and for some reason the app drawer has to be reloaded, it can take up to 30 seconds for this action to be completed (on all of the installed apps).
Caching could offer a potential solution for this, but then what if the name of an app changes (which occasionally happens)? I'd have to take the labels from the cache, and then loop over all of the apps in a separate thread and correct the labels where they have changed. This may offer a solution, but it seems more like a dirty hack than an actual good solution.
Is there any faster way to get the label of an app's activity? Also, why does it take so ridiculously long for Android to get an app's label, and/or is there anything that I can do about it?
You can get label as:
String label = (String) resInf.activityInfo.applicationInfo.loadLabel(pacMan);
If you compare Android source code for those two methods you will notice the one from applicationInfo has less code to execute. Maybe the bottleneck sits in the extra code. I personally never compared execution times for those as I never observed such issue.
To answer the original question "why?" ... As others have noted, the issue is that the label is localized, meaning it is read from resources -- from the app APK files, based on locale. But to me, this by itself doesn't explain the effect.
I have been developing an app that looks at installed apps, and on a 4-core armeabi-v7a system with some 150 apps, just getting a list of app labels alone takes around 10 seconds. It's painful.
I assumed it was using the ClassLoader to read resources from something like class files -- which can be very fast indeed -- hundreds of class files can be processed almost instantly on modern systems. Well, I don't think it uses the ClassLoader any more. But in principle...
A hundred or so little files should take much less than 10 seconds to process. That by itself couldn't account for the lag I see.
So I followed the calls down, through the creation of Resources objects, the opening of Assets, to finally retrieving that one label String. What I saw was layer upon layer upon layer of synchronized code. And all that is being called anew for each app label. Now, there is something that can make Java grind to a halt.
Of course it doesn't matter much if you're just fetching a single label. But it adds up, when you're fetching all of them.
I hoped to get to the bottom of it, and find something that I could call within one synchronized loop. But at the bottom of the android-29 source, within yet another synchronized block, I found a call to the SDK-specific nativeGetResourceValue(). That is, there is no way somehow re-roll that to be more efficient, and also run on other SDKs.
On the other hand... the OS can display lists of apps sorted by label very quickly. This means it maintains a table of app labels somewhere. Do we have access to that?
If there is some approach to obtain a list of app labels more quickly, I would love to hear it. (No, I don't need to hear about making my own cache -- which I might do anyway.)
Related
I am helping with an android app that involves keeping track of how much a person travels, and adding points for that person depending on the distance travelled. This means having to keep Data or internet access on the whole time.
The problem I am having with the app is that when the phone device is sleeping or the app is inactive for a long time, it will lose all the user information (username, e-mail, and point information). Even if I make the device use the method to track the person travelling, it will still lose the information after some time. Thus, it won't allow me to save the distance travelled data to the user.
I kept track of what causes this, and found that over time, the memory for the app would stop running, causing the user information to turn into null. I have tried finding solutions online, but the android developer website doesn't give any clear solutions. The closest I could find is this page about direct boot mode: https://developer.android.com/training/articles/direct-boot
I read over the page, but for some reason the application gets an error saying it can't run the code:
Context deviceProtected = appContext.createDeviceProtectedStorageContext();
The whole page just doesn't do a good job explaining how I'm supposed to use this code, or where I'm supposed to run certain code.
Does anybody know a better solution to my problem, or know how to properly use the Context class and Direct Boot to prevent app memory from being lost?
TL;DR How do I prevent my app from losing user/profile data, and keep certain methods/services running when the app is inactive for a long time?
I'm used to HTML development. Now I'm starting to program my first Android apps. In the tutorials I have read it looks like Android development favors using a new activity for each different form.
Nothing-less I think it's quite possible to use a single activity and use the setVisibility(View.VISIBLE|View.INVISIBLE) to show / hide GUI forms elements (This is much more similar to what I'm used with HTML-AJAX).
Is there something wrong with this way of development in Android?
Using a single activity(process) also allow to use singletons to share state and data between GUI components, while the multi-activity requires a "slightly" complex communication system using extra data to communicate the selected id, ...
I wonder what are the disadvantages of the single Activity "pattern" and why no tutorial/manual on the Internet use this technique to develop Android apps.
Do fragments have any advantage over showing/hiding views when I have no intention/interest to reuse the component?
Approach : Single Activity :
This approach will show/hide UI elements based on user interaction with app. Showing a UI Element draws View hierarchy starting from that element. This is called Layout Pass. This layout passes are expensive operation when performance is calculated. This is not advisable way to implement.
Approach : Single Activity, Multiple Fragment :
This approach will also have Single Activity but multiple Fragments associated with this activity. Each fragment defines new UI screen based on application requirement. More details available : Android Developer Guide : Fragments This is much advisable way to implement your requirement
I think there is nothing wrong, but depending on how complex your app will be, the source code can easily become very confusing!
Do you want those code happen:
elementXScreenA.setVisibility(false);
elementYScreenA.setVisibility(false);
elementZScreenA.setVisibility(false);
elementXScreenB.setVisibility(true);
elementYScreenB.setVisibility(true);
elementZScreenB.setVisibility(true);
And then, maybe after that:
elementXScreenB.setVisibility(false);
elementYScreenB.setVisibility(false);
elementZScreenB.setVisibility(false);
elementXScreenC.setVisibility(true);
elementYScreenC.setVisibility(true);
elementZScreenC.setVisibility(true);
No. I don't want to do that !!!
That just base on your ways for funny. There are many many disadvantages to do that, and I don't think there are any advantages in this approach. I can list some. Any comments will add to this list:
Design UI. How can you code multi layout on one xml layout file? Android Studio doesn't support this. You will see elements overlap elements
Performance. Load all your application UI is not an intelligent way. You lost memory, lost CPU. Although you set invisible, your memory still store those information, and when transition between elements, invisible elements still count into.
Maintainable. I'm working with a medium project, and still headache every day with bigger and bigger fragment and activity. (in case that each layout for each activity/fragment). How does everything become when you make all your layouts into one activity?
Collaboration. All layouts in one file. All your application in one file. How can you can collaborate between members? Code conflict, wrong edit ... Noooo. Stop that :)
No. Stop that. You just make element invisible when that element need this. For example, floating button when user scroll down list, error message textbox when no error need to show, ...
I have created a an application for a project - it's very basic... what I would like to do next is see how users are using my application e.g. buttons pressed, which page is viewed the most, for how long etc.
I am new to java and I do not understand how I can implement such thing; I have an idea but do not know whether it is efficient;
I would add a counter for each of the buttons in my app, whenever a button is pressed the counter increases by 1 and so on and so forth;
To see how long a user stays on a page, I could add a timer when the user enters the page, timer starts and stops when user exits.
...
Would something like this is viable and efficient? are there better ways of implementing such algorithm.
Not sure if there are, I searched but couldn't find any, does google offer such service like they do for websites with google analytic.
I am sorry, I've no to show this, as I haven't actually starting doing it. Wanted to get a grasp of it before I do and find out whether it is the correct strategy.
I would really appreciate your help.
https://developers.google.com/analytics/devguides/collection/android/v4/
Analytics for android apps maybe its what u are looking for
Start here: http://www.google.com/analytics/mobile/
https://developers.google.com/analytics/devguides/collection/android/v4/
You could also go with that you stated already, and add those values to an array. Just note that this will require you to turn on some permissions which might make your app unpalatable for some individuals.
We have a desktop client with several hundreds of users in our company. Sometimes it throws exceptions and crashes, but it's been hard to get the users to report their issues. To track these exceptions we are catching them and e-mailing the stacktrace and user specific data relating to the crash to a server wherefrom we then can view a log of all the crashes.
What would be really nice, is if we could log, not only the exception details, but also a screen recording video clip, of say the last 2 minutes up until the exception.
It shouldn't be very hard, all we need is some software that continuously records the screen and saves the video on drive, but erases everything older than a certain number of minutes. When the crash occurs we have can simply pick the current videoclip and attach it along with the exception details.
Anyone know of such a software, or anything similar that would solve our issue?
----------Solved:
I used both AndrewThompson´s and pjvds answers below. Andrews strategy outline, but with C# instead of Java, simply because our application is written in C#. The Code Project article pjvds linked helped me on how to do it in C#.
Here is one strategy:
Define a ScreenGrab object that encapsulates a BufferedImage and other relevant information (e.g. the time in millis or the mouse location).
Gain a screenshot using either the Robot or by establishing a BufferedImage the size of the content pane, and painting the content pane to the Graphics instance obtained from the image.
Create a ScreenGrab object and add it to an ArrayList
If the array list has exceeded a certain size, delete the first ScreenGrab in the list.
Rinse & repeat, perhaps at 2FPS, until an error occurs.
Either:
Use an adapted version of JpegImagesToMovie (uses the JMF) to transform the images (with pseudo mouse drawn in) to a MOV.
Zip all the ScreenGrab objects and send the archive instead.
Tweaks on this technique. The advantage of sending the ScreenGrab archive are multiple.
It can record the GUI perfectly, without the 'lossy' effect typical of JPEG compression.
If the user leaves the computer, neither the screen nor mouse position will change. So compare each one to the last and if the details are the same, skip storing it. The MOV would have to be at constant frame rate, but the Zip of custom objects could record at whatever rate best suits the user activity.
I remember I tried some code from a Code Project article years ago to accomplish the same. Capture Activities on Screen in a Movie.
We removed it from our software a release later due a lot of complains. People don't like it when their boss records their screen ;-)
I have developed a baby app where I need to lock all keys and ways out of the app, in order to be able to hand over the phone to my daughter. I used the "replace home screen" method to capture the home key, and that works great. All other hard keys (except power button, but that's not an issue since it's not easily pressed anyway) are locked. But the often discussed long press of home key is still launching the recent apps and offers a way out (which of course the daughter finds almost instantly).
I have seen other apps in market (toddler lock and more) work around this by emptying the recent apps list (or filling it with an icon that leads back to the baby app), but I have no idea of how to accomplish this. Anyone have a solution? How do I fill the recent apps from my app? Toddler lock even resets the recent apps after the lock-app is exited.
You could create an activity in your application that does nothing, and start it with an intent with the FLAG_ACTIVITY_NEW_TASK flag set. Fire this intent however many times you need to fill the history (my Incredible has 8 spots). For repopulating the history, look into ActivityManager.RecentTaskInfo.getRecentTasks (int maxNum, int flags)
See Documentation
It looks like you need to hold the GET_TASKS permission
The intents that originally fired those apps are stored as baseIntent, so you should be able to store them yourself(don't forget the extras), and re-fire them in order to repopulate the history list.
This is a hack, but it should work
Edit: After playing with this a little, it looks like you would need to have 8 different activities for this method to work, which is not realistic.
You need to do what is described in Mobius's post, but also set android:taskAffinity="" on the dummy activity elements in the android manifest file.