Adding Custom ImageButton to layout in Android causes error - android

I will start by saying this, while I have some Java training, is my first foray into development for Android.
What I have done is created a custom ImageButton called MapCell that is basically an ImageButton that holds a few extra pieces of information, and it compiles fine.
My problem comes when I want to procedurally create a MapCell in the relevant Activity and add it to my TableLayout which is defined in the xml and has the id 'mapTable'. The relevant bit looks like this:
Random randy = new Random();
MapCell n = new MapCell(randy.nextInt(4), this); //the random number is part of my extra info
findViewById(R.id.mapTable).addView((View)n, 20, 20); //add cell to display
I get one error out of that:
The method addView(View, int, int) is undefined for the type View
Which to me sounds like utter nonsense. I put that View cast in there as desperation after I got this same error with n sitting by itself and nothing changed (Obviously my MapCell is already a View since it extends ImageButton).
I hope a new pair of eyes can tell me what this is about, since I've checked for similar problems and I didn't find any quite like this. Let me now if you need to see more code.

The method findViewById returns a View and the View class doesn't have the method addView(this method is implemented in the ViewGroup and its subclasses). Instead you should write:
((TableLayout)findViewById(R.id.mapTable)).addView(n, 20, 20);
I've cast the return of the findViewById method in a class that actually has the addView method.

You got this problem because method findViewById(R.id.mapTable) returns View object.
In android you can't add one View to another.
You can use addView function with ViewGroup, and all LinearLayout (etc.) objects.

Related

Logic behind the creation of an Instance of a Button vs the creation of an instance of a plain Class?

I can't understand the logic behind the following code in android studio when we create an instance of a Button:
Button btn = (Button) findViewById(R.id.btnRegister);
From what I know an instance of a class is defined like:
MyClass myInstance = new MyClass(MyParameter)
If we apply the above logic the button code should be like this:
Button btn = new Button(findViewById(R.id.btnRegister));
But in fact the above code does not work. Why is "button" code so complicated to understand and does not relate to the code of a mere class? What does "(Button)" in brackets mean in the above example????
Thank you
The find view line doesn't create a button. Your views are all created using the standard new syntax by the framework when you call setContentView. The setContentView function parses your xml and creates the appropriate classes. What findViewById does is search the views that it created in setContentView checking the ids for one with a matching id and returns it.
As for what (Button) does- its a standard Java cast. findViewById returns a View object. But some subclasses of View have advanced functionality not found on view. To use them, you have to have an object of the correct type. So you cast it to the correct type (which will throw an exception if it isn't the right type). For example you need to have a TextView to call setText, a normal View doesn't have that function.

TextView setText Cannot resolve type

Im using Android Studio, trying set text to Text View but every time i do this
TextView test = (TextView) findViewById(R.id.testView);
test.setText("fds");
on Android Studio i see Cannot resolve symbol 'setText'.
Can someone tell me what im doing wrong?
setText() will accept String which you have passed, so there is no issue in that.
One possible reason for this might be you have not written your code inside onCreate() or onCreateView().
If it is Activity you need to use these lines after setContentView() in onCreate().
If it is Fragment you need to use these lines after inflating your view in onCreateView().
Second reason, you might be having one more test variable of different type like String or something else

Automatically/dynamically update TextView text in Android

I have an android app that I have decided to rewrite, one of the reasons for the rewrite is because I could have 10+ TextViews with text set based on a variable in a class e.g.:
MyClass myClass = new MyClass();
myClass.myNumber = 5; // inside MyClass - public int myNumber;
LinearLayout mainLayout = (LinearLayout) view.findViewById(R.id.mainLayout);
TextView myTextView = new TextView(getActivity()); //In a fragment
myTextView.setText(String.format("myNumber currently has a value of %d", myClass.myNumber));
mainLayout.addView(myTextView);
return view;
Up until now I have been using .setOnClickListener on the buttons/views that change myNumber, to set the text of the view again when the value of myNumber changes, which then calls .invalidate() to redraw the TextView, this has worked fine, but I use this method very heavily and code is getting quite repetitive and changing one integer can affect quite a lot of views (all of which use it differently - such as different wording, or a calculation (e.g. myNumber * 2)). I guess it's because it's made an immutable string in the TextView.
I have tried to create a custom TextView that implements Observer (making MyClass extend Observable) and in the update method I can get it to invalidate itself for the refresh, but it still has the same text. I have also tried creating single element arrays, in an attempt to pass the reference not the value in the hope that when it is changed and then the view is invalidated it will pick up the new value but the text still ends up remaining the same.
How can I get a TextView that will auto update when the value of myNumber has changed? Some sort of binding?
Bindroid works perfectly for this, just a note for users, using fragments the sample application is using this from an Activity so the bind method using Activity is called, so in the fragment I was using getActivity() which caused it to not work properly, digging around in the library I found a bind method that takes a View and passed in my view which gets inflated in the fragment and it works great!!! This is super easy to integrate btw it was just me not getting it!

android setBackgroundColor in runtime and other general confusion help?

i have a row of buttins created like this
i want to change the background colour at runtime in code.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout track1 = (LinearLayout)findViewById(R.id.my_toggle_container);
for (int i = 0; i<32; i++) {
ToggleButton tgl = new ToggleButton(this);
tgl.setId(i);
...
track1.addView(tgl);
this names the id of the togglebuttons 1, 2, 3... (i presume?)
i have an int variable called 'xBtn' that changes 1, 2,..
this is how i get a reference to the button using xBtn
String buttonID = ""+xBtn;
int resID = getResources().getIdentifier(buttonID, "id", "com.thing");
//find the button
ToggleButton tb = (ToggleButton) findViewById(resID);
//change its colour
tb.setBackgroundColor(Color.BLUE);
it crashes on the setBackgroundColor line.
it may be obvious to someone whats wrong and thats what im hoping
any help would be totaly ace ta
thanks
main.xml
<LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:id="#+id/my_toggle_container" android:orientation="vertical">
The id of your togglebuttons is gonna be a number from 1 to 32... However, trying to find the toggle button by id will return null because simply instantiating a new toggle button and giving an id wont help you. findViewById looks in the parent view for a child view with the specified id. If you havent added that toggle button with that id to the view, then findViewById will return null. I am 99.99% sure even without looking at the log, that it crashes because you are calling setBackgroundColor on a null object.
In other words, the id that you set a view to is only relevant once the view is actually added to a parent view. In your case you are probably trying to add these toggle buttons to your main content view, in which case you need grab hold of that view that you used for setContentView and call addView on that view and pass in each new toggle button. Note that this will probably not look right unless you also specify layoutparams for the togglebuttons.
EDIT
If thats your entire main.xml, then you've got other issues. Post the full xml file. In any event, you still are going to have to do what I've said, which is to grab hold of the view or a child view of that view and then add the toggle buttons to it via addView (after giving the togglebuttons their proper ids). Once the button has been added, then you can find it. Note though that if you're gonna add the toggle buttons to a child view of your main view, then you'll likely have to grab hold of that child view and call findViewById on THAT.
For example, you can do a nested call like this. findViewById(1) <--- gets you the LinearLayout or whatever inside of your main content view, then once you have that you can call addView on it. So LinearLayout ll = (LinearLayout)findViewById(someNumber); ll.addView(tb);
Try to use the method setTag() , and then you can get all your ToggleButton by using : findViewByTag();
Perhaps tb is null? Could you check that out?
To expand on what LuxuryMode said... What gets an ID INTO your java is inflating it via setContentView and setting it as content. That's why it's ok to have overlapping (duplicate) IDs in different layouts. You can have #+id/submit_button in layout1.xml and in layout2.xml and the Activity will get you the object via findViewById(R.id.submit_button) based on which one you have loaded into setContentView() at any given moment.
So, we're all guessing that you're probably not setting the content view and hoping that the code will find your object in your non inflated XML, which it won't. Which would lead (as everyone has guessed) to you now dealing with a null object, which you obviously can't set a background color on.
I know it gets confusing cause you have the XML RIGHT THERE!!! But the reality is that the xml isn't "alive". It's just stuff for you to look at until you have tasked the Application with inflating it and converting all of it into Android objects of some kind. A lot of the time this is done mostly transparently to you, so, it's easy to forget that none of these things really exist.
It's very likely that tb is null, because findViewById() didn't go as you expected.
You can verify this by surrounding the erroneous line with try.. catch block:
try {
tb.setBackgroundColor(Color.BLUE);
} catch (Exception e){
}
and watch for the message of e. It's likely to be null pointer exception.
In fact, I think you should not use getResources().getIdentifier(buttonID, "id", "com.thing") in the first place. It seems to me that all these resources are continuously numbered in R file, thus you should simply get the first id (as an integer), and then increment on that.
That is, you should do things like:
// The following code is not tested; I just wrote it here on SO.
for (int resID = R.id.button1; resID <= 32; resID++) {
ToggleButton tb = (ToggleButton) findViewById(resID);
tb.setBackgroundColor(Color.BLUE);
}
this should make all 32 buttons blue.

Just so lost... ViewSwitcher? Create an Activity then add to ViewSwitcher?

I'm new to Android and find it brutal (there seems to be an near infinite number of details and dependencies to remember).
Anywho, I got the TextSwitcher1 example app working, which uses ViewSwitcher. I'm assuming ViewSwitcher is the way to go, need to either display a map or a table, user can pick, and switch back and forth.
So I created my MapActivity in another application, seems to work. Next integrate into main app. So, call
View v = findViewById(R.layout.mapview);
and then
mSwitcher.addView(v);
except "v" is null. Why? Do I create the activity? But I don't want to show it yet. Is there such a call as "create activity but hide it until needed"? Or am I barking up the wrong tree?
Thanks for any insight.
The findViewById function returns a View based on an ID resource (R.id.something) for whatever view you have loaded in your activity (using setContentView(R.layout.main)). In your sample code, you're using a layout resource (R.layout.mapview). You should inflate the XML file, which will return a View that you can use to add to the ViewSwitcher.
Example Code:
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = vi.inflate(R.layout.mapview, null);
mSwitcher.addView(v);
However, you should be able to define everything in your XML file and not have to manually add the pages to your ViewSwitcher. Here's some example code on how to do that: http://inphamousdevelopment.wordpress.com/2010/10/11/using-a-viewswitcher-in-your-android-xml-layouts/

Categories

Resources