Java - dynamically build textview reference - java

New Android/Java coder. Trying to replicate in Android app a project I built in MS-Access.
I have a layout with similar named TextViews, like text10, text12, etc. In MS-Access I can dynamically build those names with collection referencing:
For X = 10 To 15
Me.Controls("text" & X) = Null
Next
There is no array required. So looking for structure in java that can accomplish the same functionality.
I want to dynamically set background color of multiple TextView based on two inputs. One is to build TextView reference and the other is a state indicator that will determine color.
Here is one procedure calling setSubColor:
public void Clear(MenuItem mi) {
puz.setText("");
sol.setText("");
for (int i=0; i<26; i++) {
setSubColor(aryA[i].charAt(0), 0);
What I have so far for setSubColor:
public void setSubColor (char c, int i) {
TextView v = (TextView) >>>dynamically reference v using name built with ("tv" + c)
if (i == 0) {v.setBackgroundColor(Color.TRANSPARENT);}
else {v.setBackgroundColor(Color.YELLOW);}

You can get the res id from the res name at runtime. So if your textview had name "text1", you could get the integer id by using:
int id = getResources().getIdentifier("text1", "string", getPackageName());
TextView view = findViewById(id);
But do so only as a last resort, it's error prone, slow and somewhat of an anti pattern.
EDIT by OP: No matter what the name argument is always returns 0 but marked as answer because it led to the following code that works exactly as I want, anti-pattern or not.
TextView v = (TextView) findViewById(getResources().getIdentifier("tv" + c, "id", getPackageName()));

Instead of the TextView Id field use its Tag field.
String tag = (String)textView.getTag() and textView.setTag(Object tag) with tag instanceof String
then you can find the TextView by Tag

Related

How can I get and set a string resource dynamically in a for-loop using a findViewById() method?

In my app, I want a counter from 0 to 8 to decide the number of players in a game.
Below there are 8 possible fields to write a name inside, which are all set to invisible. If the players-counter is set to 3 players, there should be the first 3 fields visible. Depending on the actual number of the counter, the visibility of the fields changes (1player = first field, 5 players = first 5 fields).
When the +1 (player) button is clicked, a certain method is activated. I tried to run a for-loop everytime the button is clicked. In this for-loop from 0 to "whatever amount" (max. 8 players) the actual fields should be found with "findById" and set to visible.
I tried it with a string resource (.xml) and I can get the text of the resource but with my thought process, I have to update the string resource to every number of the field (if 3 players: "field_" + "1", "field_" + "2", "field_" + "3").
How can I get and (most importantly) set/update a string resource for this specific purpose?
(Switch is too inefficient and I can't use a string with the findViewBy Id()-method by updating the String (not string resource) like mentioned before.
Please help, and accept the fact that I'm new to Android Studio for one week!)
You can use "getIdentifier" which takes a String parameter. So you can set the type as "id" in the second parameter of this method. This method returns the id of the view you want, but beware, it will throw a "FATAL EXCEPTION" if the id of the View doesn't exist. With this id, you can use findViewById to fetch the TextView and change its visibility. The "getIdentifier" method can be called from the "getResources()" method.
Below you can see what it would be like to make visible a TextView that has the id "textView1":
int id = getResources().getIdentifier("textView1", "id", getPackageName());
TextView textView = findViewById(id);
textView.setVisibility(View.VISIBLE);
Below you can see how you would make 8 TextView with id 1 to 8 visible:
TextView textView;
for (int i = 1; i <= 8; i++) {
int id = getResources().getIdentifier("textView" + i, "id", getPackageName());
textView = findViewById(id);
textView.setVisibility(View.VISIBLE);
}
So, just put the limit at i <= x , with x being the limit of players who will play:
TextView textView;
for (int i = 1; i <= totalPlayers; i++) {
int id = getResources().getIdentifier("textView" + i, "id", getPackageName());
textView = findViewById(id);
textView.setVisibility(View.VISIBLE);
}
Do you just want to make some EditTexts visible and others not? Personally I'd keep it simple, do the lookups once (in onCreate or wherever) and store the references in a list. Then when you need to display n fields, you can just iterate over the list and set the first n to VISIBLE and the rest to INVISIBLE.
I feel like it's fine to just list all the EditText IDs (R.id.field_1 etc) and generate your list of actual Views from that, but if that repetition bothers you, there's a few things you could do. Like:
set a tag attribute on each field in the XML, and use findViewWithTag to look them up, generating the lookup strings programmatically, like "field_" + i
do a similar thing with the resource ID, like in #Moises's answer
lookup their containing layout, use getChildCount and [getChildAt] to iterate over the views in that layout, and use isInstance to collect all the EditTexts in order3
create and add the EditTexts in code - you probably don't want to do this, but you could!
I'm not really sure what you mean about the string resource or what you're trying to do - I'd honestly just make a list of R.id.field_1 etc, iterate over that to do findViewById on each and store those in a new list, and you're done. Also my Java's a bit rusty so sorry no example code!

Dynamically add TextViews to FlipperView with varying ScrollY

I am developing an app and have begun learning Java a few weeks ago. At this point, there's something that I'm trying to get to work, but I can't figure out what's going wrong.
So the problem is as follows. I have a FlipperView in which I want to dynamically add TextViews between which I should be able to navigate. These TextViews have the same content and layout, the only difference between them is their "ScrollY" attribute. I want the first TextView to have a ScrollY of 0 so that the text can be seen from its beginning. Then, I want the next TextView to have a ScrollY of 0 + x, where x is the height of the TextView (which is originally defined as match_parent). The next one should have a ScrollY of 2x, etc.
I've tried many things to get this work. First I managed to dynamically get the height of the TextView using a .post. For now, I can change the ScrollY of the first TextView. For additional views, I'm using a for a loop. At this point, TextViews are properly created and I can navigate between them with the FlipperView. However, the SetScrollY function doesn't work inside the for loop. I've tried to feed it with an arbitrary integer instead of the dynamic height of the TextView without success, so I guess the function is not working at all in this case. Here's my code (the number of loops is fixed for now):
public int formatText(Context context, ViewFlipper textFlipper) {
int nbOfViews = 1;
final int[] viewMaxHeight = {0};
final int[] lineSpacing = {0};
textContent = context.getResources().getString(R.string.dummyText);
final TextView flipperView = new TextView(context, null, R.style.flipperText);
flipperView.setText(textContent);
textFlipper.addView(flipperView);
flipperView.post(new Runnable() {
#Override
public void run() {
viewMaxHeight[0] = flipperView.getHeight();
lineSpacing[0] = Math.round(flipperView.getLineSpacingExtra());
}
});
for(int i = 0; i < 2; i++) {
TextView flipperViewExtra = new TextView(context, null, R.style.flipperText);
flipperViewExtra.setText(textContent);
flipperViewExtra.setScrollY(viewMaxHeight[0] * nbOfViews + lineSpacing[0]);
textFlipper.addView(flipperViewExtra);
nbOfViews++;
}
return nbOfViews;
}
Any help is appreciated, thanks!
You are working with THREAD and thread tends to optimize the performance by caching the using variables. Hence any chance OUTSIDE the thread it won't "see" the change in memory. To coerce the thread to look at the change in memory you have to declare the variables to volatile. Example
final volatile int[] viewMaxHeight = {0};
final volatile int[] lineSpacing = {0};

FindViewByID with a variable

I have a CardView in AndroidStudio with different ID's for each card. To search the different ID's i have made this:
for (int f = 0; f < mainGrid.getChildCount(); f++) {
if (f == count) {
int index = f;
String id = "food"+index;
foodName = findViewById(R.id.id);
foodName.getText();
}
}
But at foodName = findViewById(R.id.id); says that "Cannot resolve symbol id"
There's any other way to do it?
No matter how many times you loop, if you do not have a view named id in your layout, you will get the error you are getting.
You cannot use a variable called id and then tag it onto R.id.id (which resolves as a numeric id value)
If you want to find a view when you know only its name, see this:
Find view by name

setText crashes app when trying to display byte values

I'm working on a android app that send and recieves data. In the app i have a button an a few texviews. When i press the button then data (two chars) will be send. And an the data that has been send will be shown in two tekst views.
I did the same with two integers and that worked now i want to do the same with bytes and chars and that failes.
The logcat gives the following error:
10-28 09:27:19.338: E/AndroidRuntime(13138): android.content.res.Resources$NotFoundException: String resource ID #0x0
Beloww is the onClick lisener code:
#Override
public void onClick(View v) {
// Control value
ArrayOutput[0] = 'B';
ArrayOutput[1] = 'B';
//Creating TextView Variable
TextView text = (TextView) findViewById(R.id.tv);
//Creating TextView Variable
TextView statustext = (TextView) findViewById(R.id.status);
//Sets the new text to TextView (runtime click event)
text.setText("You Have click the button");
// Convert string to bytes
ArrayOutput[0] = ArrayRecieved[0];
ArrayOutput[1] = ArrayRecieved[1];
final char Byte1 = (char) ArrayOutput[0];
final char Byte2 = (char) ArrayOutput[1];
final TextView Xtext = (TextView) findViewById(R.id.xtext);
final TextView Ytext = (TextView) findViewById(R.id.ytext);
Ytext.setText(Byte1);
Xtext.setText(Byte2);
try
{
statustext.setText("Sending....");
server.send(ArrayOutput);
statustext.setText("Sending succes");
}
catch (IOException e)
{
statustext.setText("Sending failed");
Log.e("microbridge", "problem sending TCP message", e);
}
}
});
Does anybody have a sugestion what the problem might be? Any suggestions is welcome! if i need to supply more information please say so.
Update
Thanks you all for your suggestions! For the onclick function it works! I tried to do the same for the recieve function. This event handler funnction is called when there is data avalable.
When i use the setText function it crashes my ap after a few cycles, in this function i have three settext operations. only the first one is called (then the app crashes). When i change the ordere of these operations then still only the first one is called. Could it be that the app displays the first settext operation but crashes? I use dummy data, so when the eventhandler function is called the actual recieved data is not used, but still the app crashes after the first operation. Does anybody have a sugestion?
On the other side data is send every second.
Below is the onRecieve (event handler)function:
#Override
public void onReceive(com.example.communicationmodulebase.Client client, byte[] data)
{
Log.e(TAG, "In handler!");
//Control value
ArrayRecieved[0] = 'C';
ArrayRecieved[1] = 'B';
if (data.length < 2){
return;
}
// Set data that has been recieved in array
//ArrayRecieved[0] = data[0];
//ArrayRecieved[1] = data[1];
char Byte1 = (char) ArrayRecieved[0] ;
char Byte2 = (char) ArrayRecieved[1] ;
TextView Xtext = (TextView) findViewById(R.id.xtext);
TextView Ytext = (TextView) findViewById(R.id.ytext);
Xtext.setText(""+Byte2);
Ytext.setText(""+Byte1);
TextView textRecvStatus = (TextView) findViewById(R.id.RecvStatusText);
textRecvStatus.setText("In handler!");
}
});
TextView has two methods like
TextView.setText(CharSequence) and TextView.setText(int).
1) first method directly assigns a text to TextView which is passed as CharSequence (can be String,StringBuffer,Spannable...)
2) second methods searches for the String resource that you define in Resources with ID passed as parameter.
and you are passing char as parameter. this char is type casted into int and invokes it as TextView.setText(int) and searches for the Resource String with that int ID whose value is not defined in Resources.
type cast char as String like String.valueOf(char) and try once...
The signature for the method you are using takes a CharSequence, hence sequence of characters. Using setText(someEmptyString + Byte1), you create a sequence of characters from the concatenation of someEmptyString (which you would define as "") and Byte1.
set with some change like
Ytext.setText(""+Byte1);
setText() expects string or resource id (int). If you want to display numeric value, you need to convert it to string, i.e.:
setText(String.valueOf(someInt));
Try out as below:
Ytext.setText(""+Byte1);
Xtext.setText(""+Byte2);

Convert number in textview to int

So, I am messing around with java/android programming and right now I am trying to make a really basic calculator. I am hung up on this issue though. This is the code I have right now for getting the number thats in the textview and making it an int
CharSequence value1 = getText(R.id.textView);
int num1 = Integer.parseInt(value1.toString());
And from what I can tell it is the second line that is causing the error, but im not sure why it is doing that. It is compiling fine, but when it tries to run this part of the program it crashes my app. And the only thing thats in the textview is numbers
Any advice?
I can also provide more of my code if necessary
You can read on the usage of TextView.
How to declare it:
TextView tv;
Initialize it:
tv = (TextView) findViewById(R.id.textView);
or:
tv = new TextView(MyActivity.this);
or, if you are inflating a layout,
tv = (TextView) inflatedView.findViewById(R.id.textView);
To set a string to tv, use tv.setText(some_string) or tv.setText("this_string"). If you need to set an integer value, use tv.setText("" + 5) as setText() is an overloaded method that can handle string and int arguments.
To get a value from tv use tv.getText().
Always check if the parser can handle the possible values that textView.getText().toString() can supply. A NumberFormatException is thrown if you try to parse an empty string(""). Or, if you try to parse ..
String tvValue = tv.getText().toString();
if (!tvValue.equals("") && !tvValue.equals(......)) {
int num1 = Integer.parseInt(tvValue);
}
TextView tv = (TextView)findviewbyID(R.id.textView);
int num = Integer.valueOf(tv.getText().toString());
Here is the kotlin version :
var value = textview.text.toString().toIntOrNull() ?: 0
TextView tv = (TextView)findviewbyID(R.id.textView);
String text = tv.getText().toString();
int n;
if(text.matches("\\d+")) //check if only digits. Could also be text.matches("[0-9]+")
{
n = Integer.parseInt(text);
}
else
{
System.out.println("not a valid number");
}
this code actually works better:
//this code to increment the value in the text view by 1
TextView quantityTextView = (TextView)findViewById(R.id.quantity_text_view);
CharSequence v1=quantityTextView.getText();
int q=Integer.parseInt(v1.toString());
q+=1;
quantityTextView.setText(q +"");
//I hope u like this

Categories