All i want to do is to have a class that creates dynamically a button and fills it with the text 'tarr' automatically. So i generated a new class and wrote the following in it:
import android.widget.Button;
public class FloatButton {
Button button = new Button(this);
button.setText("tarr");
}
in my main activity it should make an object of this class. So i wrote this in the activity (snippet):
...
public void onCreate() {
super.onCreate();
FloatButton myButton = new FloatButton();
}
Sadly this gives me some mistakes marked. The mistake i don't realy understand is why the 'this' is marked. Can you tell me the problem?
When sending this to the Button constructor method, you are not sending a
valid Context, but your FloatButton object.
Android Context
What you can do is :
public class FloatButton {
private Context _context;
public FloatButton(Context context) {
this._context = context;
}
public createButton() {
Button mButton = new Button(_context);
mButton.setText("tarr");
}
}
PS : Why are you trying to create a button in a separate class, and not directly in your activity ?
You are trying to create a button dynamically and then add it to your activity.
The thing you are doing wrong is obviously not providing any context and two, you are not adding it to your activity's layout without which you will not be able to actually 'display' the button.
Here's what you need to do:
Create a function in the FloatButton class which receives a context and returns a button object as:
public Button createNew(Context c){
Button b = new Button(c);
b.setText("tarr");
return b;
}
In your main class, create a FloatButton object and call the createNew function as:
FloatButton fb = new FloatButton();
Button button = fb.createNew(this);
This will give you a button object which you then have to add to your layout
Now you need to declare the mandatory layout parameters which are height and width. Do it as:
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
Get your activity's primary layout (LinearLayout or RelativeLayout) as:
LinearLayout ll = (LinearLayout)findViewById(R.id.layout_main);
where layout_main is the id of your layout
Finally add your button to the layout and set its layout parameters as:
ll.addView(button, lp);
Though I would NOT recommend doing such a thing because you can replace the FloatButton class creation and instantiate using a simple Button button = new Button(this) in your main class itself. So, it is very redundant unless you want to do several customizations to your button in the FloatButton class itself like making it a different color or something and creating the button several times at several places.
Related
I have an issue creating a Button programmatically. The button is supposed to be inserted in a pre-existing layout.
And since I need the dimensions of a specific container I created a global layout listener for that container and in the onGlobalLayout callback i check for a valid size and then instantiate a new Button.
The context used is the context from the container.
final View container = activity.findViewById(...);
container.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
if (container.getWidth()>0 && container.getHeight()>0) {
Button button = new Button(container.getContext());
}
}
});
However, in rare cases - specifically when switching from one activity to another - the Button instanciation fails with a NullPointerException in the Android framework code.
java.lang.NullPointerException: Attempt to read from field 'android.animation.Animator android.animation.AnimatorSet$Node.mAnimation' on a null object reference
at android.animation.AnimatorSet.clone(AnimatorSet.java:725)
at android.animation.AnimatorSet.clone(AnimatorSet.java:682)
at android.animation.StateListAnimator.clone(StateListAnimator.java:148)
at android.animation.StateListAnimator$StateListAnimatorConstantState.newInstance(StateListAnimator.java:328)
at android.animation.StateListAnimator$StateListAnimatorConstantState.newInstance(StateListAnimator.java:327)
at android.content.res.ConstantState.newInstance(ConstantState.java:53)
at android.content.res.ConstantState.newInstance(ConstantState.java:61)
at android.content.res.ConfigurationBoundResourceCache.getInstance(ConfigurationBoundResourceCache.java:40)
at android.animation.AnimatorInflater.loadStateListAnimator(AnimatorInflater.java:163)
at android.view.View.<init>(View.java:4815)
at android.widget.TextView.<init>(TextView.java:995)
at android.widget.Button.<init>(Button.java:113)
at android.widget.Button.<init>(Button.java:106)
at android.widget.Button.<init>(Button.java:102)
at android.widget.Button.<init>(Button.java:98)
My assumption is that somehow the Context ist not valid any more but I can't put my finger on it..
I do remove the listener when the activity gets deactivated.
Any ideas?
As docs says OnGlobalLayoutListener
Interface definition for a callback to be invoked when the global layout state or the visibility of views within the view tree changes.
So when UI is destroing, you are getting "dying" View that causes NPE. You can try to unregister listener in onStop() to prevent that. Or if you need just to handle fully created View use
container.post(new Runnable() {
#Override
public void run() {
Button button = new Button(container.getContext());
}
});
The only solution I've found so far is to not create the button by calling
Button button = new Button(container.getContext());
but by creating a small layout xml file only containing the button and then instantiate the button like so:
LayoutInflater.from(context).inflate(R.layout.button, null)
I'm getting the android xml id in first Activity
(e.g)
setContentView(R.layout.sample);
button1=(Button)findViewById(R.id.b_one);
button2=(Button)findViewById(R.id.b_two);
Now the problem is how can i use the same button in second Activity without using findViewById().
(i.e) I don't want to access xml in second Activity rather than that i have to access those button ID from the first Activity itself.
I'm trying this to create a common header.
Please help me.
You can't, because your buttons from two different activities will not share the same instance.
What you can do instead, if you want to have some common code for your header is to delegate this code in a static method of a third class. For example :
public class MyHeader {
private Button button1,button2;
public MyHeader(Activity source) {
this.button1 = (Button)source.findViewById(R.id.b_one);
this.button2 = (Button)source.findViewById(R.id.b_two);
// ...
}
public Button getHeaderButtonOne() { return button1; }
// And so on...
}
and in your activities, keep an instance of this class (initialized with :
private MyHeader header;
// ... in onCreate() method
header = new MyHeader(this);
Here's the situation: I have an activity that dynamically generates a bunch of randomized custom imagebuttons and adds them to TableRows, in a TableView, in my xml. This activity also has a method that I want to call when one/any of these buttons is clicked. The buttons have variables inside them; the method gets these variables and sets them into a TextView (in the same activity) so I figure all the buttons can use this one method. If these buttons were defined in the XML I would just use android:onClick="displayCell" to specify the method, but they aren't. Is there a way to just set onClick for these buttons as I'm generating them in the activity or do I have to use
button.setOnClickListener(new OnClickListener(){....});
and go through a bunch of hassle as I've seen in some of the answers around here? The problem I have with that is that I can't seem to call my method from inside onClick because the argument of the method (the button) is not final (I'm making a bunch of 'button' in a loop so I don't think it can be):
button.setOnClickListener(new OnClickListener(){
public void onClick(View q){
button.getActivity().displayCell(button);//I want to do something like this but this obviously doesn't work
}
});
You can have the Activity implement OnClickListener and then (assuming you are in the activity):
button.setOnClickListener(this);
Yes as comodoro states, or make your onClickLIstener a member variable of your class, don't do a "new" on each button.
private OnClickListener mOnClickListener = new OnClickListener() {...};
and when creating your buttons:
button.setOnClickListener(mOnClickListener);
The onClick() function in your listener will be passed the View of the button itself. You can access the buttons variables, etc, from this function.
public void onClick(View v)
{
ImageButton button = (ImageButton)v;
// and access your button data via button object...
}
A solution to this could be :
Create different instances of buttons .(So you can make them final)
Use setId() method to give them an integer ID (to refer to them later).You can store the ID's in an a Listto refer them later on.
Define their onClickListeners right after you create it.
Try using a class that inherits from button and add there the OnClickListener. Like this:
class MyButton extends Button {
OnClickListener clicker = new OnClickListener() {
public void onClick(View v) {
displayCell(v);
}
};
}
Th question: Can I re-use RadioButton objects over and over again in an child activity?
I have a parent activity and a child activity. In the child activity, I have a large number of radio button displayed in a UI. In order to provide databinding from the parent down to the child, I have created a class (below) which contains a collection of RadioButtons. To populate the child activity, I pass a reference to this class down to the child which then groups the radioButtons into RadioGroups and displays them. I do this because the checked status of each button is now automatically available in the parent class, without the need to transfer any data through bundles.
public class GeneralAttribute{
Activity mThis;
public class Gender { // Mutually exclusive members
String categoryDesc = "Gender of user";
RadioButton isUnspecified = initRadioButton("Unspecified", true);
RadioButton isMale = initRadioButton("Male" , false);
RadioButton isFemale = initRadioButton("Female" , false);
} ;
<....more subclasses....>
RadioButton initRadioButton(String str, Boolean b) { // Factory
float cLayoutWeight = 0.5f;
RadioButton rb = new RadioButton(mThis);
rb.setText (str);
rb.setChecked(b);
rb.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, cLayoutWeight));
return rb;
}
GeneralAttribute(Activity localThis){ // Constructor
mThis = localThis;
gender = new Gender();
handedness = new Handedness();
location = new Location();
}
}
In the parent activity i have:
public class Parent(...)
public GeneralAttribute mGeneralAttribute; // Member class of RadioButtons
public static SPIGestureLoggerActivity TopLevelActivity;// Reference to the parent activity
public void onCreate(Bundle savedInstanceState) {
TopLevelActivity = this; // Assign this to the reference
mGeneralAttribute = new GeneralAttribute(this); // Initialize the class of RBs
startActivity(child); // Start the child
In the child activity i have this:
radiogroup = new RadioGroup(this);
radiogroup.setOrientation(RadioGroup.VERTICAL);
radiogroup.addView(Parent.TopLevelActivity.mGeneralAttribute.gender.isUnspecified);
radiogroup.addView(Parent.TopLevelActivity.mGeneralAttribute.gender.isMale);
radiogroup.addView(Parent.TopLevelActivity.mGeneralAttribute.gender.isFemale);
Parent.TopLevelActivity.mGeneralAttribute.gender.isUnspecified.setChecked(true);
mLinearLayout.addView(radiogroup);
This works fine....the first time the child activity is displayed. The second time it is displayed I get an exception.
In summary, here is the chain of events:
create the class of RadioButtons,
pass them to the child,
add them to a new RadioGroup
collect user choices
finish the child acitivty (which should destroy the RadioGroups)
use the data in the parent,
start the child activity again,
attempt to add the RadioButtons to new RadioGroups...
...Exception.
I can avoid this problem, if I null the class and reconstruct it. However, I would like to re-show the choices made from the first viewing with the second viewing.
Ideas:
Are the radioButtons saving pointers to the non-existant RadioGroups from the first viewing?
Is there a way to re-assign the view parent on each radio button in the class?
P.S. You may ask why I'm not using XML. For one, I will have 100+ of these radio buttons and I think it will be too painful to manage through XML. For another, I just like working programmatically on these things.
make sure you remove all the radiobuttons from the all radiogroups. Basically your right the radiobuttons are saving pointers to the non-existant raidogroups and no there isn't isn't a way to reassigned without calling removeAllViews on all the radiogroups. The best place to do that will be the onDestroy if your sure thats being called.
I'm using a child class which extends from main to setup some buttons. I am able to change variables created in main, such as TotalMoney from within child.
The problem is findViewById is giving a nullpointer exception. The code within buildthem() works fine when used in the main class.
I am using setContentView(R.layout.main); from within OnCreate in main. The Child class is instantiated and called from OnResume in main class.
Do I need to setContentView in the child aswell, or pass the content view from the main class somehow?
package com.chewyapps.markettrader;
class child extends main {
void buildthem(){
TotalMoney = TotalMoney + 9999;
Button MenuButton = (Button) findViewById(R.id.Menu);
//etc
}
}
I can't findViewById in Oncreate because the full code will use
for(i=0; i<buttonIDs.length; i++) {
Button b = (Button) findViewById(buttonIDs[i]);
//do other stuff
}
The for loop is needed for other things relating to each button. If I can get the basic example working though I assume the full code will work.
It hadn't occured to me before to mention this, but the child class is in a seperate file called child.java, from my main.java file in onResume I use:
child childObject = new child ();
childObject.buildthem();
Why not put this line:
Button MenuButton = (Button) findViewById(R.id.Menu);
in onCreate(), then you can either pass MenuButton into buildthem() as a parameter or reference it directly, depending on your design.
Please note that Java convention is to have variable names start with a lowercase letter, so menuButton not MenuButton.
EDIT
Then why not create an array of Buttons in onCreate() that you can later iterate through?
Button myButtons[] = new Button[buttonIDs.length];
for(int i=0; i<buttonIDs.length; i++) {
myButtons[i] = (Button) findViewById(buttonIDs[i]);
}
Then just iterate over the myButtons array in your child class.
What about:
Button MenuButton = (Button) this.findViewById(R.id.Menu);
or
Button MenuButton = (Button) Child.this.findViewById(R.id.Menu);