如何在基础活动和子活动中处理黄油刀绑定?

时间:2018-02-22 05:06:15

标签: android butterknife

BaseActivity有一个布局和一个扩展了这个BaseActivity的子Activity。

如何绑定视图以便BaseActivity中的视图在BaseActivity中绑定,而Sub活动中的视图绑定在那里?

以下是解释当前场景的示例代码, 注意:示例代码取自here

基础活动

public class BaseActivity extends AppCompatActivity {

    protected void onCreate(Bundle savedInstanceState, int layout) {
        super.onCreate(savedInstanceState);
        super.setContentView(layout);
        ButterKnife.bind(this);
    }


@Override
public void setContentView(int layoutResID) {

    //I added my own implementation here

}
}

次级活动

public class SplashActivity extends BaseActivity {

    @BindView(R.id.txtName)
    TextView txtName;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ButterKnife.bind(this);

    }
}

上述方案产生了许多错误,例如无法找到带有id的视图,

经过大量的研究,我发现很多话题都在讨论,

Link 1

Link 2

Link 3

Link 4

所以在浏览完所有链接后,我尝试了以下组合,但没有一个工作

  1. 在BaseActivity中呼叫ButterKnife.bind(this)但不在SplashActivity
  2. 中呼叫
  3. 在“活动”中调用ButterKnife.bind(this)
  4. ButterKnife.bind(this)中呼叫SplashActivity,使用此组合我无法访问BaseActivity的视图项,因为它们原来是null。
  5. 我的问题 如何绑定BaseActivitySplashActivity查看项目?

    确切错误行

    Caused by: java.lang.IllegalStateException: Required view '' with ID 2131296567 for field '' was not found. If this view is optional add '@Nullable' (fields) or '@Optional' (methods) annotation.
    

    对于您的善意说明,视图中存在视图。

    修改1:

    我添加了覆盖setContentView();

    的代码

5 个答案:

答案 0 :(得分:3)

简单。

将您的抽象BaseActivity视为:

public abstract class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResource());
        ButterKnife.bind(this);
    }

    protected abstract int getLayoutResource();
}

然后只需使用BaseActivity扩展您的活动:

public class SplashActivity extends BaseActivity {

    @BindView(R.id. txtName)
    TextView textView;

    @Override
    protected int getLayoutResource() {
        return R.layout.activity_splash;
    }
}

我更喜欢在我的项目中拥有多个Base类。您可以将BaseToolbarActivity扩展为BaseActivity

public abstract class BaseToolBarActivity extends BaseActivity {

    protected static final int RESOURCE_NO_MENU = 0;

    @BindView(R.id.toolbar)
    Toolbar mToolbar;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setToolBar();
    }

    public void setToolBar() {
        setSupportActionBar(mToolbar);
    }

    protected abstract int getMenuResource();

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        if (getMenuResource() == RESOURCE_NO_MENU)
            return super.onCreateOptionsMenu(menu);
        else {
            getMenuInflater().inflate(getMenuResource(), menu);
            return true;
        }
    }
}

因此,如果您的Activity具有布局工具栏,则将其扩展为BaseToolbarActivity,否则将其扩展为BaseActivity

对于更多此类,您可以在

中引用我的项目

https://github.com/chintansoni202/Android-Master-Project

答案 1 :(得分:2)

只是意识到要查看其中一条评论。我认为你的真正问题根本不在于子类化。它是布局。 我认为你想要在超类布局中包含子类布局。不幸的是,你正在破坏子类中的超类布局。 我认为您需要在子类中包含基本活动布局(可能包含在布局中的合并标记中)..请参阅 Re-using Layouts with include - 在您的子类布局(启动画面)中包含您的基本活动布局(工具栏等)..

-

(我认为以下信息现在无关紧要,但如果您感兴趣,请将其保留在那里)

所以,如果我正确地理解了这个问题,那么在子类(splashactivity)可以设置其布局之前,似乎基本上超级类中的butterknife bindng(基本活动)正在发生。

使用getLayourResourceId(在子类中重写)的想法可能适用于大多数人,因为它是一种允许子活动在调用butterknife.bind之前将其布局指定为超级活动的方法。

因此,假设这是正确的,另一种解决问题的方法是延迟绑定,直到指定布局为止。

换句话说,

;

public class BaseActivity extends AppCompatActivity {

    // Removed layout parameter
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // It may not make sense to set the content view if it is always
        // replaced by the subclasses, but maybe you want a default?
        setContentView(R.layout.baseactivitylayout);

...稍后调用onStart时会调用bind ....         }

   ...

   public void onStart() {
       super.onStart();
       ButterKnife.bind(this);
   }

   ...

}

public class SplashActivity extends BaseActivity {

    @BindView(R.id.txtName)
    TextView txtName;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splashLayout);
        // butterknife.bind will be called when BaseActivity's onStart is called.
    }
}

当然,从onStart开始绑定并不总是方便(或正确),但它可能有助于阐明其他解决方案的工作原理。

祝你好运, CJ

答案 2 :(得分:1)

异常中的消息告诉您该怎么做:

找不到字段“txtName”的ID为2131296567的必需视图“txtName”。如果此视图是可选的,请添加“@nullable”注释。

将其添加到布局中或使用@Nullable注释使字段绑定可选。

请参阅此Link

答案 3 :(得分:1)

在活动A中,您将设置活动的实例A.删除BaseActivity中的butterknife.bind。

 super.setContentView(layout);
    ButterKnife.bind(this);

使用ButterKnife.bind在childActivity中分配View实例。

   super.onCreate(savedInstanceState);
    ButterKnife.bind(this);

表示片段

ButterKnife.Bind(View,this);
你正在移除基础活动中的奶油刀。 原因在于: - 在基础活动中没有视图存在的重量分配不必要的假设有超过10个活动不容易管理。

答案 4 :(得分:1)

将您的BaseActivity更新为:

public class BaseActivity extends AppCompatActivity {

    protected void onCreate(Bundle savedInstanceState, int layout) {
        super.onCreate(savedInstanceState);
        setContentView(layout);
        ButterKnife.bind(this);
    }

}

并且SubActivity为:

public class SplashActivity extends BaseActivity {

    @BindView(R.id.txtName)
    TextView txtName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState, R.layout.activity_splash);
    }
}