I was trying out coding android layout on Java. Then, I noticed that following code is incorrect (as in not working):
public class MainActivity extends Activity {
LinearLayout topLayout = new LinearLayout(this);
Button button1 = new Button(this);
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
... setText, layoutParam and etc ...
topLayout.addView(button1, layoutParam);
setContentView(topLayout);
}
}
while following code is correct (working):
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
LinearLayout topLayout = new LinearLayout(this);
Button button = new Button(this);
... setText, layoutParm and etc ...
topLayout.addView(button1, layoutParam);
setContentView(topLayout);
}
}
Why is that?
The context of an Activity is created once onCreate() is called.
In the first case, you don't have context set.
The comment made by #Blundell explains it, but if you want to go a little bit deeper, you need to understand the object lifecycle and order of things.
An Activity is a Java Object in the end. And so it must go through the Java Object creation process.
public class MainActivity extends Activity {
LinearLayout topLayout = new LinearLayout(this);
Button button1 = new Button(this);
Member variables (or Fields) are created right after the constructor. If you don't have a constructor, one is created for you (even tho you don't see it) you can try to create one:
public class MainActivity extends Activity {
public MainActivity() {
super();
Log.d("MAINACTIVITY", "Constructor!");
}
Now add log to your onCreate()…
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Log.d("MAINACTIVITY", "onCreate!");
}
Start your Activity and look at the log.
You should see:
Constructor!
onCreate!
With that being said, Since an Activity implements a Context interface, you cannot use them until they are not constructed, something that can be considered done after the constructor is called and ends.
Field members which are initialized inline, must be initialized during object Construction too, because that's the idea of their initialization being there…
So in short, you're trying to initialize Field Members that require something (a context) that is not yet available because it hasn't been created (this).
;)
Related
I have somthing like that:
public class A()
{
private Button myButton;
public void setMyButton(Button myButton)
{
this.myButton = myButton;
}
public Button getMyButton()
{
return myButton;
}
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
setMyButton(button);
}
public class B()
{
public void exampleMethod()
{
A aObject = new A();
Button button = aObject.getMyButton();
}
}
Button in class B is always null. I tryied that:
In class A
public Button myButton;
In class B
A aObject = new A();
Button button = aObject.myButton;
but it is not working too.
I am sure that first is button initiate, then geting button reference. I checked that using logs.
I don't know what is going on, becasue "getMyButton" in class A work fine. How can I get reference of button from class A in class B?
What is the best way to do that?
Looks like you are creating new java object of your activity on your own. Please try to get existing object of an created activity; so that you will get activity context and activity properties as well.
The button is always null because its set in onCreate, which is not automatically called. Let me guess, A is supposed to be an Activity subclass, based on the signature, right? In that case you're doing things really wrong.
*You cannot create an Activity via new, it won't be properly initialized.
*Accessing views of an Activity like that is really weird. It makes more sense to pass the view into B, as B is likely owned by A. If the Activity A doesn't own B, you're probably doing something really wrong. Pretty much if you need to do this you've probably misarchitected something.
The way that you are doing will only works in JAVA and not in ANDROID.
Its because of ACTIVITY class. Activity class reference will be created only when its life cycle is created and you cannot pass the UI elements of one activity to Another.
As the button is associated with the 'A' Class in your case and if you want this in Class 'B' you have to start Activity and its life cycle and also setContentView(R.layout.activity_main);
Other way is get the data that you want from any class and publish the value in 'A' class itself. this can be done by startActivityForResult();
In the following code, the class "Test" is extends Acitivity and implements OnClickListener.
but, the "this" refer to the instance of class "Test". There is no "new" to create
a new object to class "Test". So, where/when the instance of Test class created?
public class Test extends Activity implements OnClickListener {
Button playButton;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
playButton = (Button) this.findViewById(R.id.Button01);
playButton.setOnClickListener(this);
}
Thanks for anyone help.
Android framework is instantiating your activities for you when you open new intents, that's why you don't need to do new ActivityClass, all you have to do is declare your activities in your AndroidManifest.
So, where/when the instance of Test class created?
The instance is created 'internally', somewhere between openIntent and onCreate methods.
So, where/when the instance of Test class created?
On calling public void onCreate(Bundle savedInstanceState) method ( in your case) since its main Activity
To make it more clear, lets change a bit your code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
playButton = (Button) this.findViewById(R.id.Button01);
OnClickListener clickListener = this; // take current instance
playButton.setOnClickListener(clickListener);
}
We register our Activity to listener by passing instance to listen on events. however we don't want that setOnClickListener will see all our methods so they ask us to provide Interface only (OnClickListener).
Working the android hello world, I next added some strings to the strings.xml resource file. I then tried setting a member variable of my main activity class to the value of one of the strings:
public class MyActivity extends Activity {
/** Called when the activity is first created. */
public String myString = getString(R.string.MY_STRING); // compiles, but crashes
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText(myString);
setContentView(tv);
}
}
When it crashes, I get this in the logcat:
Unable to instantiate activity ComponentInfo{com.myclass}: java.lang.NullPointerException
So, am I doing it wrong, or is this expected behavior? Looking over the documentation,
I don't see anything to lead me to think that the resources wouldn't be available while the main activity is being constructed.
http://developer.android.com/guide/topics/resources/accessing-resources.html
However, I am pretty sure this will work in other classes--just not the main activity class.
I don't think you can call getString on the Activity class as it may not have been properly initialised yet. You may need to split the declaration (keep it as a public String) and then the assignment (move that to onCreate).
public class MyActivity extends Activity {
/** Called when the activity is first created. */
public String myString;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myString = getString(R.string.MY_STRING); // compiles, but crashes
TextView tv = new TextView(this);
tv.setText(myString);
setContentView(tv);
}
}
I want to create layout programmatically in different class which is not an activity so i will call one function from Activity and all code for creating layout is in function. so please give me some idea to write code.
this is my Activity:
public class Main extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TableLayout tl = (TableLayout) findViewById(R.id.table1);
testing t1 = new testing();
Main m = new Main();
t1.makelayout(tl,m);
}
}
And this is my class which has function that is generating layout programmatically:
public class testing {
public void makelayout(TableLayout tl,Main m1) {
// TODO Auto-generated method stub
//Main m = new Main();
TextView tv= new TextView(m1);
tv.setText("hello1");
tl.addView(tv);
}
}
can i do this or not please help me.
If your makelayout(TableLayout tl,Main m1) would be makelayout(Context c, TableLayout tl) and you call it by giving the Activity's context, then it would work.
For such "external" things, you always need to give over the appropriate context to allow creating the Views in it.
The following code does not work, and throws a RuntimeException caused by NullPointerException
public class ListFilteredActivity extends Activity {
LinearLayout typeSelector = new LinearLayout(this) ;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ScrollView sv = new ScrollView(this);
this.setContentView(sv);
//this.typeSelector = new LinearLayout(this);
this.typeSelector.setOrientation(LinearLayout.VERTICAL);
sv.addView(this.typeSelector);
}
When I moved the initialization of this.typeSelection inside onCreate() it works great.
#Override
public void onCreate(Bundle savedInstanceState) {
...
this.typeSelector = new LinearLayout(this);
...
}
Why is the null pointer error? The inline declaration in the first piece of code happens as soon as constructor is called, and then the onCreate() has access to the object, isn't it?
LinearLayout requires you pass in a Context. This is an Android lifecycle object and not a Java object. When declaring and initializing the field directly, this will be initialized using the Java default constructor. However you'll only get a context once the onCreate lifecycle method occurs, which is much, much later and part of Android, not Java. So when you call the LinearLayout constructor with this, Android is expecting a reference to a Context, which you only get after the call to onCreate.