代码优化 - 声明由多个方法引用的视图并实现onclicklistener

时间:2016-10-30 09:45:01

标签: android optimization onclicklistener instance-variables

我经常感到困惑的是,是创建实例视图并在不同的方法中使用它还是为了避免使用实例视图并在不同方法之间传递视图?实现onClickListener是一种好习惯吗?最好是单独初始化视图不同的方法,避免使用实例视图? 以下三个中哪个更好?

1. 避免实例变量而不实现onClickListener

FUNCTIONS_EXTENSION_VERSION

2. 创建实例变量并实现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) {

    }
}); 
}

3. 如果在不同方法中需要变量,则在不同方法中单独初始化它以避免实例变量并实现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;
        }
}

2 个答案:

答案 0 :(得分:2)

应避免使用选项#3 - 您不应每findViewById()次致电View次。这不仅仅是关于性能(这些调用仅在数十和数百例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 - 他做了很好的调查和解释。但是,我认为在这种情况下,可读性和可维护性会超过轻微的性能提升。

答案 1 :(得分:1)

首先 - 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) {

    }
}); 

- &GT;单个onClick的代码没有意义=)

但如果这意味着:

menthodXYZ(ivScanner,tvName);
tvName.setOnClickListener(this); 
tvText.setOnClickListener(this); 
tvDetail.setOnClickListener(this); 

- &GT;你可以使用它,我认为这是你最好的变种,因为你:

  • 您可以在Activity
  • 的任何方法中使用所有观看实例
  • 您避免使用其他findById方法调用

为什么你的第一个变体不好(这只是我个人的意见) - 你把所有的点击处理程序逻辑放在一个地方,如果点击处理程序有很多代码,那就很难调试它。 / p>

... 另外,我可以建议你另一个变种=)你可以使用杰克沃顿的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;
        }
    }

}

在这段代码中,我们只将视图实例初始化一次,然后将click侦听器设置为它们。根据{{​​1}}生命周期,onCreate方法只调用一次(如果Activity在第一次创建,或者在销毁后重新创建它的状态)。在Activity方法中我们的观点未初始化,我们只需要OnClick参数中的id

然后,看看以下代码的和平:

View

在这种情况下,我们初始化视图实例并将它们保存到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方法再次搜索此视图。

希望,这有帮助。