I'm trying to do a simple text game where the player has a weapon.
I want that, when clicking a certain option, the value that holds the weapon name "knife" gets updated to "sword".
I made a resources string that holds the "knife" value but can't seem to find a syntax that will update it.i already read that maybe you can't change resource values. Is this true?
If it is. How do I solve this?
Thanks.
It seems like you really need to go back and start with the basics of Android and Internationalization. It is not possible to update a resource at runtime, as you have correctly discovered, so it is your approach that needs to change.
Here is an example:
TextView text;
String value = getString(R.string.knife);
text.setText(value);
It seems that onClick you try to do something like:
setString(R.string.knife, "sword");
Which is impossible. Instead, you need to have the two strings as separate resources and then switch your value to the new resource when needed. So simply:
value = getString(R.string.sword);
text.setText(value); //and reset the display
For reference, if anyone stumbles upon the same problems, I found a good solution with Shared Preferences. It allows saving variable values in the device's memory.
Related
If I have a class that contains a static variable, say x:
class MyClass {
static boolean x = false;
// Other methods
}
Now let us say that, hypothetically, I set x = true; from my first activity. Is there any point through the rest of my app's life cycle (including various activities and threads) where this value will simple be 'reset' back to false due to how the 'Google JVM' or the android environment works? I have heard that static variables have a 'lifetime', that dies when the program dies. Do Activities count as separate 'programs'? What about services? Or even Widgets?
I am asking this because it is often difficult to share complex data structures that rely on other complex processing (like syncing data from an online database) in android due to how 'separated' activities are, and static variables are often a very quick and dirty solution to the problem. Other things I have tried include serialisation, but that doesn't really seem like a practical solution either (constantly serialising and decoding objects when the user navigates from one activity to the next seems like it would be very resource intensive).
If I am an evil person for doing this, please tell me what I am doing wrong, or even better, give me some links or examples of better ways to solve this problem.
Yes. There are times where that will reset. Primarily if the user leaves the app and starts fiddling around with other apps or if the user lets the phone go to sleep for a long period of time. The Android process could kill the actual app. Then the "state" of the app will be restored when the user comes back, however static variables will be at their defaults because the actual process was rebuilt.
Generally passing small objects between Activities and Services is done by overriding the Parcelable interface. This will allow you to save and restore objects using setOnInstanceState methods of both Activities, Views, and some adapters. They will likewise, have a restore method in which you can rebuild the object. Parcelable is preferable over Serializable.
Larger data may require a shared file or database depending on the data that you want to have synced. There is a 1 MB size limit for parcelables being passed between Activities. One common tactic is to save the information to a file and send a URI to the location of where the information can be retrieved.
Answering your question - yes, there is a situation when you set x = true and value will be 'reset' back to false. Well, not exactly reset but consider this scenario: you have an activity and a service. Service is using separate process (you can define that in AndroidManifest when you declare your service). Then those two processes (main app and service) won't share memory and setting x to true in your activity won't affect the value of MyClass.x in your service. In all other cases changing value in one place will be visible everywhere else. Hope it helps!
No, a static variable will not be changed unless you change it or the app ends, it is safe (but generally unclean) to use it. Closing the activity the variable lives in won't hurt it.
You suggest you just need to keep track of a value as you move around activities. In that case you can add the value in your Intents as what is called an 'extra'. If you need to also pass back the value after, android also has the startActivityForResult feature
Intent extras example:
x below could be any type of value including any object which implements Parcelable
Intent intent = new Intent(...);
intent.putExtra("myKey", x);
startActivity(intent);
in receiving class:
x = getIntent().getBooleanExtra("myKey");
Edit:
Given your additional comment - "lists of objects that contain yet more lists of objects" you may get a Parcel too large exception when trying to use extras, but this is an indication you have a bigger architectural problem and that there may be a better approach
Use Gson.
Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.
You have two options. Convert to string , then put data in an intent then pass to activity. Or Convert to string with gson, save to a preference, then in the other activity, check if the preference is alive and read from it.
If you wish to be bold, you can persist to database preferably using Realm for Android or ObjectBox is a new mobile object database optimized for performance. With ObjectBox, we are bringing technology from NoSQL server databases to mobile.
Lets say we have something like this in strings.xml:
<string name=“hello”>Hello world</string>
Now I want to set a value to a TextView using this string. Should I do it in java class like this:
TextView msgTextView = (TextView) findViewById(R.id.msg);
msgTextView.setText(R.string.hello);
or in xml file like below?
android:text="#string/hello"
Which approach is better? Or when it is better to use the first way and when the second one?
You should do neither. There is relatively new approach , called databinding (it was demo in 2015) and now this library is officially supported by Google. It is a manifestation of MVVM pattern and you should use it, because it limplifies your code and makes it more maintainable in long term. See https://developer.android.com/topic/libraries/data-binding/index.html . In few words- you create Java class with fields and accessirs and set its fields as xml attributes. By doing so, AndroidStudio will generate all .findViewbyId() boilerplate for you. you just create model and set it to that particular binding.
Regarding performance, it won't make any difference. I personally prefer to do it in XML, since it doesn't clutter your activity code.
Both approach is correct. If you want to internationalize your variable that time (change languages) both will be work. In reference of memory or speed dynamically change is correct(means using getResource() or R.string.hello).
at first you should set it in xml.(or leave it empty.) but if you want to change it when something else happens (for example when user click a button or anything else.) you should set it in java.
First method is generally used when you want your textview to be fixed and final .
Second method is recommended as the textview's value may change during the course of operation of app .Initially in second method , a value is shown by textview which shows its purpose or type . For e.g second one may be used in displaying progress of background task .
I'm new to Android development and I'm trying to make a calculator app in AndroidStudio. Originally, I used Buttons, and to retrieve the number of a button pressed, the function btn.getText() worked perfectly. I've since replaced the Buttons with ImageButtons, with the number now represented in the image.
My plan was to give all ImageButtons ids in the vein of 'btn0', 'btn1', and so on, then do something like
Character number = imgbtn.getId().charAt(imgbtn.length()-1);. This, however, fails miserably, as the id is apparently an automatically assigned int, and not the id I set.
Is there a way to access the string id property that I defined?
Alternatively, I saw mention of a getTag() function in my prior googling for solutions that looks like it might be useful in this situation, but I can't find an ImageButton tag property where I can set it.
Solved my specific issue: I just discovered that I can set the tag in the Text view, by adding android:tag="x" to the relevant ImageButtons (or that I could call imgbtn.setTag() to the same effect). I'm going to submit this anyway, in case someone has a similar issue in the future.
Lingering Questions
My question about accessing one's defined string id still stands. Is there a way to do that, in case I'd ever like to?
Also, what's an Object Tag, such as it would be used in imgbtn.setTag(<Object tag>)? I can't find any documentation.
At compile time, all resources are compiled in to a class called R.Java. When you say findViewById(R.id.xxx) what you are actually doing is pointing to a static reference of a final integer called "xxx" that has been hardcoded into this Java file. If you'd like to view this, navigate to the build directory after you've built your project and go to generated, source, debug (or release) then through your project until you see R.java
In other words, the String of the id is not present at runtime.
I've set up Content Assist to trigger on aAbBcCdDeEfFgGhHjIiJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ.() rather than only on .( (Under Window/Preferences/Java/Editor/Content Assist->Auto activation triggers for Java:) so that I can quickly select classes without pressing Ctrl+Space.
This was all good until I went back to creating variable names rather than using them, and it started suggesting a camel case variant of the name I just type, which doesn't yet exist, suffixed with the type! And of course pressing space afterwards uses this suggestion.
i.e. I type only the keys needed for
private static String HELLO = "hello";
I'll end up with the line
private static String hELLOString = "hello";
This comes under Java Proposals (Task-Focused), but turning this off under Advanced options obviously removes all the useful suggestions.
My aim is to allow auto-completion using known objects, not make them up, is there a way of doing this, and if so, How?
It looks like you're asking for code completion at a point (variable declaration) where there are no correct answers since only you know what name you want to enter. Eclipse does try to suggest a possible name, as you point out, from the already-entered type, but it can only guess.
Once you've declared the variable, Eclipse will be able to offer up that correct variable name later on in the code.
You can reduce the likelihood of accidentally selecting suggested variable names by increasing the 'Auto activation delay (ms)', and making sure that when you type a variable name you press [space] or [;] immediately afterwards before thinking about what to type next (if you haven't already).
Unfortunately there is no way (at least in the current Kepler SR1 release) of turning off variable name suggestion without also losing declared variable name suggestion, which is too useful to lose.
int foo = 0xff;
String label = getNameOfFoo(foo);
System.out.println(label);// this should print "foo";
private String getNameOfFoo(int n){
String ret;
///WHAT COULD I DO HERE TO MAKE THIS A REALITY?
return ret;
}
Before you jump on me with "Why in GOD'S name would you need this?!" I will say that my goal is get around Android's mechanism of identifying my View id's as strings (ie. "id=#+id/user_name") but having to get it back in my code as int user_name = R.id.user_name. This works fine when I know that there is a "user_name" label. But goes to crap when I don't. I'm trying to write a skinnable app that may or may not contain all sorts of things in the xml, and I need a way to inspect the ids as strings.
What you described can't be done in Java. Could you explain your real problem a bit more? I have made a skinnable Android application.
Edit: Does it help you if you can go from name to id instead? You can in that case look at this thread:
How do I get the resource id of an image if I know its name?
I did however not solve it that way, and don't see a need for it.
You can use Context.getResources() for this.
int resID = getResources().getIdentifier("label_name", "drawable", "com.test.app");
And the returned resID. If it's 0 then the label is not found. Read here for more about Resources.
I have an app which is somewhat skinnable; the user can select one of a set of drawable resources to use as a background and I did not wish to hard-code the drawable set. What I did is name the id of each drawable using an identifiable pattern, something like "background_X", where "background_" was fixed and X could be completely free-form.
I then used reflection on the R class to determine at runtime, each of the candidate backgrounds, and presented them to the user by resource ID. When the user made their selection, I stored the reflected name in sharedPrefs rather than the resource ID... this allowed updates (which could potentially re-number each ID) to retain the user's settings.
Reflection can also be used to convert the number (foo) into a name but you need to walk through everything in R.[attr|drawable|id|etc.].* to find the match, and if you add resources to the category you will run the risk of values changing.