在不使用 Butterknife 的侦听器中注入视图
Injecting view in a listener not working with Butterknife
为了避免 "inner class hell" 在 Android 事件侦听器的情况下,我已将侦听器移动到单独的 classes。以下是 TextView
的此类侦听器之一,其中包含一个日期字符串。触摸它时,我打开 DatePickerDialog
并将所选日期值设置回 TextView
。
我进一步增强了此侦听器以使用 Butterknife,如下所示:
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)
在上面的代码中使用,扫描视图的上下文层次结构并找到它的父级 activity。以下是它的代码:
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;
}
}
执行此代码时,dateView
仍然 null
抛出一个 NPE
。但是,当我不使用 Butterknife 时,这段代码对我有用(在这种情况下 DateViewClickListener
class 如下)。
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();
}
}
我的理解哪里出错了?
似乎 Butterknife 注入只有在构造函数或任何 Android 生命周期方法中存在 Butterknife.inject()
语句时才有效。
因此,我修改了 DateViewClickListener
class 以接受从中调用它的 activity 并将其用作 Butterknife 注入的 "source",例如:
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;
}
.....
}
然后像这样实例化监听器:
public class MainActivity extends ActionBarActivity {
.....
@Override
protected void onCreate(Bundle savedInstanceState) {
......
date.setOnClickListener(new DateViewClickListener(paymentDate, dateFmt, this));
......
}
.....
}
为了避免 "inner class hell" 在 Android 事件侦听器的情况下,我已将侦听器移动到单独的 classes。以下是 TextView
的此类侦听器之一,其中包含一个日期字符串。触摸它时,我打开 DatePickerDialog
并将所选日期值设置回 TextView
。
我进一步增强了此侦听器以使用 Butterknife,如下所示:
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)
在上面的代码中使用,扫描视图的上下文层次结构并找到它的父级 activity。以下是它的代码:
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;
}
}
执行此代码时,dateView
仍然 null
抛出一个 NPE
。但是,当我不使用 Butterknife 时,这段代码对我有用(在这种情况下 DateViewClickListener
class 如下)。
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();
}
}
我的理解哪里出错了?
似乎 Butterknife 注入只有在构造函数或任何 Android 生命周期方法中存在 Butterknife.inject()
语句时才有效。
因此,我修改了 DateViewClickListener
class 以接受从中调用它的 activity 并将其用作 Butterknife 注入的 "source",例如:
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;
}
.....
}
然后像这样实例化监听器:
public class MainActivity extends ActionBarActivity {
.....
@Override
protected void onCreate(Bundle savedInstanceState) {
......
date.setOnClickListener(new DateViewClickListener(paymentDate, dateFmt, this));
......
}
.....
}