I'm a very beginner in Android. I would like to print this in TextView, but the screen is all white and i can't see content of TextView. In the console works properly. Below is my activity and layout file.
public class MainActivity extends AppCompatActivity {
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Fruits();
}
public void Fruits() {
textView= findViewById(R.id.pa);
String[] fruit = {"orange", "apple", "pear", "bannana", "strawberry", "mango","grape","lemon"};
Random numberGenerator = new Random();
/* Generate A Random Number */
int nextRandom = numberGenerator.nextInt(fruit.length)
;
Set<Integer> validate = new HashSet<>();
/* Add First Randomly Genrated Number To Set */
validate.add(nextRandom);
for (int i = 0; i < fruit.length; i++) {
/* Generate Randoms Till You Find A Unique Random Number */
while(validate.contains(nextRandom)) {
nextRandom = numberGenerator.nextInt(fruit.length);
}
/* Add Newly Found Random Number To Validate */
validate.add(nextRandom);
System.out.println(fruit[nextRandom]);
textView.setText(fruit[nextRandom]);
}
}
}
layout
<TextView
android:id="#+id/pa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Your while loop is an infinite loop as the validate set would contains all 8 values at one point and will always be true. Because of which your textView is never set and keep on setting again and again.
add an additional check for size of set in while loop :
for (int i = 0; i < fruit.length; i++) {
/* Generate Randoms Till You Find A Unique Random Number */
while(validate.size() != fruit.length && validate.contains(nextRandom)) {
nextRandom = numberGenerator.nextInt(fruit.length);
}
/* Add Newly Found Random Number To Validate */
validate.add(nextRandom);
Log.i("HELLO",fruit[nextRandom]);
textView.setText(fruit[nextRandom]);
}
The above will print the randomly picked fruit and will skip once validate is full.
Note : I have added an additional check of set size(just as an example), you can add your breakpoint on which you have to be out of the loop.
The while loop will repeat forever.
When i equal fruit.length-1, validate has stored numbers in range [0,fruit.length), it led the condition in the while loop always true, and program can not get out the loop cause nextNumber you generated inside the while loop always in range [0,fruit.length). For simpler, let imagine the fruit array has only one element.
Related
I've inherited an app which displays a range of values as buttons (0 - 1000) - layout ViewA.
The buttons get indexed, and stuff happens. When the user clicks on some subset of those values, they change color, and get associated with some data which gets exported to a csv file eventually.
This works.
Now the user wants to be able to change between the original set, and a new set (0 - 1500) - layout ViewB.
I created these layouts, and put in a checkbox, and when it's selected it sets the visibility of ViewA to GONE and ViewB to Visible.
These buttons should be indexed just like the original ones, but the screen doesn't get updated before it crashes at observerPosBtn[i] = 42. 1 past the max index of the original array.
What (I think) I'm running into is that the layout is not getting updated until I leave the onChecked method, so the buttons which exceed the original range don't exist and can't get indexed. Then when stuff happens to an out-of-range button the app crashes. (Each range worked properly before adding the checkbox switch.)
Is there a way to "force" an update before I leave onChecked, or where does the code jump back to after the onChecked handler that I could call the 'updateObsPosButtons' function?
The code is structured (broadly) like:
Main Activity{
//definitions and stuff like
onCreate(){}
#Override
protected void onResume() {
super.onResume();
if(refreshSelectionEntries) {
startupConfig();
refreshSelectionEntries = false;
}
}
....
public void startupConfig(){
//onClick etcs
show1500mRangeCheckBox = findViewById(R.id.show1500mRangeCheckBox);
boolean[] observerPosChecked = new boolean[observerPosCount];
show1500mRangeCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
currentRange = "1500";
observerPosCount = 61;
} else {
currentRange = "1000";
observerPosCount = 41;
}
updateScreenRange(currentRange);
updateObsPosButtons(currentRange);
}
});
updateObsPosButtons(currentRange); //Called once in initial startup?
....
private void updateScreenRange(String range){
...
final View obs1500Incr50LL = findViewById(R.id.obs1500Incr50LL);
final View obs1500Incr25LL = findViewById(R.id.obs1500Incr25LL);
final View obsIncr50LL = findViewById(R.id.obsIncr50LL);
final View obsIncr25LL = findViewById(R.id.obsIncr25LL);
if (range == "1000") {
obs1500Incr50LL.setVisibility(View.GONE);
obs1500Incr25LL.setVisibility(View.GONE);
obsIncr50LL.setVisibility(View.VISIBLE);
obsIncr25LL.setVisibility(View.VISIBLE);
} else {
obsIncr50LL.setVisibility(View.GONE);
obsIncr25LL.setVisibility(View.GONE);
obs1500Incr50LL.setVisibility(View.VISIBLE);
obs1500Incr25LL.setVisibility(View.VISIBLE);
}
}
private void updateObsPosButtons(String range){
if (range == "1000"){
observerPosChecked = new boolean[observerPosCount];
....
populateObserverPos1000Btn();
//iterate through button range then "do stuff"
for (int observerPosIndex = 0; observerPosIndex < observerPosCount; observerPosIndex++) {
final int i = observerPosIndex;
....
}else{
observerPosChecked = new boolean[observerPosCount];
...
populateObserverPos1500Btn();
//iterate through button range - CRASHES AT i = 42
for (int observerPosIndex = 0; observerPosIndex < observerPosCount; observerPosIndex++) {
final int i = observerPosIndex;
// CHEAT HERE
....
}
} //End StartConfig
private void populateObserverPos1000Btn() {
int oPS_index = 0;
View obsIncr50LL = findViewById(R.id.obsIncr50LL);
View obsIncr25LL = findViewById(R.id.obsIncr25LL);
observerPosBtn[oPS_index++] = obsIncr50LL.findViewById(R.id.observerPosBtn_0);
observerPosBtn[oPS_index++] = obsIncr25LL.findViewById(R.id.observerPosBtn_25);
...
observerPosBtn[oPS_index++] = obsIncr50LL.findViewById(R.id.observerPosBtn_1000);
}
private void populateObserverPos1500Btn() {
int oPS_index = 0;
View obs1500Incr50LL = findViewById(R.id.obsIncr50LL);
View obs1500Incr25LL = findViewById(R.id.obs1500Incr25LL);
observerPosBtn[oPS_index++] = obs1500Incr50LL.findViewById(R.id.observerPosBtn_0);
observerPosBtn[oPS_index++] = obs1500Incr25LL.findViewById(R.id.observerPosBtn_25);
...
observerPosBtn[oPS_index++] = obs1500Incr50LL.findViewById(R.id.observerPosBtn_1500);
}
....
} //End MainActivity
If I "cheat" and add (at CHEAT HERE):
if (observerPosBtn[i] == null){
continue;
}
The updObsPosButtons function does finish and the screen updates, but it seems like if I click on anything above index 41 it crashes.
I think I've included the relevant code.
I've tried a few suggestions I've seen here like notifydatasetchanged, and a run handler... not sure I really can implement them in the current configuration though.
Is there anything I can do without a major refactor?
(I apologize in advance for my poor terminology, code architecture, and general ignorance - my software experience is a little firmware (C) - not Java let alone Android!
I'm the only option to even look it over for this "simple" (haha) update. Either it's something I can take a crack at, or I need to explain the roadblock well enough to outsource it! Thanks so much!)
I have a UI with some EditTexts in it and this set of edittexts can repeat number of times (not too much but 3 - 10 times max) based on the number of items in the list.
User can edit/modify/delete the item or edit the value of the edit texts. Currently I am doing this manually with "AddView/RemoveView", manually handling the states etc, however it is a lot of work as I have many scenarios like this.
We have a web app with the very same functionalities and we are using AngularJS to deal with all these, which, as you know is amazingly easy.
is there any closer way to bind the axml/xml view with a collection (may be an Observable collection and at least from the code behind) that will take care of collection changes as well as the individual field changes without me doing all this manually. In some scenarios I have to display images as well.
Also, I tried using a ListView, however it doesn't work as I would expect it to work.
is there any closer way to bind the axml/xml view with a collection (may be an Observable collection and at least from the code behind) that will take care of collection changes as well as the individual field changes without me doing all this manually.
The answer is no, there isn't. Android's views have to be bound to certain context/activity when they are created. They can't be isolated, so add/remove the EditTexts have to be implemented by yourself.
Currently, the closest way to your requirement is to create an ObservableCollection and listen for the CollectionChanged event and when CollectionChanged add/remove the view in your container:
[Activity(Label = "Demo", MainLauncher = true)]
public class MainActivity : Activity
{
Button btnAdd;
ObservableCollection<View> oc;
LinearLayout container;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
btnAdd = FindViewById<Button>(Resource.Id.btnAdd);
btnAdd.Click += BtnAdd_Click;
GenerateET(Resource.Id.container, this, 3);
}
private void BtnAdd_Click(object sender, System.EventArgs e)
{
EditText et = new EditText(this);
et.Text = "test";
et.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
oc.Add(et);
}
public void GenerateET(int resId, Activity activity,int num)
{
//create an observable collection
oc = new ObservableCollection<View>();
container = activity.FindViewById<LinearLayout>(resId);
for (int i = 0; i < num; i++)
{
EditText et = new EditText(activity);
et.Text = "test";
et.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent);
container.AddView(et);
oc.Add(et);
}
oc.CollectionChanged += Oc_CollectionChanged;
}
private void Oc_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
for (int i = 0; i < e.NewItems.Count; i++)
{
//add the view manually
container.AddView((View)e.NewItems[i]);
}
}
}
}
Main.axml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
<Button
android:id="#+id/btnAdd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add EditText"/>
</LinearLayout>
This is driving me a little mad since I know this should be very simple but I am not getting the desired affect.
I have the following arraylist
private List<String> tagStringArray = new ArrayList<>();
Then later I have a method that creates dynamic buttons, based on ID values pulled across from my Retrofit instance.
In my method, I have a count to help me set the title of the button but I also add the values of count to an ArrayList for use in another method.
I have taken a snip of relevant information from the method mentioned.
count = 1;
if (!questionNumber.equals("") && !questionNumber.equals(null)) {
for (final Object value : list) {
try {
/*Dynamically create new Button which includes the question number
*/
final AppCompatButton btn_question = new AppCompatButton(getActivity());
/*LayoutParams (int width, int height,float weight)
As LayoutParams is defaulted in px, I have called a method called dpToPX to make sure
the dynamically added EditText is the same size on all devices.
*/
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(dpToPx(280), dpToPx(45), 1);
btn_question.setBackgroundColor(Color.parseColor("#3B5998"));
btn_question.setTextColor(Color.WHITE);
btn_question.setText("Question "+count);
//set the Tag based on its position in the XML
tagStringArray.add(String.valueOf((count)));
count++;
If a user clicks on say Question 1 Button, I want my fragment to say Question 1, so to try and achieve that, I have tried doing the following:
String tags = String.valueOf(tagStringArray);
tags = tags.substring(1, tags.length() -1);
String[] currentTag = tags.split(",");
if (currentTag[0].contains("1")) {
tv_setQuestions_edit.setText("Question 1");
}else if(currentTag[1].contains("2")) {
tv_setQuestions_edit.setText("Question 2");
}
But this will always set the title to Question 1 and I am not sure what is going wrong.......
If I use the following toast Toast.makeText(getActivity(), Arrays.toString(currentTag), Toast.LENGTH_LONG).show(); it shows [1,2] so I know they are being added ok.
I did look into using tags by doing:
public static int KEY_COUNT=0; public static int KEY_VALUE=1;
btn_question.setTag(KEY_VALUE,value);
btn_question.setTag(KEY_COUNT,count);
But for some reason, when I add more than one tag (as I need a minimum of 2), my dynamic button is missing from the layout. But for some reason when only 1 tag - like this btn_question.setTag(value); is used, it shows up fine (I have a feeling its some issue with my fragment). Therefore I am trying to think of a workaround in the meantime.
Any help or guidance would be really appreciated.
It's because
currentTag[0].contains("1")
is always true. The first item of currentTag always contains "1".
Instead of doing this, why don't you just do String titleForFragment = myButton.getText() in the onClick method for the button? That way, you can set the same onClickListener on all the buttons, and it will reduce the amount of code you need to write.
Ok im making app and it have 15 button's and 6 textview's.I want when I press first button to change value of first textview(value is "") to something (number one for example).But problem is when i press second button if first textview is already set to some value to set set second textview to second value.
If you need something else ask in comments (sorry for bad English)
here is what I was doing(this is under onclick)when i press second button
if(textview1.equals("1")){
textview2.setText("2");}
else if (textview1.equals("")){
textview1.setText("2");
}
It sounds like you wish to show last 6 buttons pressed.
Store all pressed buttons in a List (i.e. LinkedList) of size 6. Initially, it will be empty.
Then whenever any button is pressed do two things:
1) add it to the List and delete old elements if size exceeds six.
2) set button values from List.
Second step can be achieved like this:
// all TextViews should be in a list
private List<TextView> textViews;
// declare as field
private List<String> memoryQueue = new ArrayList<String>();
public void update() {
//set fields for the pressed buttons
for (int i=0; i<6 && i<memoryQueue.size(); i++) {
String text = memoryQueue.get(i);
textViews.get(i).setText(text);
}
// set empty fields
for (int i = memoryQueue.size(); i<6; i++) {
textViews.get(i).setText("");
}
}
This code snippet assumes that you store your TextViews in a List.
And Easiest way to keep track of last six button:
public void buttonPressed(Button button) {
//get text based on your button
String text = button.getText();
if (memoryQueue.contains(text)) {
return;
}
memoryQueue.add(text);
if (memoryQueue.size() > 6) {
memoryQueue.remove(0);
}
}
Since you're concerned with the text inside of your text view, you should be using the object's getText method:
if( textview1.getText().equals("1") ){ // Edited
textview2.setText("2");
} else if (textview1.getText().equals("")){ //Edited
textview1.setText("2");
}
At first, you have to get the String text from TextView using getText() method then you can compare that String with another String. Now, change your condition as follows...
if(textview1.getText().toString().equals("1")){
textview2.setText("2");}
else if (textview1.getText().toString().equals("")){
textview1.setText("2");
}
I am self studying Android and now I am learning how to use buttons. I created a simple up counter which works like this:
I add the strings (eg. 1 2 3) in different text fields. Then I want to compaire those in pairs(1 with 2, 1 with 3, 2 with 3). The first string element is written on the first button, second on the second and after i press any of those buttons, the tags on the buttons has to change (if there was 1 and 2 so it should change to 1 and 3 or 2 and 3 etc) and the string element gets a higher rank. Everything seems to work well, but I think I am doing huge mistake with adding buttons. Can anyone help me? :) Can I add button listeners like I did in code bellow? :) Thank You!
public void counter()
{
int i = 0;
int a = i + 1;
for ( i = 0; i < candidates.size() - 1; i++ )
{
Log.d(TAG, "Setting button one tag: " + i );
button_one.setTag(i);
button_one.setText(candidates.get(i).name);
for (a = i + 1; a < candidates.size(); a++)
{
Log.d(TAG, "Setting button two tag: " + a );
button_two.setTag(a);
button_two.setText(candidates.get(a).name);
button_one.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view) {
/* Read the clicked tag */
int tag = (Integer) view.getTag();
/* Make higher rank */
candidates.get(tag).addRank();
}
});
button_two.setOnClickListener(new View.OnClickListener()
{
public void onClick(View view) {
/* Read the clicked tag */
int tag = (Integer) view.getTag();
/* Make higher rank */
candidates.get(tag).addRank();
}
});
}
}
everything AndyRes said plus:
you're creating (candidates.size() * candidates.size()) number of OnClickListeners
that's A LOT of unnecessary objects hogging your memory.
You should create ONE OnClickListener mListener = new View.OnClickListener etc... etc...
and OUTSIDE the loop, probably during your OnCreate() just after you defined button_one = (Button)findViewById(R.id.button_one); you do button_one.setOnClickListener(mListener);
that way you have only 1 listener that will be serving any amount of buttons you might have, and don't need to be setting again the same listener.
In general there's not need to add the click listeners in a loop, unless you create those buttons dinamically.
Setting the click listeners in a loop for the same button, every time you cycle through the loop, will do nothing but override the previous settings, so I don't see any point in doing like this.