So I realize that this question has been asked a lot but I wasn't able to apply any of the others to my situation in a way that I was able to. Basically I am having trouble with global objects in Java as most of my experience is in Python.
Below is my code. Bascially checkbox1 is where I would like it to be, but I don't know how to get my two methods to recognize that it is there. I could fix this by defining checkbox1 in both resetAll as well as doMath but I am sure there is a better way around this
public class MainActivity extends ActionBarActivity {
// right here is where I want my objects so that both resetAll and doMath can use them
CheckBox checkbox1 = (CheckBox)findViewById(R.id.checkBox1);
public void resetAll(View view){
// do stuff with checkbox1
}
public void doMath(View view){
// do stuff with checkbox1
}
problem:
CheckBox checkbox1 = (CheckBox)findViewById(R.id.checkBox1);
You cant just initialized a View before you inflate or set the contentView of the activity or else you'll get a NPE.
solution:
Create a global variable which you already did but dont initialized it first.
CheckBox checkbox1;
In your onCreate method of the ActionBarActivity you then initialized it after the setContentView(R.layout.your_layout_for_the_checkbox);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.internal_main);
checkbox1 = (CheckBox)findViewById(R.id.checkBox1);
}
After youve done that you can call the checkbox1 field in both of the methods as long as that method are inside your MainActivity class
If you mean you want it to be accessible throughout MainActivity, you need to declare that checkbox as a member:
public class YourActivity extends Activity{
private CheckBox mCheckBoxOne;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activty_your);
mCheckBoxOne = (CheckBox)findViewById(R.id.checkBox1);
}
public void resetAll(View view){
mCheckBoxOne.setChecked(!mCheckBoxOne.isChecked());
}
public void doMath(View view){
mCheckBoxOne.setChecked(!mCheckBoxOne.isChecked());
}
}
if you want it to be accessible from other places, you need to cast the context to MainActivity or use interface . is that what you want?
Related
I am trying to define global objects using the application class.
I therefore define the following class.
public class MyApplication extends Application {
private MyObject myObject=new MyObject();
public MyObject getMyObject(){
return this.myObject;
}
}
Then, I use it in an activity, but I get an error (Cannot resolve method getApplication()):
public class AnActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mood);
Button buttonMusic=(Button) findViewById(R.id.button5);
buttonMusic.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyApplication myApplication = ((MyApplication)this.getApplication());
Toast.makeText(MoodActivity.this, "playing music", Toast.LENGTH_SHORT).show();
}
});
}
}
I have no clue why I get this error, as it for example works when calling the getApplication() in another activity.
I'm pretty new to Android and Java, so please excuse the ingenuity of the question.
UPDATE
Then I do MyObject myObject=myApplication.getMyObject(); and I don't get any compilation issue but the app dies as soon as I get in that activity.
As I understand it is not advised to use the Application class for such use, what would be a good alternative?
You're getting this error because you call this.getApplication() inside the View.OnClickListener. Because of this, this now references the listener and not the activity.
To do what you need, just create a Context object outside of the listener in your activity's onCreate method and assign this to it. And, inside the listener, use context instead of this. Something like this :-
public class AnActivity extends Activity {
Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mood);
context = this;
Button buttonMusic=(Button) findViewById(R.id.button5);
buttonMusic.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
MyApplication myApplication = ((MyApplication)context.getApplication());//Changed "the" to "context"
Toast.makeText(MoodActivity.this, "playing music", Toast.LENGTH_SHORT).show();
}
});
}
}
Edit after question update :-
Instead of using the application class, use static objects to achieve global variables. static objects are independent of objects and can be referenced using the class that they belong to. For example, if you define a static variable in your MainActivity.class and name it testObject, then it can be accessed using the following code regardless of your current activity :-
YourObject object = MainActivity.testObject;
Unless you have a specific reason for extending the Application class in Android you probably shouldn't. For reference, look at the note in the documentation for this: https://developer.android.com/reference/android/app/Application.html .
If you are trying to create an object that you can use in your Android app, simply do that as you would in Java:
public class MyObject {
//Your stuff here
}
If there is a reason that you're specifically wanting to extend the Application class then perhaps there's more that people can do to help you if you explain what you're trying to do. I just don't necessarily see a need to go through all that complexity based on your example :)
Change this to AnActivity.this.
Inside the code below the meaning of this changes from AnActivity to View.onClickListener as it is another object and inside those braces you are in the scope of the click listener class
new View.OnClickListener() {
public void onClick(View v) {
MyApplication myApplication = ((MyApplication)this.getApplication());
Toast.makeText(MoodActivity.this, "playing music", Toast.LENGTH_SHORT).show();
}
}
So the code above should become
new View.OnClickListener() {
public void onClick(View v) {
MyApplication myApplication = ((MyApplication)AnActivity.this.getApplication());
Toast.makeText(MoodActivity.this, "playing music", Toast.LENGTH_SHORT).show();
}
}
You can read a bit more about it here
Have some problem with android finish() methods.
I have one parent-class activity. Lets call it ParentActivity. All other activities in my project extends ParentActivity. Each time on ParentActivity.onCreate there are some statement, and I want to stop activity from executing if it fails. But when I call finish() in parent, I cant stop executing onCreate method on its child. Something like that:
public class ParentActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!someStatement) finish();
}
public class Test extends ParentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("TAG", "I dont want this code!");
}
}
Surely, I can just verify in parent activity its status each time, but I dont think its a good idea.
public class Test extends RexActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (isFinishing()) return; /// It works - but it bad :(((
Log.d("TAG", "I dont want this code!");
}
}
Can I somehow stop executing onCreate method on child activity from its parent? Many thanks for any help!
I'm not sure if I got your question right. As you have some grammatical issues.
The onCreate statements are always executed. You can either have a Boolean in ParentActivity to stop the code from executing in ChildActivity#onCreate().
You can try making your onCreate() code more modular by dividing it into functions so that it's not called.
Let me know what works for you.
Best option is to Use finish() in your splash screen just before you create your second activity,
Suppose we have an Activity with a lot of views on which OnClickListener is to be registered.
The most common way to implement this is to let the Activity-Subclass implement the OnClickListener, something like this:
public class ActivityMain extends Activity implements View.OnClickListener
{
#Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
}
The way I like to implement it is to create a private class inside the Activity-Subclass and let that inner class implement the OnClickListener:
public class ActivityMain extends Activity implements View.OnClickListener
{
private class ClickListener implements View.OnClickListener
{
#Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
}
}
This way the code seems more organized and easy to maintain.
Moreover, talking about "Is-a", "Has-a" relationships, the latter seems to be a good practice because now the Activity-Subclass would have a "Has-a" relationship with the ClickListener.
While in the former method we would be saying that Our Activity-Subclass "Is-a" ClickListener, which ain't completely true.
Note that, I am not concerned with the memory overhead the latter would cause.
Also, adding onClick tag in xml is completely out of question.
So, what really is the best way to implement a ClickListener?
Please don't suggest any libraries like RoboGuice or ButterKnife etc.
UPDATE:
I would like to share the approach I finally adopted.
I directly implement the listener in Activity/Fragment.
As far as OOP design is concerned. The "HAS-A" approach doesn't offers any practical benefits and even takes up more memory. Considering the amount of nested classes (and the memory overhead) we will be creating for every similar listener we implement, this approach should clearly be avoided.
First, there is no best practice defined by Android regarding registering click listeners. It totally depends on your use case.
Implementing the View.OnClickListener interface to Activity is the way to go. As Android strongly recommends interface implementation over and over again whether it is an Activity or Fragment.
Now as you described :
public class ActivityMain extends Activity implements View.OnClickListener
{
private class ClickListener implements View.OnClickListener
{
#Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
}
}
This is your approach. Now it is your way of implementation and there is nothing wrong with this if you are not concerned with memory overhead. But what's the benefit of creating the inner class and implementing the View.OnClickListener if you can simply implement that in the main class which can also lead to the code clarity and simplicity that you need.
So it just a discussion rather getting the best possible solution of implementing the View.OnClickListener because if you go with the practical point of everyone, you will go for a solution which is simple and memory efficient.
So I would prefer the conventional way. It keeps things simple and efficient. Check the code below:
#Override
public void onClick(View view)
{
switch (view.getId())
{
//handle multiple view click events
}
}
P.S : Your approach will definitely increase lines of code :P ;)
First of all lets get the basics clear here..
By implementing an Interface, your class doesn't become that.. like you said:
"Our Activity-Subclass "Is-a" ClickListener, which ain't completely true."
Your class can only have "Is-a" relationship if it extends, in this case an Activity. Implementing an interface means that it can behave like what interface has set its contract.
An Example:
class Peter extends Human .. means Peter is a Human..
class Peter can also implement programmer, musician, husband etc
means Peter can behave as the above.
As for best practice, you could make an entirely separate class which implements OnClickListener like this:
class MyListener implements View.OnClickListener{
#Override
public void onClick(View view) {
// do whatever you want here based on the view being passed
}
}
And in your main Activity you could instantiate MyListener and call onClick() and pass your view in it:
MyListener listener = new MyListener();
Button b = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.button);
listener.onClick(button);
}
I use button.setOnClickListener(this); where my Activity implements View.OnClickListener, and then get the ID of the Button in a separate method. See below for an example:
public class MyActivity extends ActionBarActivity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.YOUR_LAYOUT);
...
Button myFirstButton = (Button) findViewById(R.id.YOUR_FIRST_BUTTON);
myFirstButton.setOnClickListener(this);
Button mySecondButton = (Button) findViewById(R.id.YOUR_SECOND_BUTTON);
mySecondButton.setOnClickListener(this);
...
}
...
#Override
public void onClick(View v) {
Button b = (Button) v;
switch(b.getId()) {
case R.id.YOUR_FIRST_BUTTON:
// Do something
break;
case R.id.YOUR_SECOND_BUTTON:
// Do something
break;
...
}
}
...
}
Here you can create a btnClickListner object and after that you will call that btnCLickLisner object when ever you want to perform the onCLieck actions for buttons..
Let us assume, in my activity i have a 5 to 10 buttons and writing each button separate onclick listner is bad idea. So to over come this,we can use like below..
register your buttons
Button button1 = (Button)findViewById(R.id.button1);
Button button2 = (Button)findViewById(R.id.button2);
Button button3 = (Button)findViewById(R.id.button3);
Button button4 = (Button)findViewById(R.id.button4);
Button button5 = (Button)findViewById(R.id.button5);
Here i am setting the onclick listner to my buttons after click
button1.setOnClickListener(btnClickListner);
button2.setOnClickListener(btnClickListner);
button3.setOnClickListener(btnClickListner);
button4.setOnClickListener(btnClickListner);
button5.setOnClickListener(btnClickListner);
Here is the btnClick Listner implementation
View.OnClickListener btnClickListner = new OnClickListener()
{
#Override
public void onClick( View v )
{
// TODO Auto-generated method stub
if( button1.getId() == v.getId() )
{
//Do Button1 click operations here
}
else if( button2.getId() == v.getId() )
{
// Do Button2 click operations here
}
else if( button3.getId() == v.getId() )
{
// Do Button3 click operations here
}
else if( button4.getId() == v.getId() )
{
// Do Button4 click operations here
}
else if( button5.getId() == v.getId() )
{
// Do Button5 click operations here
}
}
}
I have found using Butterknife makes for clean code. And because it uses code generation (not reflections) it has little performance overhead.
public class ActivityMain extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
}
#OnClick(R.id.button_foo)
void onFoodClicked() {
// Do some foo
}
#OnClick(R.id.button_bar)
void onBarClicked() {
// do some bar
}
}
For this particular case I'd say that maintain a single instance of a OnClickListener is the best approach for you. You will have a "Has-a" relationship and won't need to create several instances since you are handling the behavior using the view id in the onClick(View view) callback.
public class ActivityMain extends Activity implements View.OnClickListener {
private View.OnClickListener mClickListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
switch (view.getId()) {
//handle multiple view click events
}
}
};
}
Your ClickListener is an inner non-static class the coupling of this 'has-a' is no different than if your class Activity implemented View.OnClickListener. This is because your inner ClickListener requires an instance of ActivityMain and really can't be reused. I would argue that you're over engineering and aren't actually gaining anything.
EDIT: To answer your question I like to have anonymous View.OnClickListener for each widget. I think this creates the best separation of logic. I also have methods like setupHelloWorldTextView(TextView helloWorldTextView); where I put all my logic related to that widget.
First approach is better than the other because thats why View.OnClickListener is an Interface instead of an abstract class. besides the later might leak in various situations since you are using a non-static inner class.
A small remark to this, and maybe a little bit of topic.
What, if we not just implement OnClickListener and we have a bunch of other Listeners / Callback to implement. In my Opinion it will get messy to implement all of these in the class instead of using anonymous classes / lambda. It is hard to remember wich method belongs to which interface.
So if we have to implement an interface (in this case OnClickListener) multiple times it my be a good solution to implement on class base and use the switch/case.
But if we have to implement multiple interfaces it may be a good solution to use anonymous classes / lambda
simply you using like not implements subclass or not handle a click event just do like this way .
android.view.View.OnClickListener method_name = new android.view.View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
// put your code .
}
};
and handle click event into button ya any type of click event like
button_name.setOnClickListener(method_name);
its work very simply
Thanks
public class ProfileDetail extends AppCompatActivity implements View.OnClickListener {
TextView tv_address, tv_plan;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile_detail);
tv_address = findViewById(R.id.tv_address);
tv_plan = findViewById(R.id.tv_plan);
tv_address.setOnClickListener(this);
tv_plan.setOnClickListener(this);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv_plan:
startActivity(new Intent(getApplicationContext(),PlanActivity.class));
break;
case R.id.tv_address:
startActivity(new Intent(getApplicationContext(),AddressActivity.class));
break;
}
}
}
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Chronometer chronometer;
private Button startButton;
private Button stopButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chronometer = findViewById(R.id.chronometer);
startButton =findViewById(R.id.startBtn);
stopButton = findViewById(R.id.stopBtn);
startButton.setOnClickListener(this);
stopButton.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.startBtn:
chronometer.start();
break;
case R.id.stopBtn:`
chronometer.stop();
break;
}
}
}
It really depends on what you want to achieve. If you have e.g. a complex functionality with threading, dependencies, etc., I personally like to decouple it completely from the Activity into a separate class XyzAction, that does the heavy stuff, knows about certain Invokers and returns them results, if needed. My Invokers are basically objects, that implement OnClick/OnTouch/etc.Listeners and bind themselves to needed actions. E.g. there could be a LoginInvoker implementing OnClickListener for a Button and an ImageView and also a generic ActionListener that gets invoked when a MenuItem is clicked. The Invoker has update methods for showing progress to the user and the result of the bound action. The action posts updates to its Invokers and can be garbage collected, if all of them die, because it has no connection to the UI.
For less complex actions, I couple them directly to the Android component (i.e. Activity/Feagment/View) and also call them Actions, with the big difference of them implementing the UI callbacks directly.
In both cases I declare the actions as members, so I can see on a quick glance what specific actions the Android component supports.
If there's something trivial like "show a Toast if button is pressed", I use anonymous inner classes for the UI callbacks, because you normally don't care that much about them with regards to maintainability.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button north,south,east,west;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
north.setOnClickListener(this);
south.setOnClickListener(this);
east.setOnClickListener(this);
west.setOnClickListener(this);
}
private void init(){
north = findViewById(R.id.north);
south = findViewById(R.id.south);
east = findViewById(R.id.east);
west = findViewById(R.id.west);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.north:
Toast.makeText(MainActivity.this,"NORTH",Toast.LENGTH_SHORT).show();
break;
case R.id.south:
Toast.makeText(MainActivity.this,"SOUTH",Toast.LENGTH_SHORT).show();
break;
case R.id.east:
Toast.makeText(MainActivity.this,"EAST",Toast.LENGTH_SHORT).show();
break;
case R.id.west:
Toast.makeText(MainActivity.this,"WEST",Toast.LENGTH_SHORT).show();
break;
}
}
}
From the android development perspective, while you are programming which way do you prefer to implement for listener? Or which way do you think is the best for readable code? I gave two example about these things but think more complex classes such as which has more than one Listener:)
First example which is an Anonymous Class:
public class SenderReceiverActivity extends Activity {
Button cancelButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sending);
cancelButton = (Button) findViewById(R.id.button1);
cancelButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
}
});
}}
Second example which is implementing interface :
public class SenderReceiverActivity extends Activity implements OnClickListener {
Button cancelButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sending);
cancelButton = (Button) findViewById(R.id.button1);
cancelButton.setOnClickListener(this);
}
public void onClick(View v) {
}
}
if you have single button then first approch is right because there are no any complexity in your code but when you have many button then second is more clear ,just one onClick method for many buttons and check id of button using v.getId()
But there are no any change in functionality both are identical.
I think 2nd approch is good as
1- you can handle multiple Views click at one place...
2- it make code shorter and easy to read..
3- it is easy in maintenance.
4- if you are using the Base Activity like concept in your project then it is also useful.
Well, there isn't really much differences between both except one: in second case you have access to onClick(View v) method from outside the class.
If it comes to me I prefer first approach, because not often more than one component have at the same time the same behaviour on click.
I have experience with programming languages but am a bit new to android programming.
I have a program with some fields that function as labels(textview), buttons, and data entry(edittext).
Whenever i declare them at the beginning of the program out of any methods(but in the class of course), when I start my application it crashes and simulation gives a "unfortunately, your program has stopped" alert.
Eclipse doesn't give any errors for the declaration and i did use the same way for defining regular variables with no issue. It also gives the same error when i declare a mediaplayer object in the class body.
Does anyone know why it gives error?
And is there another way to declare global objects like edittext, viewtext, etc... Declaring them over and over again in methods sounds weird to me.
Thank you!!
public class TrainerActivity extends Activity {
Button stopTimer = (Button)findViewById(R.id.StopTimer);
Button startTimer = (Button)findViewById(R.id.StartTimer);
EditText totalTime = (EditText)findViewById(R.id.TotalTime);
EditText enterMin = (EditText)findViewById(R.id.EnterMin);
EditText enterSec = (EditText)findViewById(R.id.EnterSec);
private boolean breaker = false;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startTimer.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Button_StartTimer();
}
});
stopTimer.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
Button_StopTimer();
}
});
}
Without seeing example code of what you're trying it's impossible to say for definite (we don't do mind-reading here). But let me guess, you're doing something like this?...
public class MyActivity extends Activity {
TextView tv1; // This is fine.
TextView tv2 = (TextView) findViewById(R.id.textview2); // Don't do this.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv1 = (TextView) findViewById(R.id.textview1); // This is fine
tv1.setText("Some text"); // This works
tv2.setText("Some text"); // NullPointerException here
}
}
The tv2.setText(...) will fail because you used findViewById(...) BEFORE you call setContenetView(...) and as a result, tv2 will be null.
It's quite acceptable to declare your widgets as instance members in your Activity but don't try to use findViewById(...) until AFTER you have set your content view.
try declaring the widget objects names only outside the onCreate() method
Button stopTimer;
Button startTimer;
EditText totalTime;
EditText enterMin;
EditText enterSec;
then initialise them after setContentView() inside onCreate()
setContentView(R.layout.main);
stopTimer = (Button)findViewById(R.id.StopTimer);
startTimer = (Button)findViewById(R.id.StartTimer);
totalTime = (EditText)findViewById(R.id.TotalTime);
enterMin = (EditText)findViewById(R.id.EnterMin);
enterSec = (EditText)findViewById(R.id.EnterSec);
Can you post a bit of sample code that illustrates the issue? It is fine to declare a member variable that is an EditText or TextView in the class.
logcat(in DDMS) should be give you some info about the error as well. If you are using eclipse there is a tab for DDMS, if not you can just run DDMS from a command line look at the logcat tab and launch your app (with your phone plugged in via usb, of course.) You should be able to see the actual error being reported.
You can declare these variables inside the Class body or inside the method body. In the former case, the variables are global and thus can be accessed within the whole class; in the latter case, they are local and thus can be only accessed within that method. Both of them could be commonly seen in proramming.
In Android, the typical application is that you declare the variables in the Class body and instantiate them in the onCreate() method. Something like this:
public Class MyClass extends Activity{
TextView label;// so this variable can be accessed within any methods in this Class
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(Bundle savedInstanceState);
setContentView(R.layout.main) // load the layout of the activity
label=(TextView)findViewById(R.id.<the TextView id defined in the layout file>); //this variable get instantiated. From now on you can manipulate it anywhere inside the class.
Button submit=(Button)findViewById(R.id.<the Button id defined in the layout file>);//you declared and instantiated it, but it could only be used within this method since you declared it here.
}
}
If you just declare a variable in the Class body,in most caeses, you can't use it until you instantiate it, because they are null before the instantiation. I think this is why you have problems. Please post the logcat so we can specify the real problem.