Is it possible to make a secondary class to hold the OnClick Listener? Meaning not being created in the Activity class?
I just find that putting OnClick listeners in the main activity class is just messy and I would rather have them in separate classes. Thanks
Sure, that's possible. Just create a class that implements View.OnClickListener
and set that as listener to the View
. For example:
public class ExternalOnClickListener implements View.OnClickListener {
public ExternalOnClickListener(...) {
// keep references for your onClick logic
}
@Override public void onClick(View v) {
// TODO: add code here
}
}
And then set an instance of above class as listener:
view.setOnClickListener(new ExternalOnClickListener(...));
The parameterized constructor is optional, but it's very likely you'll need to pass something through to actually make your onClick(...)
logic work on.
Implementing a class anonymously is generally easier to work with though. Just a thought.
Instead of putting the onCLicklistener
in a separate class, why dont you try to define onClickListener
outside onCreate()
??
For e.g: like this
onCreate()
yourViewName.setOnClicklistener(listener):
Outside onCreate()
private OnClickListener listener = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
};
Yes you can. However, making the listener an inner class has one advantage - it can access the fields and variables of your activity class directly. If you make it a separate class, and your listener actually need to access 5 views, your listener constructor might look like this:
MyListener listener = new MyListener(context, button, textView1, textView2, ratingBar, imageView);
Which is kinda bulky too. If your listener is simple, go ahead and make it a separate class. Otherwise, its up to you for readability.
You can do it. But just think that you will not have a reference to the activity, neither to it's attributes, including all the views. (unless you make them public or accessible with getters methods).
Also, be extra carefull with storing references to the activity or any members on the listener, since they might avoid the garbage collector from getting the listener memory back.
Let me share how I code it using MVP. It's the best way to make a clean code. Remember each classes must have an interface to control it. I will show you with the simplest one.
Suppose you want to Toast a text onClick and control it from another class. Here's how it works. Creating interfaces are for nothing but to connect each other and you can review the code easily.
Create an interface for that MainActivity class.
public interface MainActivityView {
void showToast();
}
Create another interface for Presenter class.
public interface IMainPresenter<V extends MainActivityView> {
/*Generic Type is to make sure it comes from MainActivity class only and to avoid other class to access it.*/
void onAttach(V mainView);
void onButtonClick();
}
Remember interfaces are nothing but to override method for each classes.
Create Presenter class
public class MainPresenter<V extends MainActivityView> implements IMainPresenter<V> {
private V mainActivityView;
@Override
public void onAttach(V mainActivityView) {
this.mainActivityView=mainActivityView;
}
public V getView() {
return mainActivityView;
}
@Override
public void onButtonClick() {
getView().onToast(); //This is the method from MainActivity controlling with this class
}
}
I'll skip, activity_main.xml layout because there's just a button with id="@+id/buttonId." In MainActivityClass,
public class MainActivity extends AppCompactActivity implements MainActivityView {
Button btn;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainPresenter mainPresenter = new MainPresenter();
mainPresenter.onAttach(this);
btn = findViewById(R.id.buttonId);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mainPresenter.onButtonClick(); //Here, check No.3 again!
}
});
}
@Override
public void showToast() {
Toast.makeText(this, "Hello", Toast.LENGTH_SHORT).show();
}
}
All I want to tell you is that. If you create objects in a class, it cannot make unit testing. That's why you're not seeing any new objects calling in android. So, you can use singleton pattern (Here is Lazy Type) in Presenter class. I'll remove its interface and Generic to see it clearly.
public class MainPresenter {
private static final MainPresenter mainPresenter = new MainPresenter();
MainPresenter() {}
public static MainPresenter getInstance() {
return mainPresenter;
}
//Some methods here can be get it once you create object with getInstance();
}
And so you can get its methods from MainActivity like this.
Instead of creating objects like this...
MainPresenter mainPresenter = new MainPresenter();
You can get it like this...
MainPresenter mainPresenter = mainPresenter.getInstance();
More example for singleton pattern can be found here,
https://www.journaldev.com/1377/java-singleton-design-pattern-best-practices-examples
Finally, using static is not a very good choice because it uses memory space whether you use it or not. And so, you can create objects within Application Layer get it with a Typecasting. I'm sure you don't need to unit test that Application layer.
public class AppLayer extends Application {
private MainPresenter mainPresenter;
@Override
public void onCreate() {
super.onCreate();
mainPresenter = new MainPresenter();
}
public MainPresenter getMainPresenter() {
return mainPresenter;
}
And you need to give a class name within Application in manifest.xml
<application
android:name=".AppLayer"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>
And you can get it with a Typecast in MainActivity like this!
MainPresenter mainPresenter = ((AppLayer)getApplication()).getMainPresenter();
- For further studies, I suggest you to learn ButterKnife, Dagger 2 and SOLID Principles. It will help you to create clean coding. Have fun!