I want to modularize the usage of my class but I have problem in passing function. I want to be able to pass an OnClickListener from 1 activity to this CoachmarkActivity.
I tried 2 different method:
1. Passing an OnClickListener to Intent
2. Passing a class, FollowUpClass, implements Serializable, which has method onClick.
You can see the code below. It is not complete code, but you should be able to comprehend this.
public class CoachmarkActivity extends Activity {
public static final String RES_LAYOUT = "RES-LAYOUT";
public static final String LISTENER = "LISTENER";
public static final String FOLLOW_UP = "FOLLOW-UP";
#Override protected void onCreate(Bundle savedInstance) {
setContentView(getIntent.getIntExtra(RES_LAYOUT, R.layout.activity_default))
Button button1 = (Button) findViewById(R.id.button1);
Button button2 = (Button) findViewById(R.id.button2);
// 1ST ATTEMPT
// I want to modularize this
OnClickListener onClickPassedFromIntent = (OnClickListener) getIntent().getSerializableExtra(LISTENER);
button1.setOnClickListener(onClickPassedFromIntent);
// 2ND ATTEMPT
final FollowUpListener folllowup = (FollowUpListener) getIntent().getSerializableExtra(FOLLOW_UP);
button2.setOnClickListener(new OnClickListener() {
#Override void onClick() {
// !! Here is error, exception thrown
folllowup.onClick();
}
});
}
/**
* Public method to be used in other activity.
* Invocation wanna be:
* CoachmarkActivity.startThisActivity(getActivity(), R.layout.coachmark1, new OnClickListener() {
* #Override void onClick() {
* // Do something
* }
* });
*/
public static void startThisActivity(Context context, int resId, OnClickListener listener) {
Intent intent = new Intent(context, CoachmarkActivity.class);
intent.putExtra(RES_LAYOUT, resId);
// !! Line below is error, onClickListener is not serializable, no method can accomadate below
intent.putExtra(LISTENER, listener);
context.startActivity(intent);
}
/**
* Public method to be used in other activity.
* Invocation wanna be:
* CoachmarkActivity.startThisActivity(getActivity(), R.layout.coachmark1, new FollowUpListener() {
* #Override void onClick() {
* // Do something
* }
* });
*/
public static void startThisActivity(Context context, int resId, FollowUpListener folllowup) {
Intent intent = new Intent(context, CoachmarkActivity.class);
intent.putExtra(RES_LAYOUT, resId);
intent.putExtra(FOLLOW_UP, followup);
context.startActivity(intent);
}
}
The abstract class:
public abstract class FollowUpListener implements Serializable {
public abstract void onClick();
}
The problems are stated in the comment in source code above, with tag "!!" (Just CTRL+F "!!"). What I want to do is like passing a Delegate object (function in form of variable) in C#, but in Android Java.
Any idea? Thanks.
You are trying to add a Serializable extra to your Intent, but OnClickListener does not implement that interface. You can achieve what you want by creating a class that implements both of the interfaces you need.
private class SerializableClickListener implements View.OnClickListener, Serializable {
#Override public void onClick() {
// TODO handle click
}
}
However, just because you can doesn't mean you should. Sending a click listener to another activity is a horrible code smell, and you should really rethink how you could do this via Intents/Broadcasts.
I tried to pass the OnlclickListener and I couldn't. then I tried this solution.
I made a static click listener variable in a GlobalData class
public static View.OnClickListener btn;
Then when I call the startactivity to go to another activity I did this.
GlobalData.btn = new View.OnClickListener() {
#Override
public void onClick(View v) {
//Listern action
}
};
c.startActivity(new Intent(c, DialogActivity.class));
Then in the second activity, I can set the static listener reference which I used to assign a listener object in the first activity.
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(GlobalData.btn!=null){
GlobalData.btn1.onClick(v);
}
finish();
}
});
I didn't use it directly as a parameter so I can do other stuff in the second activity listener. this worked for me.
But you have to think more because you are using a static reference. this is not a 100% solution. but it's worth trying.
Related
I was wondering one thing today. Whenever we are setting up a ClickListener, we run this code.
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
I Opened the View Class and saw the OnClickListener interface and found that it is not static. The method is like this:
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* #param v The view that was clicked.
*/
void onClick(View v);
}
Then how are we able to access OnClickListener method directly by using class name?
For java, "A nested interface is implicitly static." jls (9.1.1.3)
You can implement class View.OnClickListener and then you will able to Override its method just like shown below :
public class YourActivity implements View.OnClickListener {
#Override
public void onClick(View v) {
}
}
this is probably simple but i am still a beginner
i have a button in class MainActivity and i want to use the onclick method in another class(another activity) i am aware that it could be easily achieved by making it public static and accessing it as instance but in my case i can not make it public static for some good reason
button xml:
<Button
android:id="#+id/googledrivemain"
android:layout_width="78dp"
android:layout_height="77dp"
android:layout_marginTop="149dp"
android:background="#drawable/google"
android:onClick="onClickOpenFile"
android:paddingTop="6dp"
android:textColor="#fff"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="#+id/imageView3"
app:layout_constraintHorizontal_bias="0.51" />
MainActivity button:
public void onClickCreateFile(View view) {
fileOperation = true;
// create new contents resource
Drive.DriveApi.newDriveContents(mGoogleApiClient)
.setResultCallback(driveContentsCallback);
}
second class button:
btn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MainActivity main = new MainActivity();
use onclick from mainactivity...??
}
});
Do it like this
btn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((MainActivity) getActivity()).onClickCreateFile(v);
}
});
i think it will work.
Simply wrap the code you invoke from the MainActivity.onClickCreateFile() into another class and call it from wherever you want
And never, NEVER, do something like new MainActivity(). Activities are managed by the system
You can create a handler class, something like this:
public static class ClickHandler {
private ClickHandler mInstance;
public static ClickHandler getInstance(){
if(mInstance == null){
mInstance = new ClickHandler();
}
return mInstance;
}
public void onClickCreateFile(View view) {
fileOperation = true;
// create new contents resource
Drive.DriveApi.newDriveContents(mGoogleApiClient)
.setResultCallback(driveContentsCallback);
}
}
Then wherever you need it:
btn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ClickHandler.getInstance().onClickCreateFile(view);
}
});
The reason you can't make a click method static is that 1) The android:onClick XML action requires public void and 2) The view that you are clicking belong to the instance of the activity, not the class.
You could make a static method like this.
public static void createDriveContents(GoogleApiClient apiClient, ResultCallback callback) {
Drive.DriveApi.newDriveContents(apiClient)
.setResultCallback(callback);
}
But, then you still need a reference to the GoogleApiClient object.
Since no client is bound to any one Activity, you could move it into a singleton in order to access one client instance from everywhere.
For example,
btn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MainActivity.createDriveContents(
GoogleClientWrapper.getInstance().getClient(), // A GoogleApiClient instance
new ResultCallback() {
// TODO: Implement
});
}
});
If you have access to the GoogleClient in the second class, just pass in the API client object directly.
Or, abstracting up one level, you can instead provide a Context, and re-build the client.
public static void createDriveContents(Context context, ResultCallback callback) {
GoogleApiClient client = new GoogleApiClient.Builder(context);
// TODO: add scopes to client
Drive.DriveApi.newDriveContents(apiClient)
.setResultCallback(callback);
}
With this method, we assume the second class is another activity without it's own GoogleClient
btn3.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MainActivity.createDriveContents(
SecondClass.this, // A Context instance
new ResultCallback() {
// TODO: Implement
});
}
});
Sorry if this question might be stupid for you, but I'm new to Android programming and I can't wrap my head around Java syntax.
Can you explain what is happening with this line of code step by step?
View.OnClickListener ourOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v){
ourMessage.setText(“The button got tapped”);
}
};
There is an interface declared inside View class, and it's OnClickListener, it looks like this in View.java source:
/**
* Interface definition for a callback to be invoked when a view is clicked.
*/
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* #param v The view that was clicked.
*/
void onClick(View v);
}
Normally you would create a class, and have it implement this interface:
public void MyClass implements View.OnClickListener {
#Override
public void onClick(View view) {
// do stuff
}
}
But sometimes you don't need this class in a separate file. Instead, you can create anonymous inner class, it's like creating new class, which only methods are the one from the interface specified:
new View.OnClickListener() {
#Override
public void onClick(View v){
ourMessage.setText(“The button got tapped”);
}
}
You can then use instance of this class everywhere the View.OnClickListener interface is needed.
What's also worth mentioning is that anonymous inner class will hold a reference to the class in which you're creating it. So this will be legal and valid:
public class MyClass {
private int clicksCount = 0;
private View.OnClickListener listener = new View.OnClickListener() {
#Override
public void onClick(View view) {
clicksCount += 1;
}
}
}
Here you can access clicksCount field, which is field of MyClass even from the inner class that implements OnClickListener. Side note - if you want to access a variable, you need to add final modifier to it:
public void testMethod(final int canAccess, int cantAccess) {
final String test = otherView.getText().toString();
myView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Cannot access cantAccess, because it's not final
if (test.length == 0) { // can access
// do something
}
}
}
This is probably a duplicate, but i can't find any thing on this so here goes.
I want to call a function in a class from file B.java into A.java with the onClick. Problem is, i get an error every time I add the line in. Here is my code and I'll give the error at the bottom.
A.java
import com.example.app.B;
public class MainService extends Service
{
private CallFunc callFunc;
private Button btn;
public void onCreate()
{
callFunc = new CallFunc();
btn = new Button(this);
//Code for setOnClickListener
#Override
public void onClick(View v)
{
callFunc();
}
}
}
B.java
public class CallFunc
{
public CallFunc()
{
//Stuff to do
}
}
Error I get
The method callFunc() is undefined for the type new View.OnClickListener(){}
//you are not calling your function:
import com.example.app.B;
public class MainService extends Service
{
private CallFunc callFunc;
private Button btn;
public void onCreate()
{
callFunc = new CallFunc();
btn = new Button(this);
//Code for setOnClickListener
#Override
public void onClick(View v)
{
callFunc.callFunc();//It is a good idea to use better method names. it looks like you are calling your constructor, not a method.
}
}
}
In your CallFunc class,
public CallFunc()
{
//Stuff to do
}
means it's constructor. It get called when you create it. In here callFunc = new CallFunc();.
You can include it to onClick method.
#Override
public void onClick(View v)
{
callFunc = new CallFunc();
}
Better way is to do this is add a method to CallFunc class because method means you do something. You do your stuff in that method. Class means a object like a car. Car can be drive. so it should have dirve() method. Then car.drive() means you drive the car. :)
#Override
public void onClick(View v)
{
callFunc.someMethod();
}
What you have in your B.java is a constructor not a method. A constructor is a special case method that gets invoked when an instance of that class is created. It is used to correctly initialise and populate new instances of a class.
What you were probably trying to do is:
public class CallFunc
{
public CallFunc()
{
// this is the constructor
// initialise the class instance here
}
public void someMethod()
{
// a method you can call
// perform actions here
}
}
Then in the onCreate() of your MainService you should:
#Override
public void onClick(View v)
{
callFunc.someMethod();
}
However, you are extending Service and using UI components (Button and onClick) when a Service does not have a UI. Are you sure you didn't want to use an Activity?
I'm trying to pass something from one class to my MainActivity, but it doesn't seem to work, I don't understand why.
I have my GPS Tracker on another class (not the MainActivity) in order to reuse it.
When the location changes, I want my other class to call a method from within the MainActivity to update my UI.
I summarized my code like that :
My MAIN ACTIVITY :
public class MainActivity extends Activity implements OnClickListener {
TextView tv;
EditText et;
Button btun;
int arg0;
int stuff;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
et = (EditText) findViewById(R.id.et);
btun = (Button) findViewById(R.id.btun);
btun.setOnClickListener(this);
}
private void setter(int stuff) {
tv.setText(stuff);
}
public void setText(int _stuff) {
_stuff = stuff;
setter(_stuff);
}
#Override
public void onClick(View v) {
Getter get = new Getter();
get.getInfo(Integer.parseInt(et.getText().toString()));
}
The other Class :
public class Getter {
int _getString;
MainActivity main = new MainActivity();
public void getInfo(int getString) {
_getString = getString * 8;
main.setText(_getString);
}
}
I end up having a NullPointerException in my LogCat
at :
- tv.setText(stuff);
- setter(_stuff);
- main.setText(_getString);
- get.getInfo(Integer.parseInt(et.getText().toString()));
and I don't really know why, and above all, how to fix it.
I'll appreciate any help !
(PS : My GPS tracker thingy is working fine, it's just about invoking my setter() method.
Instantiaing an Object of MainActivity doesn't automatically call onCreate method but this method is called when you start an activity using Intent; And using the same intent you can pass extra values. For example:
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("key", value);
context.startActivity(intent);
and then in your main activity onCreate method:
String value = getIntent.getStringExtra("key");
Edit:
In your case why don't you change your void getInfo(int getString) to return a String value i.e.
public class Getter {
...
...
public String getInfo(int getString) {
_getString = getString * 8;
return Integer.toString(_getString);
}
}
and then in onClick event of MainActivity bind this returned text to TextView
It's maybe because the MainActivity's onCreate()-Method hasn't been called. Therefore the tv is still null causing the NullPointerException
One problem is here. main is an Activity, but it should be the MainActivity calling this object.
public class Getter {
int _getString;
MainActivity main = new MainActivity();
public void getInfo(int getString) {
_getString = getString * 8;
main.setText(_getString);
}
}
I cannot really make out what you are trying to achieve in the Getter class, but either:
1: Pass the Activity instance to the object
public class Getter {
int _getString;
MainActivity _main = null;
public Getter(MainActivity main) {
_main = main;
}
public void getInfo(int getString) {
_getString = getString * 8;
_main.setText(_getString);
}
}
#Override
public void onClick(View v) {
Getter get = new Getter(this);
get.getInfo(Integer.parseInt(et.getText().toString()));
}
or
2: set the text in the Activity and only get the value from the Getter (My choice)
public class Getter {
int _getString;
MainActivity main = new MainActivity();
public void getInfo(int getString) {
return getString * 8;
}
}
#Override
public void onClick(View v) {
Getter get = new Getter();
int info = get.getInfo(Integer.parseInt(et.getText().toString()));
setText(Integer.toString(info));
}
Use Application Class or create a separate Class and declare a static variable in it. Use getter & setter methods to get the value. To update the Textview in mainacivity from other class pass the texview reference variable from main activity and put null check condition in other class if textview is not null then update the value.