代码优化-声明多个方法引用的视图并实现onclicklistener
Code optimization-Declaring views referenced by more than one method and implementing onclicklistener
我经常困惑是创建实例视图并在不同方法中使用它还是避免使用实例视图并在不同方法之间传递视图?实现 onClickListener 是好的做法吗?初始化视图是好的做法分别使用不同的方法并避免使用实例视图?
以下三种方法哪个更好?
1.避免实例变量并且不实现 onClickListener
public class XYZActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initViews();
}
private void initViews() {
ImageView ivScanner = (ImageView) findViewById(R.id.ivBanner);
TextView tvName = (TextView) findViewById(R.id.tvOfferName);
TextView tvText = (TextView) findViewById(R.id.tvOfferText);
TextView tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
menthodXYZ(ivScanner,tvName);
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvDetail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}
2.创建实例变量并实现 OnClickListener
public class XYZActivity extends BaseActivity implements View.OnClickListener{
private ImageView ivScanner;
private TextView tvName,tvText,tvDetail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initViews();
}
private void initViews() {
ivScanner = (ImageView) findViewById(R.id.ivBanner);
tvName = (TextView) findViewById(R.id.tvOfferName);
tvText = (TextView) findViewById(R.id.tvOfferText);
tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
tvName.setOnClickListener(this);
tvText.setOnClickListener(this);
tvDetail.setOnClickListener(this);
ivScanner.setOnClickListener(this);
...
}
@Override
public void onClick(View view) {
switch (view.getId())
{
case R.id.ivScanner:
...
break;
case R.id.tvName:
....
break;
case R.id.tvText:
....
break;
case R.id.tvDetail:
....
break;
}
}
3.如果在不同的方法中需要一个变量,那么在不同的方法中分别初始化它以避免实例变量并实现 OnClickListener
public class XYZActivity extends BaseActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initViews();
}
private void initViews() {
ImageView ivScanner = (ImageView) findViewById(R.id.ivBanner);
TextView tvName = (TextView) findViewById(R.id.tvOfferName);
TextView tvText = (TextView) findViewById(R.id.tvOfferText);
TextView tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
...
}
private void methodXYZ()
{
ImageView ivScanner = (ImageView) findViewById(R.id.ivBanner);
TextView tvName = (TextView) findViewById(R.id.tvOfferName);
TextView tvText = (TextView) findViewById(R.id.tvOfferText);
TextView tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
...
}
@Override
public void onClick(View view) {
ImageView ivScanner = (ImageView) findViewById(R.id.ivBanner);
TextView tvName = (TextView) findViewById(R.id.tvOfferName);
TextView tvText = (TextView) findViewById(R.id.tvOfferText);
TextView tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
switch (view.getId())
{
case R.id.ivScanner:
...
break;
case R.id.tvName:
....
break;
case R.id.tvText:
....
break;
case R.id.tvDetail:
....
break;
}
}
首先 - findByView 被认为是一项昂贵的操作,需要执行一次,因此从这个角度来看,您的变体 3 非常昂贵。
其次,如果您的 ... 在第二个变体中意味着
menthodXYZ(ivScanner,tvName);
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvDetail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
--> 你的代码只有一个 onClick
没有意义 =)
但是如果它意味着:
menthodXYZ(ivScanner,tvName);
tvName.setOnClickListener(this);
tvText.setOnClickListener(this);
tvDetail.setOnClickListener(this);
--> 你可以使用它,我认为它是你最好的变体,因为你:
- 您可以在
Activity
的任何方法中使用所有视图实例
- 您避免了额外的
findById
方法调用
为什么你的第一个变体不好(这只是我个人的意见)- 你把所有的点击处理程序逻辑放在一个地方,如果点击处理程序有很多代码,将很难调试它.
...
另外,我可以向您推荐另一种变体 =) 您可以使用 Jake Wharton 的 ButterKnife library。它将删除用于创建视图实例和 onClickListeners
:
的所有样板代码
public class MyActivity extends BaseActivity {
private Unbinder unbinder;
@BindView(R.id.app_version)
TextView appVersionTextView;
@BindView(R.id.my_image_view)
ImageView myImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
unbinder = ButterKnife.bind(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbinder.unbind();
}
@OnClick(R.id.my_need_click_view)
public void clickToMySuperView() {
Log.i("TAG", "click to my super view!");
}
@OnClick(R.id.my_need_click_view_2)
public void clickToMySuperView() {
Log.i("TAG", "click to my super view 2!");
}
...
}
更新
请查看以下代码:
public class MyActivity extends BaseActivity implements View.OnClickListener {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
}
private void initView() {
ImageView myImageView = (ImageView) findViewById(R.id.my_image_view);
TextView myTextView = (TextView) findViewById(R.id.my_text_view);
myImageView.setOnClickListener(this);
myTextView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.my_image_view:
// special code for image view
break;
case R.id.my_text_view:
// special code for text view.
break;
default:
// no actions.
break;
}
}
}
在这段代码中,我们只初始化视图实例一次,然后为它们设置点击侦听器。 onCreate
方法,根据Activity
生命周期,只调用一次(如果Activity
第一次创建,或者销毁后重新创建状态)。在 OnClick
方法中,我们的视图没有初始化,我们只需要 View
参数中的 id
。
那么,请看下面的代码:
public class MyActivity extends BaseActivity implements View.OnClickListener {
private ImageView myImageView;
private TextView myTextView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
}
private void initView() {
myImageView = (ImageView) findViewById(R.id.my_image_view);
myTextView = (TextView) findViewById(R.id.my_text_view);
myImageView.setOnClickListener(this);
myTextView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.my_image_view:
// special code for image view
break;
case R.id.my_text_view:
// special code for text view.
break;
default:
// no actions.
break;
}
}
}
在这种情况下,我们初始化我们的视图实例并将它们保存到我们的 Activity
对象中。但是,同样,我们只初始化它们一次——在 onCreate
方法中。同样,在 onClick
方法中,我们不会通过 findById
方法再次搜索此视图。
希望对您有所帮助。
应避免选项 #3 - 每个 View
不应多次调用 findViewById()
。这不仅与性能有关(这些调用只有在数十和数百个调用时才会成为性能问题,例如 ListViews
),而且还与代码可读性有关。
我通常为特定组件中使用的所有 Views
定义字段。通过这种方式,您可以(某种程度上)通过查看组件的字段定义来了解组件的作用。将来您也可能需要在其他方法中引用其中一些 Views
,因此这种方法提高了可维护性。
至于是使用匿名监听还是让封装组件实现OnClickListener
接口,主要是个人喜好选择。我的经验法则:如果所有 Views
感兴趣的匿名听众适合单页代码 - 我选择匿名;如果不是 - 我让包含组件实现 OnClickListener
接口并在单独的方法中处理所有点击。
所以,在你的情况下,我会选择这样的东西:
public class XYZActivity extends BaseActivity {
private ImageView ivScanner;
private TextView tvName;
private TextView tvText;
private TextView tvDetail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initViews();
}
private void initViews() {
}
ivScanner = (ImageView) findViewById(R.id.ivBanner);
tvName = (TextView) findViewById(R.id.tvOfferName);
tvText = (TextView) findViewById(R.id.tvOfferText);
tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvDetail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}
如果我需要向 ivScanner
添加一个侦听器,那么我会将所有侦听器重构为一个方法。
性能:
请注意,匿名 类 会产生一些性能成本。您可以听 this talk by Jake Warthon - 他在调查和解释方面做得很好。但是,我认为在这种情况下,可读性和可维护性比微小的性能提升更重要。
我经常困惑是创建实例视图并在不同方法中使用它还是避免使用实例视图并在不同方法之间传递视图?实现 onClickListener 是好的做法吗?初始化视图是好的做法分别使用不同的方法并避免使用实例视图? 以下三种方法哪个更好?
1.避免实例变量并且不实现 onClickListener
public class XYZActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initViews();
}
private void initViews() {
ImageView ivScanner = (ImageView) findViewById(R.id.ivBanner);
TextView tvName = (TextView) findViewById(R.id.tvOfferName);
TextView tvText = (TextView) findViewById(R.id.tvOfferText);
TextView tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
menthodXYZ(ivScanner,tvName);
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvDetail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}
2.创建实例变量并实现 OnClickListener
public class XYZActivity extends BaseActivity implements View.OnClickListener{
private ImageView ivScanner;
private TextView tvName,tvText,tvDetail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initViews();
}
private void initViews() {
ivScanner = (ImageView) findViewById(R.id.ivBanner);
tvName = (TextView) findViewById(R.id.tvOfferName);
tvText = (TextView) findViewById(R.id.tvOfferText);
tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
tvName.setOnClickListener(this);
tvText.setOnClickListener(this);
tvDetail.setOnClickListener(this);
ivScanner.setOnClickListener(this);
...
}
@Override
public void onClick(View view) {
switch (view.getId())
{
case R.id.ivScanner:
...
break;
case R.id.tvName:
....
break;
case R.id.tvText:
....
break;
case R.id.tvDetail:
....
break;
}
}
3.如果在不同的方法中需要一个变量,那么在不同的方法中分别初始化它以避免实例变量并实现 OnClickListener
public class XYZActivity extends BaseActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initViews();
}
private void initViews() {
ImageView ivScanner = (ImageView) findViewById(R.id.ivBanner);
TextView tvName = (TextView) findViewById(R.id.tvOfferName);
TextView tvText = (TextView) findViewById(R.id.tvOfferText);
TextView tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
...
}
private void methodXYZ()
{
ImageView ivScanner = (ImageView) findViewById(R.id.ivBanner);
TextView tvName = (TextView) findViewById(R.id.tvOfferName);
TextView tvText = (TextView) findViewById(R.id.tvOfferText);
TextView tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
...
}
@Override
public void onClick(View view) {
ImageView ivScanner = (ImageView) findViewById(R.id.ivBanner);
TextView tvName = (TextView) findViewById(R.id.tvOfferName);
TextView tvText = (TextView) findViewById(R.id.tvOfferText);
TextView tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
switch (view.getId())
{
case R.id.ivScanner:
...
break;
case R.id.tvName:
....
break;
case R.id.tvText:
....
break;
case R.id.tvDetail:
....
break;
}
}
首先 - findByView 被认为是一项昂贵的操作,需要执行一次,因此从这个角度来看,您的变体 3 非常昂贵。
其次,如果您的 ... 在第二个变体中意味着
menthodXYZ(ivScanner,tvName);
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvDetail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
--> 你的代码只有一个 onClick
没有意义 =)
但是如果它意味着:
menthodXYZ(ivScanner,tvName);
tvName.setOnClickListener(this);
tvText.setOnClickListener(this);
tvDetail.setOnClickListener(this);
--> 你可以使用它,我认为它是你最好的变体,因为你:
- 您可以在
Activity
的任何方法中使用所有视图实例
- 您避免了额外的
findById
方法调用
为什么你的第一个变体不好(这只是我个人的意见)- 你把所有的点击处理程序逻辑放在一个地方,如果点击处理程序有很多代码,将很难调试它.
...
另外,我可以向您推荐另一种变体 =) 您可以使用 Jake Wharton 的 ButterKnife library。它将删除用于创建视图实例和 onClickListeners
:
public class MyActivity extends BaseActivity {
private Unbinder unbinder;
@BindView(R.id.app_version)
TextView appVersionTextView;
@BindView(R.id.my_image_view)
ImageView myImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
unbinder = ButterKnife.bind(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbinder.unbind();
}
@OnClick(R.id.my_need_click_view)
public void clickToMySuperView() {
Log.i("TAG", "click to my super view!");
}
@OnClick(R.id.my_need_click_view_2)
public void clickToMySuperView() {
Log.i("TAG", "click to my super view 2!");
}
...
}
更新
请查看以下代码:
public class MyActivity extends BaseActivity implements View.OnClickListener {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
}
private void initView() {
ImageView myImageView = (ImageView) findViewById(R.id.my_image_view);
TextView myTextView = (TextView) findViewById(R.id.my_text_view);
myImageView.setOnClickListener(this);
myTextView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.my_image_view:
// special code for image view
break;
case R.id.my_text_view:
// special code for text view.
break;
default:
// no actions.
break;
}
}
}
在这段代码中,我们只初始化视图实例一次,然后为它们设置点击侦听器。 onCreate
方法,根据Activity
生命周期,只调用一次(如果Activity
第一次创建,或者销毁后重新创建状态)。在 OnClick
方法中,我们的视图没有初始化,我们只需要 View
参数中的 id
。
那么,请看下面的代码:
public class MyActivity extends BaseActivity implements View.OnClickListener {
private ImageView myImageView;
private TextView myTextView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
}
private void initView() {
myImageView = (ImageView) findViewById(R.id.my_image_view);
myTextView = (TextView) findViewById(R.id.my_text_view);
myImageView.setOnClickListener(this);
myTextView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.my_image_view:
// special code for image view
break;
case R.id.my_text_view:
// special code for text view.
break;
default:
// no actions.
break;
}
}
}
在这种情况下,我们初始化我们的视图实例并将它们保存到我们的 Activity
对象中。但是,同样,我们只初始化它们一次——在 onCreate
方法中。同样,在 onClick
方法中,我们不会通过 findById
方法再次搜索此视图。
希望对您有所帮助。
应避免选项 #3 - 每个 View
不应多次调用 findViewById()
。这不仅与性能有关(这些调用只有在数十和数百个调用时才会成为性能问题,例如 ListViews
),而且还与代码可读性有关。
我通常为特定组件中使用的所有 Views
定义字段。通过这种方式,您可以(某种程度上)通过查看组件的字段定义来了解组件的作用。将来您也可能需要在其他方法中引用其中一些 Views
,因此这种方法提高了可维护性。
至于是使用匿名监听还是让封装组件实现OnClickListener
接口,主要是个人喜好选择。我的经验法则:如果所有 Views
感兴趣的匿名听众适合单页代码 - 我选择匿名;如果不是 - 我让包含组件实现 OnClickListener
接口并在单独的方法中处理所有点击。
所以,在你的情况下,我会选择这样的东西:
public class XYZActivity extends BaseActivity {
private ImageView ivScanner;
private TextView tvName;
private TextView tvText;
private TextView tvDetail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initViews();
}
private void initViews() {
}
ivScanner = (ImageView) findViewById(R.id.ivBanner);
tvName = (TextView) findViewById(R.id.tvOfferName);
tvText = (TextView) findViewById(R.id.tvOfferText);
tvDetail = (TextView) findViewById(R.id.tvOfferDetail);
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
tvDetail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}
如果我需要向 ivScanner
添加一个侦听器,那么我会将所有侦听器重构为一个方法。
性能:
请注意,匿名 类 会产生一些性能成本。您可以听 this talk by Jake Warthon - 他在调查和解释方面做得很好。但是,我认为在这种情况下,可读性和可维护性比微小的性能提升更重要。