Calling methods without reference variable [duplicate] - java

This question already has answers here:
Calling a method inside another method in same class
(5 answers)
Why am I able to access a method without object in java [duplicate]
(2 answers)
Closed 3 years ago.
Could someone explain to me one thing about call methods, viz. When I was learning at Neatbeans, calling a method was always done using a reference variable, where I had to create a real object before, for example:
public class Question {
public static void main(String[] args) {
Test test = new Test();
test.method();
}
}
class Test {
void method() {
System.out.println("Test");
}
}
In this case, I had to create an object, assign its reference to the test variable, and then call the method.
However, in Android Studio, to call a method, I do not have to create a reference variable or an object, I only directly call the method ... for example:
public class SecondActivity extends AppCompatActivity {
EditText editText;
Button button2;
String name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
editText = findViewById(R.id.editText);
button2 = findViewById(R.id.button);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
prepareResult();
}
});
}
public void prepareResult() {
Intent i = new Intent();
name = editText.getText().toString();
i.putExtra("name", name);
setResult(RESULT_OK, i);
finish();
}
}
In this case, I do not create an object, and I do not assign its reference to 'X' variables, I immediately call the prepareResult method. Why is this happening?

In Java, when you call another method in the same class, you do not need to reference by it's class object.
Where when you call the method from same class, you can access method directly.

It's all a matter of scope. In your first example, you were trying to use the method method() from the class Test from within another class, Question.
In the second example, you can call prepareResult() directly because the method from where that call is issued, onCreate(), belongs to the same class SecondActivity.
This is possible because, essentially, they are in the same scope. All methods and variables in a particular class are visible amongst each other. Visibility outside of the class depends on the access modifiers, public, private, protected or the default package-private
You can find more details in this Oracle Java tutorial:
https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

In Java, whenever you call a function which is outside the activity, you are calling. You have to use a reference variable to call the other class constructor to build an object. It can be done in your case.
Test test = new Test();
test.method();
OR
new Test().method();
Whenever you call a function which is inside the same class(within where you defined the function), you can call directly using its name directly because you do not have to call the constructor of the class which is already created. Like you have done in your other code.
You can see the class do not change here.
public class SecondActivity extends AppCompatActivity {
EditText editText;
Button button2;
String name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
editText = findViewById(R.id.editText);
button2 = findViewById(R.id.button);
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
prepareResult();
}
});
}
public void prepareResult() {
Intent i = new Intent();
name = editText.getText().toString();
i.putExtra("name", name);
setResult(RESULT_OK, i);
finish();
}
}

Related

Implementing a class that will override the onClick()

I want to create a method that, when implemented in other classes, you just need to pass some parameters and then call the - onclick() function to set the element.
At the moment, I´ve just done this. But this gives me a RunTimeException
Unable to start activity ComponentInfo{com.example.test/com.example.testActivity.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.ActivityThread$ApplicationThread android.app.ActivityThread.getApplicationThread()' on a null object reference
my code:
Class: clickeable
imports ...
public class ClickeableOptions implements View.OnClickListener{
private CardView cardView;
private Context cont;
private Class actTarget;
public OpcionesMainClickeables() {}
public ClickeableOptions(CardView cardView, Context cont, Class actTarget) {
this.cardView = cardView;
this.cont = cont;
this.actTarget= actTarget;
}
//Getters and Setters
#Override
public void onClick(View v) {
getCardView().setOnClickListener(this);
Intent intent = new Intent(this.getCont(), this.getActTarget());
startActivity(intent);
}
}
And i want to implement this class like this...
public class MainActivity extends AppCompatActivity{
private CardView cvRegistration;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cvRegistration = (CardView) findViewById(R.id.cvRegistration);
ClickeableOptions optionRegistration = new ClickeableOptions(
cvRegistration, this, Registration.class
);
optionRegistration.onClick(optionRegistration.getCardView());
}
I've implemented the method in the same file, but I want to do it this way to keep things more tidy.
I think the problem is in the use of this, but i really don't get it
No need to call onClick explicitly from your Activity. Just try like below:
public ClickeableOptions(CardView cardView, Context cont, Class actTarget) {
this.cardView = cardView;
this.cont = cont;
this.actTarget= actTarget;
this.cardView.setOnClickListener(this);
}
And inside onClick
#Override
public void onClick(View v) {
Intent intent = new Intent(getCont(), getActTarget());
getCont().startActivity(intent);
}
And remove this line from Activity.
//optionRegistration.onClick(optionRegistration.getCardView());
Now when you clicked your CardView, Then Activity transitions start.
Try to replace this line:
startActivity(intent);
with
getCont().startActivity(intent);
Also, why are you inheriting ClickeableOptions from AppCompatActivity?
Although you have instantiated the ClickeableOptions (derived from Activity) object, none of its Activity life cycle methods have been called and none of the super class instantiation related work (normally should be done in onCreate) has been accomplished. Hence the ActivityThread is simply null and you've got an exception when invoking
startActivity(intent);
If you want to start another Activity on your CardView click then you need to
follow Leo Leontev's advice:
call
getCont().startActivity(intent)
instead of
startActivity(intent)
move the line
getCardView().setOnClickListener(this)
to the ClickeableOptions custom constructor's most bottom line
delete this line from your MainActivity$onCreate() method:
optionRegistration.onClick(optionRegistration.getCardView());
After all of above is done you'll be able to start new activity on click event.

How to define a specific layout onclick function globally for multiple activities

I need to define a layout for multiple activities in android and from the UI part, it is successful. But to code those elements to perform on each click listeners, I need to define it in all the java pages I use.
Can we globally define this in a java page and include it in the required pages?
menuButton = findViewById(R.id.menuButton);
menuButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(getApplicationContext(), MenuActivity.class);
startActivity(i);
finish();
overridePendingTransition(0, 0);
}
});
Yes and No.
You can create a BaseActivity which has the common logic that has to be executed for each button click.
But you need to implement the listener for the button on specific activity, since life cycle of each activity is independent of other activity.
To make the code readable better (avoiding implementing listener/setOnclickListener), you can use ButterKinfe, and create a method for OnClick() annotation, and call the method in BaseActivity.
What you essentially want to do is call the findViewById(), which can only be called if you have a reference to a Context variable. You should use your Activity Context, hence you pass this to the static function, which can then access all methods accessible via Context .
public class ExampleActivity2 extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MenuUtils.setListener(this);
}
}
Define the static class like this:
public static class MenuUtils{
public static void setListener(Context context){
menuButton = context.findViewById(R.id.menuButton);
menuButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// do stuff
}
});
}
}
What you should be careful about is that any Activity you pass to this function should have a menuButton in it's layout, otherwise you run the risk of getting a NullPointerException, which is when findViewById() cannot find menuButton.

Using object from other class

I have mainActivity class and class1. In class1 i have something like this
public void ownedAdd(int a)
{
owned = owned +a;
}
Simple. But when i want to call this method in MainActivity
Class1 obj1 = new Class1();
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
obj1.ownedAdd(10);
}
});
And in this place i have few question. Android Studio saying that obj1 need to be declared as final. I dont like that. What i want to do is using class1 object in main method. Is that possible? I want to make few objects of class1 each with some variable as price, owned etc and i have no idea how. For any help, thanks a lot ;)
What's wrong is that in JAVA, you cannot access a variable from a method to an anonymous class inside that method unless the variable is declared final inside the method, or the variable is itself global to the parent Class.
To solve your problem, set the obj1 variable to be global. Something like:
public class MainActivity extends AppCompatActivity {
//Declare the obj1 object here
Class1 obj1;
#Override
public void onCreate(Bundle savedInstanceState) {
//inflate layout and do other stuff
//from where you posted
obj1 = new Class1();
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
obj1.ownedAdd(10);
}
});
}
}
From the code given, you don't need the reference to the Class1 instance other than in the click listener, so you can simply make it a member variable of the View.OnClickListener:
button1.setOnClickListener(new View.OnClickListener() {
final Class1 obj1 = new Class1();
#Override
public void onClick(View v) {
obj1.ownedAdd(10);
}
});
(Although it is still worth making it final).
However, it's not super-useful like that, since only the click listener can access the instance - you can't display the value in another control, for example. It is simplest just to make your current local variable final.

In android, when is a context different from "this"?

I am at baby step level of programming on Android (and in Java in general). I do understand that Activity inherits from the Context class. However in every code snippet I have come across, every time a context must be mentionned, it is set to "this".
My question is : when is a context different from "this" ? Could you provide an real life example of context needing to be different from "this"?
Thank you very much.
Typically, you will want to use this when you are "inside" of an Activity. However, when you are using for example a Helper class, the reference this will not work. An example can be something like this:
public class MyActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
}
A case, where you cannot:
public class MyHelper
{
/* some code of yours */
public void lockOrientation(Activity activity)
{
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
}
The above code locks the orientation to the current orientation. Notice that you need to supply the method with an Activity parameter, since you cannot use:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
In the first example, you could use this to achieve this, because you were "inside" of an Activity.
Another type of example, how do you set onClickListener.
First example, when you use this:
public class MyActivity extends Activity implements View.OnClickListener
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Button btn=(Button)findViewById(R.id.mybutton);
btn.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
//handle the click event
}
}
In this example, you can use this because in the first line, we wrote implements View.OnClickListener, so the class inherits from the given interface. Without the implements thingie, you couldn't do it. An example of setting the onClickListener without this:
public class MyActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Button btn=(Button)findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
//handle the click event
}
});
}
}
In the second example, we are defining an Anonymous Inner Class, which will handle the click event of the button. Notice that in this case, our Activity does NOT implements View.OnClickListener.
In Outer Class you directly use "this" reference
In Inner Class Or Abstract Class implementation Or Interface implementation use "classname.this" reference
Example:
class Example{
int number = 0;
public Example(int number){
this.number = number;
}
}
notice that number in the contructor and number in the class are not the same. Altough they have the same name. Saying number = number doesn't make sense. Be using this you can asses number in the class.
For example when you are implementing an OnClickListener the "this" is different.
this is a reference to the current object — the object whose method or constructor is being called.
Inside an Activity's method this can be used as a Context object because Activity inherits from ContextThemeWrapper, which inherits from ContextWrapper, which inherits from Context.
A Fragment on the other hand does not inherit from Context. So to get the Context inside a Fragment you would have to call getActivity() for example.
This applies to any object you are calling this from.
Consider you are inside the OnClick() method of a View.OnClickListener and you want to start an Activity:
button.setOnClickListener (new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(this, NextActivity.class); // wrong because 'this' is the OnClickListener object
Intent intent = new Intent(CurrentActivity.this, NextActivity.class); // correct because 'this' is the CurrentActivity object
startActivity(intent);
}
});

Unit testing a method declared inside a method

I have an Android application, where inside an onCreate() method of an Activity a button is defined to have an onClick method. In code:
public void onCreate(Bundle savedInstanceState) {
/.../
buttonSave = (Button) findViewById(R.id.store_button_save);
buttonSave.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
saveEditor(v);
}
});
/.../
}
My question is, how can I call this nested method onCLick() from an Android unit test? myActivity.onClick(myButton) does not work, since onClick() is not a method defined in the activity itself.
Btw, I should not be changing any original source code for my tests.
You can test this by not creating such an anoynmous class.
Instead create a normal inner class, and assign a new instance to to the listener:
public static class MyClickListener implements OnClickListener {
Editor editor;
public MyClickListener(Editor e) {
this editor= e;
}
public void onClick(View v) {
editor.saveEditor(v);
}
}
buttonSave.setOnClickListener(new MyClickListener());
In JuniTest
public void testOnClickListener() {
Editor e = new Editor();
MyClickListener l = new MyClickListener(e);
l.onClick();
// however you check for correct result
assertTrue(checkSaveEditor(e));
}
But why not just write unitest for method saveEditor() only?
This is sufficient, you can rely that onClick() works.
The onClick method is defined inside an anonymous class, so you cannot directly invoke it. Instead you need trigger the click event from the outer class. Don't know much about Android development but the following post explains how to test such as scenario using ActivityManager to simulate a button click with #UIthreadTest annotation. How to call Button.performClick in Android JUnit test case?

Categories

Resources