I want to run a class multiple times, lets say I have a class
public class setTextClass {
public void setTextClass (String text){
this.text = text;
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
textview.setText(text);
}
public void run{
textview.setText(text);
}
}
So, As I see, if I initiate the class doing:
setTextClass hi = new setTextClass("hello");
The code on the onCreate will run right? (this is my first question)
And then, if I run the code:
hi.run()
The code over the run method will be executed and also will pass the text variable that was assigned at the initialization?. This is my second question. I'm learning java, sorry if this is a really basic question
First of all, it's difficult to address question with basic java and Android misconceptions in a Stack Overflow answer. SO is not made for these kind of question, that's why you are getting downvotes. So, that said, I'll try to help you a little bit:
First answer: "The code on the onCreate will run right? (this is my first question)"
No. You are probably mixing up because of onCreate method from Android's Activity class, right? But a constructor is something general for all classes in java, while onCreate is a method specific to some Android complex classes, like Activity or Fragment. It is a method related to the lifecycle of these classes and you should read more about it here.
So, in this simple class that you showed, onCreate will not be called in the constructor (unless you explicitly call it in the constructor). You should assign the text to textView inside your constructor.
Second question: "The code over the run method will be executed and also will pass the text variable that was assigned at the initialization?"
Yes, it will run and use the variable assigned to this.text on the constructor. BUT, you are missing the declaration of this global variable for it to work:
public class setTextClass {
private TextView textView;
private String text; // You have to declare your global variables here
public void setTextClass (TextView textView, String text){ // You should pass your TextView in the constructor and assign it to your global variable, so it's not null when you assign text to it;
this.textView = textView;
this.text = text;
textview.setText(text); // Moved from your onCreate method to the constructor
}
public void run{
textview.setText(text);
}
}
I hope I could make myself clear, but you should study more java and do some basic tutorials to better understand the language and it's concepts, so you can ask more specific questions here. Read here about classes, objects, constructors and more
Your onCreate function will not run when you do the initialization:
setTextClass hi = new setTextClass("hello");
instead what will run as its constructor(which should not have a return type because its return type is the object itself) ie:
public setTextClass (String text){
this.text = text;
}
And as for the second question the text variable, that variable only exist in the scope of the constructor or setTextClass method. So if you wanted to do something like that you would need to create and set a class variable.
It seems like you need to do a lot more learning and go through examples of OOP design and scope. I would check out these resources if i were you:
http://www.learnjavaonline.org/en/Objects
http://www.learnjavaonline.org/en/Functions
Related
I'm trying to use the array in my android program.
I did this
public class MainActivity extends Activity {
TextView[ ] answer = { new TextView(this) };
and, I tried to do use answer[0]
but it gives me errors. Is there any problems with me initializing the arrays?
(I want to create, and initialize them at once)
Guys thank you.. figured it out by help!
I did
TextView[] answer;
in Main
and did
TextView[] answer = {new TextView(this)};
in On create
this made me able to use answer in other methods! thank you guyz!
The statement
TextView[] answer = { new TextView(this) };
needs to be in an instance method such as onCreate. If you need to access it outside the method declare it as a class member variable:
public class MainActivity extends Activity {
private TextView[ ] answer;
#Override
public void onCreate(Bundle savedInstanceState) {
...
answer = new TextView[] { new TextView(this) };
}
....
}
It refers to the instance of MainActivity on which onCreate() has been called.
In general, from the Java Language Specification, 15.8.3:
The keyword this may be used only in the body of an instance method, instance initializer or constructor, or in the initializer of an instance variable of a class. If it appears anywhere else, a compile-time error occurs.
When used as a primary expression, the keyword this denotes a value that is a reference to the object for which the instance method was invoked (ยง15.12), or to the object being constructed. The type of this is the class C within which the keyword this occurs. At run time, the class of the actual object referred to may be the class C or any subclass of C.
You should try this.
public class MainActivity extends Activity
{
TextView[] answers;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
answers = new TextView[]{new TextView(this)};
}
}
It should be defined as:
TextView[] answer = new TextView[]{new TextView(this)};
I have some code that is utilising a variable from one class to another, I am using getters and setters and I checked that when i setClassName() before changing class that it works but i can't acces it properly from the other class, it return's null.
http://pastebin.com/6AP4c6ii -- CLASS A
http://pastebin.com/QCnWDnYs -- CLASS B
There is more code but it's relatively messy and long, im a noob to this and am working on ways to improve my coding and this is just a little project.
Any help appreciated.
It returns null because you actually never set the variable.
CLASSA Ccs = new CLASSA(gsm);
#Override
public void init() {
getFirstCompanion();
getVariables();
}
private void getVariables() {
classChoice = Ccs.getClassChoice();
System.out.println("Init, class is " + classChoice); //here, this returns as nothing, not null, nothing
}
You see, you are creating a totally new object when declaring new CLASSA(gsm), any changes you made to a previous object is not reflected, because this a fresh new object, therefore its chosenClass attribute, is initialized to null. Since you are getting the value without previously setting it, you are getting a null value
I hope I made myself clear enough, and I hope I helped you!
Edit
If you want to share the same variable across multiple instances, you can make them static:
private static String chosenClass = "";
public static void setChosenClass(String chosenClass)
{
this.chosenClass= chosenClass;
}
public static String getChosenClass()
{
return chosenClass;
}
Does "my code to go to the next class" mean you instantiate class B? Because then Class B might have another instance of A then the one you set the class choice on.
I have this in onCreate :
final TextView text1 = (TextView) findViewById(R.id.txtNextAlarm);
And I'm trying to set a text in a method that is in the same class :
public static void NextTxt(){
text1.setText("");
}
But it doesn't recognize the "text1".
The problem is that static methods aren't associated with any particular object, but with the class as a whole. As such, they can only see static fields in your class. Your text1 variable isn't even that, if what you say is true. Instead, it's a local variable that only exists for the length of the onCreate() method. If you know you'll only ever have one instance of your activity (and that's probably not an unreasonable assumption), what you could do is use
private static TextView text1;
at the top of your class (or, basically, anywhere outside of a method). The final modifier doesn't buy you anything. Your choice of whether to make it public or private, but I tend toward private by default (unless there's a reason for something else).
The alternative is to ask yourself why NextTxt() is static; if you make it a normal instance method, then you'd still need to declare text1 in the class, but it wouldn't need to be static. But then you'd need an instance to call it on.
TextView text1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
text1 = (TextView) findViewById(R.id.txtNextAlarm);
}
Do the initialization in the onCreate method.
If the method is static, you cannot access any of the non-static fields of the class. You have to make your textField static or pass it as a parameter.
static TextView text1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyClass.text1 = (TextView) findViewById(R.id.txtNextAlarm);
}
public static void NextTxt(){
MyClass.text1.setText("");
}
Of course you can only have one textField set at the time, because it's a static field of the class. The other options include making a singleton or removing static modifier from your NextTxt method.
If it's true that this line is in your onCreate method
final TextView text1 = (TextView) findViewById(R.id.txtNextAlarm);
then the answer to your question is that text1 is out of scope from within your NextTxt method. You've declared and initialized a variable within one method and you're trying to access it from another one. In order for the NextTxt method to "see" text1, you need to move that member to a place where both methods can access it.
As mentioned in other answers, you're also dealing with the fact that onCreate is an instance method while NextTxt is a static method. You may be tempted to start making everything static in order to "fix" your issues, but this is a dangerous and sloppy path. You don't have control over when Android kills your UI, so text1 could become invalid with no warning. The next time you try to call a method on it, you won't like the results.
Rethink what you're trying to do, sketching it out if necessary and don't just apply quick fixes in Eclipse if you don't understand the error.
text1 is a local variable you have to declare it as an attribute of your class
public final TextView text1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
text1 = (TextView) findViewById(R.id.txtNextAlarm);
}
and in your static method use:
public static void NextTxt(){
text1.setText("");
}
I needed to change variables inside an inner class and I got the infamous "Cannot refer to a non-final variable inside an inner class defined in a different method" error.
void onStart(){
bt.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int q = i;
}
});
}
I quickly made a class that held all of the things I wanted to change and made a final version of the class outside the inner class
class temp{
int q;
}
void onStart(){
final temp x = new temp();
bt.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
x.q = i;
}
});
}
This seems to be what I need and it works but I am wondering if this is how to correctly work around the problem. Also, I really hate using the word temp to name my class. Is there an actual programming term for what I did so that I make a more descriptive name for my class?
You can simply create an inner class instead of an anonymous one (like you are currently doing). Then you have a constructor and any other methods you want to set your members. No hackiness required (like the array of 1 case).
I find this cleaner if the class requires any exchange of data with its outer class, but admit it is a personal preference. The array of 1 idiom will work as well and is more terse, but frankly, it just looks fugly. I typically limit anonymous inner classes to those that just perform actions without trying to update data in the outer class.
For example:
private MyListener listener = new MyListener();
void onStart(){
bt.setOnClickListener(listener);
}
class MyListener implements OnClickListener
{
String name;
int value;
void setName(String newName)
{
name = newName;
}
void setValue(int newValue)
{
value = newValue;
}
public void onClick(View v)
{
// Use the data for some unknown purpose
}
}
If there are multiple threads involved, then appropriate synchronization will have to be used as well.
I posted a similar answer in my other thread here. Basically the idea is to create a "wrapper" which wraps over pretty much any Object type. Since final in Java stands for "no reassignment" and not "constant", this trick pretty much works out fine. But as mentioned in the original post, make sure you tread with caution when using it in a multi-threaded environment.
I would keep a reference to your on click listener in the outer class, and make the int a member variable in your listener. Just store the variable in the listener on click, then grab the variable in the outer class when you need it, rather than setting it at the point of the click.
To put it simply, if the inner class needs to change it, make it a variable in the inner class.
Since you appear to be setting multiple things (from the comments), make a method in the main class, button1WasClicked(), (a better name might be doUpdate, doSave etc. - something relevant to what the button does), put the proper code there, and call it from the inner class / listener. (If you are using Swing I'd make it an Action, YMMV)
That way if later on there is a menu or an intent or a gesture that needs to execute the same stuff, the call is there.
Is it better to give default values to your instance variables in onCreate, onResume or just when declaring them? In code:
When declaring them:
public Class Foo extends Activity{
private String variable1 = "my super var";
private int variable2 = 42;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
OR during onCreate
public class Foo extends Activity{
private String variable1;
private int variable2;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
variable1 = "my super var";
variable2 = 42;
}
}
OR during on resume:
public class Foo extends Activity{
private String variable1;
private int variable2;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
protected void onResume() {
super.onResume();
variable1 = "my super var";
variable2 = 42;
}
}
Thank you.
The above answers are good, and it does depend on coding style BUT, as a rule, try to avoid assigning default values other than when the variables are declared. This will help with maintainability. When you come back to your code in 6 months to fix a weird bug, having defaults scattered throughout the code will add to your troubles.
Only use onCreate, onResume etc if there is a purpose in doing so and then, add a meaningful comment e.g.
// re-initialise foobarValue when the app regains focus
// to ensure that the wobbly gong generator starts from the beginning
foobarValue = 1;
Cheers
That all depends on your sense of coding style, and of course the instance variables being assigned. Often, a fair number of my instance variables are views and thus depend on having a valid context - so these I of course put in onCreate(). If I need a variable to be reset every time I leave an activity and return, then it has to be in onResume(). As for inline, I tend to do this when I know that the variable will not change and shouldn't change, and I make them final. The balance between inline constructed variables and onCreate() depends. Some people might like to have all of their assignments in one place, so onCreate() makes sense as a way to capture all assignments in a single location, if you don't care than there's no real performance difference between them, so put the assignment where you want.
I don't think there's a whole lot of difference from doing it as default values or in onCreate if the values are simple. What onCreate is good for is if you need activity-related things like a Context or something from the Intent, etc. Then you have to do it in onCreate.
However, doing this initialization in onCreate vs. onResume makes a huge difference. If you put code in onResume it runs every time you regain focus in the activity (for an exact definition you'll want to read the docs). This means that if you press home and then go back to your app, this code will run again. So it really depends on what behavior you want.