Android: cách xử lý nhấp vào nút


95

Có kinh nghiệm vững chắc trong lĩnh vực không phải Java và không phải Android, tôi đang học Android.

Tôi có rất nhiều nhầm lẫn với các lĩnh vực khác nhau, một trong số đó là cách xử lý các lần bấm nút. Có ít nhất 4 cách để làm điều đó (!!!), chúng được liệt kê ngắn gọn ở đây

vì mục đích nhất quán, tôi sẽ liệt kê chúng:

  1. Có một thành viên của View.OnClickListenerlớp trong hoạt động và gán nó cho một cá thể sẽ xử lý onClicklogic trong onCreatephương thức hoạt động.

  2. Tạo 'onClickListener' trong phương thức hoạt động 'onCreate' và gán nó vào nút bằng setOnClickListener

  3. Triển khai 'onClickListener' trong chính hoạt động và chỉ định 'this' làm trình nghe cho nút. Đối với trường hợp nếu hoạt động có ít nút, id nút nên được phân tích để thực thi trình xử lý 'onClick' cho nút thích hợp

  4. Có phương thức công khai trên hoạt động triển khai logic 'onClick' và gán nó vào nút trong khai báo xml hoạt động

Câu hỏi 1:

Đó là tất cả các phương pháp, có lựa chọn nào khác không? (Tôi không cần bất kỳ thứ gì khác, chỉ cần tò mò)

Đối với tôi, cách trực quan nhất sẽ là cách mới nhất: nó yêu cầu lượng mã ít nhất được gõ và dễ đọc nhất (ít nhất là đối với tôi).

Mặc dù vậy, tôi không thấy phương pháp này được sử dụng rộng rãi. Khuyết điểm khi sử dụng nó là gì?

Câu hỏi 2:

Ưu / nhược điểm của từng phương pháp này là gì? Vui lòng chia sẻ kinh nghiệm của bạn hoặc một liên kết tốt.

Mọi phản hồi đều được chào đón!

Tái bút Tôi đã cố gắng lên Google và tìm một cái gì đó cho chủ đề này, nhưng điều duy nhất tôi tìm thấy là mô tả "cách" để làm điều đó, chứ không phải tại sao nó tốt hay xấu.

Câu trả lời:


147

Câu hỏi 1: Thật không may, cái mà bạn nói là trực quan nhất lại ít được sử dụng nhất trong Android. Theo tôi hiểu, bạn nên tách biệt giao diện người dùng (XML) và chức năng tính toán (Tệp lớp Java). Nó cũng giúp gỡ lỗi dễ dàng hơn. Nó thực sự dễ dàng hơn rất nhiều để đọc theo cách này và nghĩ về Android imo.

Câu hỏi 2: Tôi tin rằng hai chủ yếu được sử dụng là # 2 và # 3. Tôi sẽ sử dụng Nút clickButton làm ví dụ.

2

là một lớp ẩn danh.

Button clickButton = (Button) findViewById(R.id.clickButton);
clickButton.setOnClickListener( new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                ***Do what you want with the click here***
            }
        });

Đây là mục yêu thích của tôi vì nó có phương thức onClick ngay bên cạnh nơi biến nút được đặt với findViewById. Có vẻ như rất gọn gàng và ngăn nắp rằng mọi thứ liên quan đến Chế độ xem nút clickButton này đều nằm ở đây.

Một vấn đề mà đồng nghiệp của tôi nhận xét, đó là hãy tưởng tượng bạn có nhiều quan điểm cần người nghe onclick. Bạn có thể thấy rằng onCreate của bạn sẽ rất dài. Vì vậy, đó là lý do tại sao anh ấy thích sử dụng:

3

Giả sử bạn có, 5 nút bấm

Đảm bảo Hoạt động / Phân đoạn của bạn triển khai OnClickListener

// in OnCreate

Button mClickButton1 = (Button)findViewById(R.id.clickButton1);
mClickButton1.setOnClickListener(this);
Button mClickButton2 = (Button)findViewById(R.id.clickButton2);
mClickButton2.setOnClickListener(this);
Button mClickButton3 = (Button)findViewById(R.id.clickButton3);
mClickButton3.setOnClickListener(this);
Button mClickButton4 = (Button)findViewById(R.id.clickButton4);
mClickButton4.setOnClickListener(this);
Button mClickButton5 = (Button)findViewById(R.id.clickButton5);
mClickButton5.setOnClickListener(this);


// somewhere else in your code

public void onClick(View v) {
    switch (v.getId()) {
        case  R.id.clickButton1: {
            // do something for button 1 click
            break;
        }

        case R.id.clickButton2: {
            // do something for button 2 click
            break;
        }

        //.... etc
    }
}

Cách này như đồng nghiệp của tôi giải thích là gọn gàng hơn trong mắt anh ấy, vì tất cả tính toán onClick được xử lý ở một nơi và không làm chật chội phương thức onCreate. Nhưng nhược điểm mà tôi thấy là:

  1. quan điểm của họ,
  2. và bất kỳ đối tượng nào khác có thể nằm trong onCreate được sử dụng bởi phương thức onClick sẽ phải được tạo thành một trường.

Hãy cho tôi biết nếu bạn muốn biết thêm thông tin. Tôi không trả lời câu hỏi của bạn đầy đủ vì nó là một câu hỏi khá dài. Và nếu tôi tìm thấy một số trang web, tôi sẽ mở rộng câu trả lời của mình, ngay bây giờ tôi chỉ đưa ra một số kinh nghiệm.


1
Đối với tùy chọn 2, bạn sẽ muốn thực hiện nó: clickButton.setOnClickListener (new View.OnClickListener () {@Override public void onClick (View v) {// TODO những gì bạn muốn làm}}); để giúp nó giải quyết OnClickListener
ColossalChris

Tùy chọn 3 có lẽ là sạch nhất và dễ mở rộng nhất với mẫu MVP.
Raffaeu

Phương án 2 vẫn có thể tạo ra onCreate()điều đó không quá lâu. Các phép gán trình nghe nhấp chuột và các lớp ẩn danh có thể được tính toán thành một phương thức trợ giúp riêng biệt được gọi từ đó onCreate().
Nick Alexeev

@Colossal: Bạn không cần phải làm điều đó. Thêm phần mở rộng vào Lớp hoạt động như "triển khai View.OnClickListener".
TomeeNS

10

# 1 Tôi sử dụng cái cuối cùng thường xuyên khi có các nút trên bố cục không được tạo (nhưng rõ ràng là tĩnh).

Nếu bạn sử dụng nó trong thực tế và trong một ứng dụng kinh doanh, hãy chú ý thêm ở đây, bởi vì khi bạn sử dụng nguồn obfuscater như ProGuard, bạn sẽ cần đánh dấu các phương thức này trong hoạt động của mình để không bị xáo trộn.

Để lưu trữ một số loại bảo mật thời gian biên dịch với phương pháp này, hãy xem Android Lint ( ví dụ ).


# 2 Ưu và nhược điểm của tất cả các phương pháp gần như giống nhau và bài học phải là:

Sử dụng những gì phù hợp nhất hoặc cảm thấy trực quan nhất đối với bạn.

Nếu bạn phải gán giống nhau OnClickListenercho nhiều phiên bản nút, hãy lưu nó trong phạm vi lớp (# 1). Nếu bạn cần một trình nghe đơn giản cho Nút, hãy thực hiện triển khai ẩn danh:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        // Take action.
    }
});

Tôi có xu hướng không triển khai OnClickListenerhoạt động, điều này đôi khi hơi khó hiểu (đặc biệt là khi bạn triển khai nhiều trình xử lý sự kiện khác và không ai biết thistất cả đang làm gì).


Tôi đang làm theo tương tự nhưng vẫn không nhận được đầu ra cho hàm, mã và truy vấn của tôi ở đây: stackoverflow.com/questions/25107427/…
Rocket

8

Tôi thích tùy chọn 4 hơn, nhưng nó có ý nghĩa trực quan đối với tôi vì tôi làm quá nhiều việc trong Grails, Groovy và JavaFX. Tất cả các kết nối "ma thuật" giữa khung nhìn và bộ điều khiển đều phổ biến. Điều quan trọng là phải đặt tên cho phương thức tốt:

Trong dạng xem, hãy thêm phương thức onClick vào nút hoặc tiện ích con khác:

    android:clickable="true"
    android:onClick="onButtonClickCancel"

Sau đó, trong lớp, xử lý phương thức:

public void onButtonClickCancel(View view) {
    Toast.makeText(this, "Cancel pressed", Toast.LENGTH_LONG).show();
}

Một lần nữa, hãy đặt tên cho phương thức một cách rõ ràng, điều gì đó bạn nên làm, và việc bảo trì trở thành bản chất thứ hai.

Một lợi thế lớn là bạn có thể viết các bài kiểm tra đơn vị ngay bây giờ cho phương pháp này. Phương án 1 có thể làm được điều này, nhưng phương án 2 và 3 khó hơn.


1
Tôi sẽ băn khoăn một chút và đề xuất tùy chọn thứ năm (không, không có sự tham gia của Bruce Willis :)), một biến thể của tùy chọn 2: sử dụng lớp Presenter trong khuôn khổ Model-View-Presenter để xử lý các nhấp chuột. Nó giúp kiểm tra tự động dễ dàng hơn RẤT NHIỀU. Hãy xem liên kết này để biết thêm thông tin: codelabs.developers.google.com/codelabs/android-testing/…
Steve Gelman

4

Cách được sử dụng nhiều nhất là khai báo ẩn danh

    Button send = (Button) findViewById(R.id.buttonSend);
    send.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // handle click
        }
    });

Ngoài ra, bạn có thể tạo đối tượng View.OnClickListener và đặt nó thành nút sau đó, nhưng bạn vẫn cần ghi đè phương thức onClick chẳng hạn

View.OnClickListener listener = new View.OnClickListener(){
     @Override
        public void onClick(View v) {
            // handle click
        }
}   
Button send = (Button) findViewById(R.id.buttonSend);
send.setOnClickListener(listener);

Khi hoạt động của bạn triển khai giao diện OnClickListener, bạn phải ghi đè phương thức onClick (View v) trên cấp độ hoạt động. Sau đó, bạn có thể coi hoạt động này là nút nghe đối với nút, vì nó đã triển khai giao diện và ghi đè phương thức onClick ()

public class MyActivity extends Activity implements View.OnClickListener{


    @Override
    public void onClick(View v) {
        // handle click
    }


    @Override
    public void onCreate(Bundle b) {
        Button send = (Button) findViewById(R.id.buttonSend);
        send.setOnClickListener(this);
    }

}

(imho) Cách tiếp cận thứ 4 được sử dụng khi nhiều nút có cùng một trình xử lý và bạn có thể khai báo một phương thức trong lớp hoạt động và gán phương thức này cho nhiều nút trong bố cục xml, bạn cũng có thể tạo một phương thức cho một nút, nhưng trong trường hợp này, tôi thích khai báo các trình xử lý bên trong lớp hoạt động.


1

Tùy chọn 1 và 2 liên quan đến việc sử dụng lớp bên trong sẽ làm cho loại mã trở nên lộn xộn. Tùy chọn 2 khá lộn xộn vì sẽ có một người nghe cho mỗi nút. Nếu bạn có số lượng nút nhỏ, điều này không sao. Đối với tùy chọn 4, tôi nghĩ điều này sẽ khó gỡ lỗi hơn vì bạn sẽ phải quay lại và thứ tư mã xml và java. Cá nhân tôi sử dụng tùy chọn 3 khi tôi phải xử lý nhiều lần nhấp vào nút.


1

Mẫu của tôi, Đã thử nghiệm trong Android studio 2.1

Xác định nút trong bố cục xml

<Button
    android:id="@+id/btn1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Java phát hiện xung

Button clickButton = (Button) findViewById(R.id.btn1);
if (clickButton != null) {
    clickButton.setOnClickListener( new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            /***Do what you want with the click here***/
        }
    });
}

1

Để làm mọi thứ dễ dàng hơn asp Câu hỏi 2 đã nêu, bạn có thể sử dụng phương thức lambda như thế này để tiết kiệm bộ nhớ biến và tránh điều hướng lên và xuống trong lớp xem của bạn

//method 1
findViewById(R.id.buttonSend).setOnClickListener(v -> {
          // handle click
});

nhưng nếu bạn muốn áp dụng sự kiện nhấp chuột vào nút của mình cùng một lúc trong một phương pháp.

bạn có thể sử dụng Câu hỏi 3 của @D. Trân trả lời. Nhưng đừng quên triển khai lớp xem của bạn với View.OnClickListener.

Cách khác để sử dụng Câu hỏi số 3 đúng cách


1
Đây nên được coi là câu trả lời hiện đại kết hợp với phương pháp tham khảo IMO. Hầu hết các câu trả lời khác không cho thấy thực tế chúng là mã Java8 cũ trên Android.
Ryan The Leach

0

Câu hỏi số 1 - Đây là cách duy nhất để xử lý các lần nhấp vào lượt xem.

Câu hỏi # 2 -
Phương án # 1 / Phương án # 4 - Không có nhiều sự khác biệt giữa phương án số 1 và phương án số 4. Sự khác biệt duy nhất mà tôi thấy là trong một trường hợp hoạt động đang triển khai OnClickListener, trong khi, trong trường hợp khác, sẽ có một triển khai ẩn danh.

Tùy chọn # 2 - Trong phương pháp này, một lớp ẩn danh sẽ được tạo. Phương pháp này hơi rườm rà, vì bạn cần phải thực hiện nhiều lần, nếu bạn có nhiều nút. Đối với các lớp Ẩn danh, bạn phải cẩn thận trong việc xử lý rò rỉ bộ nhớ.

Tùy chọn # 3 - Tuy nhiên, đây là một cách dễ dàng. Thông thường, các lập trình viên cố gắng không sử dụng bất kỳ phương pháp nào cho đến khi họ viết ra nó, và do đó phương pháp này không được sử dụng rộng rãi. Bạn sẽ thấy hầu hết mọi người sử dụng Tùy chọn số 4. Bởi vì nó sạch hơn về mặt mã.


Xin chào Gaurav, cảm ơn bạn đã trả lời. Nhưng bạn có thể vui lòng làm rõ ý bạn ở đây không: Đối với các lớp Ẩn danh, bạn phải cẩn thận khi xử lý rò rỉ bộ nhớ. Làm thế nào rò rỉ bộ nhớ đến đây?
Budda

Bạn chỉ cần lưu ý rằng: nếu bạn tạo một lớp ẩn danh bên trong một phương thức có thể được gọi nhiều lần trong suốt thời gian hoạt động của ứng dụng của bạn thì không một số trường hợp của một lớp sẽ được tạo mà có một số lớp bao gồm cả các trường hợp của chúng. Bạn có thể tránh điều đó bằng cách sử dụng các lớp bên trong thông thường và khởi tạo trình nghe dưới dạng các trường cá thể. Cố gắng giảm bớt các lớp trình nghe khác nhau bằng cách làm cho trạng thái của trình nghe nhận biết được thông qua các đối số của hàm tạo. Một lớp bên trong thông thường cung cấp cho bạn lợi ích của các hàm tạo tùy chỉnh và các phương thức khác.
Risadinha

0

Ngoài ra còn có các tùy chọn có sẵn dưới dạng các thư viện khác nhau có thể làm cho quá trình này trở nên rất quen thuộc với những người đã sử dụng các khuôn khổ MVVM khác.

https://developer.android.com/topic/libraries/data-binding/

Hiển thị một ví dụ về thư viện chính thức, cho phép bạn liên kết các nút như sau:

<Button
    android:text="Start second activity"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:onClick="@{() -> presenter.showList()}"
/>

0

Bước 1: Tạo tệp XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btnClickEvent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me" />
</LinearLayout>

Bước 2: Tạo MainActivity:

package com.scancode.acutesoft.telephonymanagerapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity implements View.OnClickListener {

    Button btnClickEvent;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnClickEvent = (Button) findViewById(R.id.btnClickEvent);
        btnClickEvent.setOnClickListener(MainActivity.this);

    }

    @Override
    public void onClick(View v) {
        //Your Logic
    }
}

HappyCoding!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.