Change Android app language with out restarting the app using Restring library - android

I am using Restring library to load localized strings on my app. And I am able to load localized strings from the api and display it on the app, with out any issues. But the pitfall is every time the language is switched, I have to restart the app, then only the language is updated on the app. But I need to achieve it without restarting the app. Any help is appreciated. I already referred some links, which I am providing below,
https://proandroiddev.com/change-language-programmatically-at-runtime-on-android-5e6bc15c758
https://medium.com/#hamidgh/dynamically-change-bundled-strings-a24b97bfd306
Change app language programmatically in Android
Note: Restring uses SharedPreferences as the String Repository, so
when ever getString(id) method is invoked, it'll provide the string
matching the id from its SharedPrefernces repository.

I would recommend applying View-Model in your android app architecture, A View-Model's major role is to survive configuration changes (which includes but are not limited to orientation changes from landscape to portrait and vice-versa, surviving drastic changes in app's performance stats like power-drain and many more) so you will not need to restart yoour app + additionally use live-Data which is Activity/Fragment aware so it will only update your data of the app when it is in foreground.
There are many YouTube videos specifically teaching these things, I would recommend watching "coding in flow" YouTube channel's MVVM architecture.
It will definitely give you an idea how to continue with your app, it is only 10 videos long but for your requirement first 5 are enough.

You can use a new version of Restring (based on the one you are using) from here:
https://github.com/B3nedikt/restring
It includes a method to update your activity without any restart.
Restring.reword(rootView) will look into all child views of "rootView" and update strings
Restring.setLocale(Locale.FRENCH);
// The layout containing the views you want to localize
final View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
Restring.reword(rootView);
It also explains how to make sure each activity will get the desired strings when created:
in all activities, add:
#Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(Restring.wrapContext(newBase)));
}
#Override
public Resources getResources() {
return Restring.wrapContext(getBaseContext()).getResources();
}

Related

how to save the reached level in a quiz app

I'm new to kotlin and android app developpement in general and I want to make a Quiz app with jetpack compose not XML, and this app has multiple levels and when the user starts the quiz if he decides to stop playing in a certain level and quit the app i want to save that level so next time when he come back to play he's gonna start from the same level he stopped.
I've tried to use preference datastore but it doesn't seem to work.
this is my Datastore class:
Datastore
this is how I store the current level:
save current lvl
this is how I get the lvl I stored in the datastore:
get stored lvl
if you have any idea what I'm doing wrong please and if posibile use jetpack compose.
thank you.
You should post code, not images. Although in this case, you can see from your second image that saveScreen is a function you're never calling anywhere, because it's grey (i.e. it's never used anywhere), and there's a yellow underline giving you a warning too.
You'll have to call saveScreen() or saveScreen.invoke() somewhere. Why not just make it a normal function though?
// call this when you want to save the screen
private fun saveScreen() {
// scope.launch { datastore.Save etc }
}
Unless doing things this way is a Compose thing (I've never used it). Either way, that function you're defining isn't called anywhere, so your screen isn't being stored!

Tutorial first time you enter into an app?

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.

Change the title of Paypal PaymentActivity class

I included paypal sdk in the app and set the product name and price as shown in the attached image.
Is it possible to change the title of the paypal PaymentActivity class . ?
I used the entire code for paypal from this link
.Please suggest whether we could change the title to any text ,(I want to change the text that is marked in Red Circle)?
Jeff here from the PayPal Mobile SDK team.
The PayPal Android SDK doesn't support modifying any of the SDK activities. We don't plan to allow the ability to modify titles, as this would be an inconsistent user experience. However, we're open to feedback from users, so please feel free to file issues in GitHub if you have feature requests!
Couple observations, apparently:
The activity of off which you have put screenshot is PaymentMethodActivity (according to Hierarchy Viewer)
PayPal SDK uses ABS
According to the sample app provided in PayPal SDK page, onBuyPressed() launches PaymentActivity with startActivityForResult():
Now, according to SDK references, PaymentActivity does not provide any API for setting custom title. The page lists setTitle() as a part of "Methods inherited from class android.app.Activity", but does not give any details on how to extend PaymentActivity so that one could leverage those APIs.
So, currently, there is no way to use a custom title.
I personally would not bother to change the title on that screen as it clearly depicts itself as a PayPal screen (as one would see their homepage on a browser), but if you really want a custom title, you may need to file a new issue on their GitHub page.
Your AndroidManifest.xml file should have an entry for the PaymentActivity that looks like this:
<activity android:name="com.paypal.android.sdk.payments.PaymentActivity" />
All you should have to do is add the label attribute to that to change the title:
<activity android:name="com.paypal.android.sdk.payments.PaymentActivity" android:label="#string/some_title" />
For other potentially useful attributes, refer to the activity tag documentation.
Note: I'm assuming here that the PayPal SDK will allow you to override the title. That is, I would expect it to only set a default title if none is given explicitly.
Edit: Unfortunately, the assumption above has proven to be incorrect. Diving a little deeper, it turns out every activity in the PayPal SDK always sets its title in the onCreate() method. That's actually a little surprising, because that means that PayPal isn't leveraging Android's built-in support for localisation and resources. Although I suppose it does allow them to offer developers the SDK as a jar, which doesn't support bundling Android resources.
In any case, since the various activities haven't been declared final, you could simply try to extend them and set the title after the super has done its work:
public class TitlePaymentMethodActivity extends PaymentMethodActivity {
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("Custom Title")
// or:
setTitle(R.string.custom_title);
}
}
After that, you'll have to change the manifest to point to your TitlePaymentMethodActivity, in stead of directly to the activity in the SDK. Do note that this approach may break at any point, if PayPal decides to finalize the activity classes. With that in mind, I suggest you follow #shoe rat's recommendation and file a request with PayPal for 'official' support.

Customizable input fields in an android app

I'm working on a project for my university about customizing an Android application on runtime.
Is it possible to include layout XML files that are actually not in the \res\layout\ folder of my android project but on an external webserver?
The idea behind this is to give me an opportunity to customize the xml-file on my webserver, e.g. adding new fields, without having to re-install/update the app.
I'll try to explain my idea with the following example:
Let's say I got an application to save and display addresses. All addresses are stored in a database. I got the fields 'name' and 'surname' in my database and displayed in the app when saving or displaying the addresses.
Now I would like to add a third field 'email' where I can enter email addresses.
My idea is to create this field in my database and add it to my layout-xml-file which is on my webserver. So I can 'link' the xml file within the app and the new field appears after refreshing the app.
Hope you guys can give me some information about how to customize my input forms on runtime, my research on the internet didnt help me out at all..
Greetz
You can't use external XML files to dynamically adjust the layout.
The documentation of LayoutInflater#inflate(XmlPullParser, ViewGroup) explains why:
Important For performance reasons, view inflation relies heavily on pre-processing of XML files that is done at build time. Therefore, it is not currently possible to use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
But you can create your layout dynamically in code, see e.g. Android Runtime Layout Tutorial
So you could put a file on the server that holds layout information, fetch it in your app, parse it and create the layout dynamically. It is going to be a lot of work since you would basically replicate Android's LayoutInflater. You can obviously simplify the format to just the basics that you need but it's still a lot of work that is IMHO not required.
Let's assume your layout info is just a plain text file that has name of fields
name
surname
email
You can then read it line by line and create a simple EditText for each in a way like
private View getDynamicLayout(ArrayList<String> lines) {
LinearLayout ll = new LinearLayout(this);
for (String line : lines) {
EditText et = new EditText(this);
// fill it with some text
et.setText(line);
ll.addView(ll);
}
return ll;
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayList<String> layoutConfig = readConfigFromFile();
View layout = getDynamicLayout(layoutConfig);
setContentView(layout);
}
But unless you really need that, I would suggest that you update the app the regular way. It is also faster to use preprocessed layouts instead of building that info on your own.
Also take care not do heavy disk / any network access in the UI thread like in above example (reading the file). That should be done in a background task.
Thanks a lot for your help. I'll try to get through this.
The reason I can't just update the app is that the app I'm talking about is actually a CRM system used by many different companies. They all have to download the same app from the google play store.
The goal of my work is that every company can customize their input forms on their own, so there could be many different input forms (each for every company) but all using the same app.
I thought about a server that stores a file with the layout information which can be accessed by the app on runtime.
btw, since I'm not a software engineer, I don't have to write any code, I only have to describe the concept in an abstract way.. :)

Android Spinner - System view VS User view

I have been creating Spinner controls (Combo boxes/Drop downs) in one of my apps, and was surprised to find out how difficult it was to achieve all of the following features:
User facing Strings are externalized, taking advantage of strings.xml internationalisation (I18N) feature of Android.
Spinner selections operate using a System view, which facilitates not having to work with or map Strings to meaningful values (yuck).
User view to System view mapping should be easy, automated and minimal (i.e not hand rolled for every component).
Others have attempted solutions to this, but universally as far as I could see they suffer from one or many of the following problems:
UI code is creeping into their enum class which doesn’t belong there (messy), nearly all existing solutions suffered from this.
Hardcoded User facing Strings in their enum classes. Because these are not externalized you cannot do I18N using the stock Android features.
Authors typically make the Fragment or Activity an OnItemSelectedListener which perpetuates a common problem of inheritance for convenience, where composition is more appropriate.
I have developed my own solution which does this: http://www.androidanalyse.com/android-spinner-externalize-user-strings-mapped-to-system-enum/
My question is, have I missed something? This seems like something that should not have been this hard (which makes me feel like I'm possibly reinventing the wheel).
Below is some example code showing my solution in-use (which is available Apache 2 license from the link above).
String none = getString(R.string.none);
String light = getString(R.string.light);
String medium = getString(R.string.medium);
String strong = getString(R.string.strong);
SpinnerUtil.createNewSpinner(view, R.id.wind, Arrays.asList(none, light, medium, strong), WindLevel.values(),
new SpinnerItemSelectedListener<WindLevel>() {
public void onItemSelected(Spinner item, WindLevel value) {
// Take whatever action you wish to here.
}});
I would just use ArrayAdapter<WindLevel>. Yes, you created a custom typed listener, but the regular event listener gets the position and can call getItem() on the ArrayAdapter<WindLevel> to get a WindLevel properly typed.
IMHO, the vast majority of Spinner widgets will be populated with material read in from a database, the Internet, or some other dynamic data source, rather than populated by some sort of enum with display values coming from static strings that can be internationalized ahead of time.
This is not to say that your code is useless: if you find it useful, then it was worth writing. And I am sure that there are apps out there that contain your targeted pattern (i.e., a Spinner backed by an enum or equivalent where the display values are known in advance and can be internationalized) who might find your solution useful as well. Every developer who writes enough code cooks up these sorts of helper classes and the like that help map an OS or framework model into something that better fits the developer's own mental model. So long as you are not perceiving any performance issues, it's all good.
Also, note that OnItemSelectedListener is an interface; implementing that interface on an existing class is not inheritance.
I believe the reason nobody answered you is :
What problem are you trying to solve ? Spinners existed prior to your well designed attempt.
Why reinvent them in exactly the same way they exist in Android ?
http://developer.android.com/guide/topics/ui/controls/spinner.html
It is a beautiful wheel indeed you designed, but still, it is just a wheel :)
UPDATE :
I think I begin to understand what you did. This is interesting. I'm not sure why you did not go to the pattern implemented by the ListPreference with its entries and entryvalues.
In fact, I'm not sure I understand why the Android team did not go that route either.
In any case, it is worth proposing your idea to the Android framework. It is after all open source.

Categories

Resources