I'm using this library to show the main features of the app, currently I'm using shared preferences variable like this,
1- After installation I set a SharedPreferences variable x to 0
2- First time the user opens the main activity I check the variable x, if it 0 I use ShowCase
view and set x to 1
3- Now every time the user opens the app I will check x, if it's 1 I skip the ShowCase view
I'm new in Android and I'm not if it's good idea to check SharedPreferences on the main thread every time the app is opened, any one thinks I should be doing something else instead? or is this good enough?
It's absolutely ok. Of course it depends on time of retrieving of x variable from SharedPreferences. I suppose if you save few million variables in SharedPreferences then time of retrieving will significantly grow and user will notice it.
When you think about performance just test your case because general recommendations could not work in particular case.
Related
Everytime the application loses focus (whether manually by hitting the menu button, or by going to idle ) an APP_CMD_SAVE_STATE command is sent.
In the example shown from the Android API documentation for native activity (https://developer.android.com/reference/android/app/NativeActivity.html) , when this particular command is sent they are saving some sort of "state" inside their android_app .
// (...)
switch (cmd) {
case APP_CMD_SAVE_STATE:
// The system has asked us to save our current state. Do so.
engine->app->savedState = malloc(sizeof(struct saved_state));
*((struct saved_state*)engine->app->savedState) = engine->state;
engine->app->savedStateSize = sizeof(struct saved_state);
break;
// (...)
If you look in their code, savedState is just a struct holding values. First I thought that we need to save every single value that matters for our app everytime we lose focus, because otherwise the values would all become corrupt or something like that (yeah scary!)
I run a simple test by removing the code snippet above, and fortunately nothing changed, the values of my struct stayed the same after regaining focus even without saving them.
So I was wondering what is the purpose of this command ? Is that something important to consider ?
The APP_CMD_SAVE_STATE command is sent when your app loses focus. The aim is to make it possible to not only suspend your app, but, if the system has to kill the app to get some resources (e.g. free RAM), the app can be restored seamlessly next time the user returns to it.
If you look in their code, savedState is just a struct holding values.
Yes, from the point of view of the Native Activity, it's just a struct. But this struct is passed to Android in ANativeActivity_onCreate() function that's called via JNI (and usually it's implemented in android_native_app_glue.c from the SDK, which you could alter or replace if you need). Thus, Android will take care of the data when managing apps.
I run a simple test by removing the code snippet above, and fortunately nothing changed, the values of my struct stayed the same after regaining focus even without saving them.
Your test was too soft :) Try opening the Recents screen and close your activity from there: tap the × button or Close All command. The effect will be to kill the app, and you should now find that your data have been wiped unless you use the save-restore mechanism.
I'm programming an app using android studio. I want to know in which way I can do a tutorial that users will see only the first time that use the app. Tutorial like image or screenshoots
Can someone help me? Thanks
I encountered this thread while looking for a solution for running a tutorial only at the first time (as rbaleksandar suggested), so in case it will be helpful for someone someday, here's a template of a solution that works for me (using the SharedPreferences API):
#Override
protected void onResume() {
super.onResume();
String tutorialKey = "SOME_KEY";
Boolean firstTime = getPreferences(MODE_PRIVATE).getBoolean(tutorialKey, true);
if (firstTime) {
runTutorial(); // here you do what you want to do - an activity tutorial in my case
getPreferences(MODE_PRIVATE).edit().putBoolean(tutorialKey, false).apply();
}
}
EDIT - BONUS - If you're into app tutorial - I'm messing now with the ShowcaseView library (which is amazing - try it out). Apparently they have some shortcut for that issue using a method called singleShot(long) - its input is a key for the SharedPreferences, and it does the exact same thing - runs only in the first activation. Example of usage (taken from here):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_shot);
Target viewTarget = new ViewTarget(R.id.button, this);
new ShowcaseView.Builder(this)
.setTarget(viewTarget)
.setContentTitle(R.string.title_single_shot)
.setContentText(R.string.R_string_desc_single_shot)
.singleShot(42)
.build();
}
You could always code your own solution, but, let us not reinvent the wheel.
Check this Android Library:
Tour Guide Repository
It allows you to add pointers in your screen, so the user knows where is he supposed to touch next.
It's pretty easy to use, you only need to point to the element you want the user to touch.
From the doc:
Let's say you have a button like this where you want user to click on:
Button button = (Button)findViewById(R.id.button);
You can add the tutorial pointer on top of it by:
TourGuide mTourGuideHandler = TourGuide.init(this).with(TourGuide.Technique.Click)
.setPointer(new Pointer())
.setToolTip(new ToolTip().setTitle("Welcome!").setDescription("Click on Get Started to begin..."))
.setOverlay(new Overlay())
.playOn(button);
Hope this helps!
Some links to libraries for creating introduction and/or tutorial screens.
Horizontal cards like Google Now:
https://github.com/PaoloRotolo/AppIntro
Tutorial screen:
https://github.com/amlcurran/ShowcaseView
As far as I understand the question is not How do I create a tutorial? (as the people who have already posted an answer have concluded) but instead How to show a tutorial upon first launch only?. So here are my two cents on this topic:
I'm not familiar with how your Android app stores its configuration data but I will assume that it's either in a database (SQLite) or a text file (plaintext, YAML, XML - whatever). Add a configuration entry to wherever the app's settings are being stored - something like tutorial_on : false, tutorial_on : 1 etc. depending on the format the configuration is represented in.
The way configurations work is that whenever an app (or software in general) is launched it has to be loaded in the app itself. So add the following to your app (where and how is up to you and your app design):
Check tutorial_on entry
If tutorial_on is set to true/1 whatever
2.1 Display tutorial
2.2 Change tutorial_on to false/0 whatever
2.3 Store the result in your configuration
Continue using the app
By doing so the first time your app launches the flag responsible for displaying the tutorial will be toggled and afterwards every time you start the app the toggle flag will be read leading to omitting the tutorial.
Personally I would suggest that you an option similar to Don't show tutorial anymore along with a description how to re-enable it (by triggering some action in that app's menu etc.). This has two major benefits:
Improved user experience - users like to have control (especially over trivial matters such as showing or hiding a tutorial). Whenever you take the control away from them, they get pissed off.
Enable your user to re-learn forgotten things - a general rule of thumb is to create apps that should not burden the user with a lot of stuff to remember. That is why things should be self-explanatory. However sometimes you may want to do that nonetheless. By adding the possibility that the user re-launches (by simply resetting the tutorial_on flag and repeating the steps from above) the tutorial allows just that - refreshing a user's memory.
In my android app, I need settings to select time range (e.g. 2 to 4 minutes, 8 to 12 minutes etc).
To implement it, I used two instances of ListPreference, one to select minimum time and other to select maximum time.
As maximum time cannot be less than minimum time, I want to update the maximum time list preference whenever minimum time is changed by a user.
To achieve it, I am using Preference.OnPreferenceChangeListner. When user changes minimum time preference, the listener callback function is called and in the callback, I call setEntries(), setEntryValues() and setValueIndex() on maximum time ListPreference instance.
The problem is that GUI of maximum time preference is not updated immediately when I do above. I can still see old entries in the preference. If I exit settings activity and launch the settings again, I can see updated entries and values.
Please let me know how I could solve this issue.
Also, please suggest if there is any better way to handle such settings use case.
Thanks.
After some more debugging, I realized my mistake.
I did not read this document of OnPreferenceChangeListener callback:
"Called when a Preference has been changed by the user. This is called before the state of the Preference is about to be updated and before the state is persisted."
The problem was that I was querying the value of minimum time list preference in the preference change listener callback of it and generating the entries of maximum time list preference on the bases of that. But as the document reads, new value of minimum time list preference was not yet set in the callback, so the entries were generated on the basis of old values. So it was not supposed to work as I was expecting.
Sorry for not posting code as it required more effort to make the code ready for posting here.
Thanks for reading my question.
When I originally wrote and published my app, I was using a custom written activity to handle application settings. I used custom file name to store shared preferfences, like this:
getSharedPreferences("custom_settings_file",MODE_PRIVATE);
But now I'm refactoring my app and I would like to implement PreferenceActivity or PreferenceFragment and an xml file with PreferenceScreen section. Every tutorial or example that I've seen is using
getDefaultSharedPreferences(context);
to retrieve shared preferences, because PreferenceActivity assumes default filename to store preferences and there's no way to tell it to use a different one(at least I couldn't find one after an hour of searching and reading documentation).
So now I have a problem. If I just simply use the new default file, existing users of my app will lose their settings when they update the app, because the new application will not know anything about "custom_settings_file". What would be the best way to move the data from an old file to a new one on app update?
Here are the possible options that I could come up with:
Extend Application class and implement a piece of code in onCreate() so that every time my app is launched, it would check for existence of "custom_settings_file" and move it's contents to the new one. But running a block of code on every app launch seems like wasting too much processing resources for an operation that only needs to run once.
Just notify the user that their old settings are gone. But obviously this is not acceptable.
Is there a better solution, than option 1? Perhaps someone has already faced a similar problem?
What is preventing you from doing number 1 only once?
Just add a "migration" boolean to the new sharedpreferences.
If you also load the xml preference file then you can try this:
PreferenceManager.setDefaultValues(context, YOUR_PREFERENCE_NAME, MODE_PRIVATE, R.xml.preference_file, false);
If not (you want to add each preference item dynamically in your code) then you can do like this:
PreferenceManager pm = getPreferenceManager();
pm.setSharedPreferencesMode(MODE_PRIVATE);
pm.setSharedPreferencesName(YOUR_PREFERENCE_NAME);
In case you still want to use the defaultSharedPreference and process the migration then ... I'm writing this and I see Nicklas's answer, so I'm done here.
Could you add value in your new SharedPreferences that records whether you are a new install or an upgrade. If you don't have the setting in your sharedpreferences, check to see if you have an old preferences file in the way you were before. Then convert those preferences to your new method, and set your private setting indicating that it's been upgraded. Then just set the new value indicating the new state and you won't need to check your old preferences any more.
So I have this big stupid problem with the preferences in my live-wallpaper.
First, PreferenceManager.getDefaultSharedPreferences, doesn't work. I'm calling it in my Main class, a subclass of WallpaperService in the function onCreate. For the parameter, I first tried "this" and then this.getBaseContext(), but it doesn't matter. So, when I print the values, nothing shows up!
Second, I saw in another answer here that to put some default values, use something like PreferenceManager.setDefaultValues(this.getBaseContext(), R.xml.setting, true);. So, this, doesn't get my defaultValues at all. They're all zeros and even one values from my setting.xml doesn't show up in the list. I explicitly put a android:defaultValue for each of them.
Note that once I put values for each of them in the preferences, this problem doesn't happen. But still, for someone who installs my app, it needs to work on the first time it's launched.
Preferences are a bear. I always start with a working example, and then modify it to suit my needs; it's impossible to remember the formalisms :-). The "obvious" place to start is the "second" Cube example in the SDK, which uses a preferences activity to choose between cube and dodecahedron shapes. For something more sophisticated, you might wanna look at Moonblink's "Substrate" package, which combines multiple wallpapers, and has complex settings. Project home is here: http://code.google.com/p/moonblink/wiki/Substrate , then click Source at top left, then Browse, Trunk, Substrate, src, etc. GF