在不使用 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));

        ......

    }

    .....

}