Reputation: 2555
To avoid "inner class hell" in case of Android event listeners, I have moved the listeners to separate classes. Following is one of such listeners for a TextView
which holds a date string. On touching it, I open a DatePickerDialog
and set the selected date value back to the TextView
.
I further enhanced this listener to use Butterknife as follows:
public class DateViewClickListener implements View.OnClickListener {
private final DateTime prevDate;
private DateTimeFormatter dateFmt;
public DateViewClickListener(DateTime prevDate, DateTimeFormatter dateFmt) {
this.prevDate = prevDate;
this.dateFmt = dateFmt;
}
@Override
public void onClick(View view) {
new DatePickerDialog(view.getContext(), new DatePickerDialog.OnDateSetListener() {
@InjectView(R.id.date)
TextView dateView;
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
Activity activity = ActivityUtil.getParentActivity(view);
ButterKnife.inject(this, activity.getWindow().getDecorView());
DateTime newDate = prevDate.withDate(year, monthOfYear, dayOfMonth);
dateView.setText(dateFmt.print(newDate));
}
}, prevDate.getYear(), prevDate.getMonthOfYear(), prevDate.getDayOfMonth()).show();
}
}
ActivityUtil.getParentActivity(view)
used in the above code, scans through the context hierarchy of the view and finds its parent activity. Following is the code for it:
public class ActivityUtil {
public static Activity getParentActivity(View view) {
Context context = view.getContext();
return scanForActivity(context);
}
private static Activity scanForActivity(Context context) {
if (context == null)
return null;
else if (context instanceof Activity)
return (Activity) context;
else if (context instanceof ContextWrapper)
return scanForActivity(((ContextWrapper) context).getBaseContext());
return null;
}
}
On executing this code, the dateView
remains null
throwing an NPE
. However, this code works for me when I don't use Butterknife (the DateViewClickListener
class is as follows in that case).
public class DateViewClickListener implements View.OnClickListener {
private final DateTime prevDate;
private DateTimeFormatter dateFmt;
public DateViewClickListener(DateTime prevDate, DateTimeFormatter dateFmt) {
this.prevDate = prevDate;
this.dateFmt = dateFmt;
}
@Override
public void onClick(View view) {
new DatePickerDialog(view.getContext(), new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
Activity activity = ActivityUtil.getParentActivity(view);
TextView dateView = (TextView) activity.findViewById(R.id.date);
DateTime newDate = prevDate.withDate(year, monthOfYear, dayOfMonth);
dateView.setText(dateFmt.print(newDate));
}
}, prevDate.getYear(), prevDate.getMonthOfYear(), prevDate.getDayOfMonth()).show();
}
}
Where is my understanding going wrong?
Upvotes: 0
Views: 514
Reputation: 2555
It seems that Butterknife injection works only if Butterknife.inject()
statement is present in the constructor or any of the Android life-cycle methods.
Hence, I have modified the DateViewClickListener
class to accept the activity that it gets called from and use it as the "source" for Butterknife injection something like:
public class DateViewClickListener implements View.OnClickListener {
@InjectView(R.id.date)
TextView dateView;
private final DateTime prevDate;
private DateTimeFormatter dateFmt;
public DateViewClickListener(DateTime prevDate, DateTimeFormatter dateFmt, Activity contextActivity) {
Butterknife.inject(this, contextActivity);
this.prevDate = prevDate;
this.dateFmt = dateFmt;
}
.....
}
And then instantiate the listener like:
public class MainActivity extends ActionBarActivity {
.....
@Override
protected void onCreate(Bundle savedInstanceState) {
......
date.setOnClickListener(new DateViewClickListener(paymentDate, dateFmt, this));
......
}
.....
}
Upvotes: 1