引入 Butterknife 库导致片段 class 绑定视图时出现运行时异常

Introducing Butterknife library causes runtime exception in fragment class when binding views

我开始重构我的应用程序以使用 Butterknife 库进行视图绑定。在我的 activity class 中,一切都按预期工作,但我无法理解如何在我的静态片段 class 中正确使用 butterknife。我的片段包含一个 RecyclerView 适配器,其中包含一个 CardView 元素列表。

重构前

public static class PlaceholderFragment extends Fragment {

        Activity mActivity;
        RecyclerView mRecyclerView;
        TaskAdapter taskAdapter;
        FloatingActionButton mFabView;
        TextView m_ID;
        TextView mTitle;

...

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {

            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            mRecyclerView = (RecyclerView) rootView.findViewById(R.id.cardList);
            mFabView = (FloatingActionButton) rootView.findViewById(R.id.normal_plus);

            mFabView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

还有

        @Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            mRecyclerView.setAdapter(taskAdapter);
            mRecyclerView.setHasFixedSize(true);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
            mRecyclerView.setItemAnimator(new DefaultItemAnimator());
            taskAdapter.SetOnItemClickListener(new TaskAdapter.OnItemClickListener() {

                @Override
                public void onItemClick(View v, int position) {
                    m_ID = (TextView) v.findViewById(R.id._task_id);
                    mTitle = (TextView) v.findViewById(R.id.title);
                    Intent detailIntent = new Intent(v.getContext(), DetailActivity.class);
                    detailIntent.putExtra("TASK_ID", m_ID.getText().toString());
                    detailIntent.putExtra("TASK_TITLE", mTitle.getText().toString());

重构后

public static class PlaceholderFragment extends Fragment {

        Activity mActivity;
        TaskAdapter taskAdapter;
        @Bind(R.id.cardList) RecyclerView mRecyclerView;
        @Bind(R.id.normal_plus) FloatingActionButton mFabView;
        @Bind(R.id._task_id) TextView m_ID;
        @Bind(R.id.title) TextView mTitle;

...

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {

            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            ButterKnife.bind(this, rootView);

...

        @Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            mRecyclerView.setAdapter(taskAdapter);
            mRecyclerView.setHasFixedSize(true);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
            mRecyclerView.setItemAnimator(new DefaultItemAnimator());
            taskAdapter.SetOnItemClickListener(new TaskAdapter.OnItemClickListener() {

                @Override
                @OnClick({R.id._task_id, R.id.title})
                public void onItemClick(View v, int position) {
                    ButterKnife.bind(this, v);
                    Intent detailIntent = new Intent(v.getContext(), DetailActivity.class);
                    detailIntent.putExtra("TASK_ID", m_ID.getText().toString());
                    detailIntent.putExtra("TASK_TITLE", mTitle.getText().toString());

我看到的异常是

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.github.idclark.forgetmenot/com.github.idclark.forgetmenot.MainActivity}: java.lang.RuntimeException: Unable to bind views for com.github.idclark.forgetmenot.MainActivity$PlaceholderFragment

...

Caused by: java.lang.RuntimeException: Unable to bind views for com.github.idclark.forgetmenot.MainActivity$PlaceholderFragment
                                                                                    at butterknife.ButterKnife.bind(ButterKnife.java:322)
                                                                                    at butterknife.ButterKnife.bind(ButterKnife.java:279)
                                                                                    at com.github.idclark.forgetmenot.MainActivity$PlaceholderFragment.onCreateView(MainActivity.java:86)

从堆栈跟踪来看,它看起来像那样,因为我现在正在有效地尝试在 onCreateView() 中绑定 m_IDmTitle 而不是 onItemClick() 回调,这就是为什么视图为空。那是对的吗?我还调用了 Butterknife.bind() 两次,一次是在 onCreteView 中调用 mRecyclerViewmFabView,但 Butterknife.bind() 也在回调中被调用。如何在适当的时候绑定 m_IDmTitle 视图/除了 onCreateView 我应该使用什么方法?

您应该 ButterKnife.bind(...) 仅一次,在 onCreateView() 中,就像您所做的那样。

对于回调,您应该将 View 转换为实际的自定义 View class(这也绑定了它的小部件!),并获得 titleid 从那里:

public class MyCustomView extends FrameLayout {

    public @Bind(R.id._task_id) TextView m_ID;
    public @Bind(R.id.title)  TextView mTitle;

    public MyCustomView(Context context) {
        super(context);
        initialize(context);
    }

    public MyCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize(context);
    }

    void initialize(Context context) {
        LayoutInflater.from(context).inflate(R.layout.my_custom_view, this);
        ButterKnife.bind(this);
    }
}

然后你必须

  • PlaceholderFragment

    中删除 TextView 的引用
      TextView m_ID;
      TextView mTitle;
    
  • 修复处理程序:

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mRecyclerView.setAdapter(taskAdapter);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        mRecyclerView.setItemAnimator(new DefaultItemAnimator());
        taskAdapter.SetOnItemClickListener(new TaskAdapter.OnItemClickListener() {
    
            @Override
            @OnClick({R.id._task_id, R.id.title})
            public void onItemClick(View v, int position) {
                MyCustomView myView = (MyCustomView)v;
                Intent detailIntent = new Intent(v.getContext(), DetailActivity.class);
                detailIntent.putExtra("TASK_ID", myView .m_ID.getText().toString());
                detailIntent.putExtra("TASK_TITLE", myView .mTitle.getText().toString());
    

希望对你有所帮助