Android: วิธีจัดการกับการคลิกปุ่ม


98

มีประสบการณ์ที่มั่นคงในพื้นที่ที่ไม่ใช่ Java และไม่ใช่ Android ฉันกำลังเรียนรู้ Android

ฉันมีความสับสนอย่างมากกับพื้นที่ต่างๆหนึ่งในนั้นคือวิธีจัดการกับการคลิกปุ่ม มีอย่างน้อย 4 วิธีในการทำ (!!!) ซึ่งระบุไว้สั้น ๆที่นี่

เพื่อความสอดคล้องฉันจะแสดงรายการ:

  1. มีสมาชิกของView.OnClickListenerชั้นเรียนในกิจกรรมและกำหนดให้กับอินสแตนซ์ที่จะจัดการonClickตรรกะในonCreateวิธีการของกิจกรรม

  2. สร้าง 'onClickListener' ในวิธีกิจกรรม 'onCreate' และกำหนดให้กับปุ่มโดยใช้ setOnClickListener

  3. ใช้ 'onClickListener' ในกิจกรรมเองและกำหนดให้ 'this' เป็นผู้ฟังสำหรับปุ่ม ในกรณีที่กิจกรรมมีปุ่มไม่กี่ปุ่มควรวิเคราะห์รหัสปุ่มเพื่อเรียกใช้ตัวจัดการ 'onClick' สำหรับปุ่มที่เหมาะสม

  4. มีวิธีการสาธารณะในกิจกรรมที่ใช้ตรรกะ 'onClick' และกำหนดให้กับปุ่มในการประกาศ xml ของกิจกรรม

คำถามที่ 1:

วิธีการทั้งหมดนั้นมีทางเลือกอื่นหรือไม่? (ฉันไม่ต้องการอย่างอื่นแค่อยากรู้อยากเห็น)

สำหรับฉันวิธีที่เข้าใจง่ายที่สุดคือวิธีใหม่ล่าสุด: ต้องพิมพ์โค้ดให้น้อยที่สุดและอ่านได้ง่ายที่สุด (อย่างน้อยสำหรับฉัน)

แม้ว่าฉันจะไม่เห็นวิธีนี้ใช้กันอย่างแพร่หลาย ข้อเสียสำหรับการใช้งานคืออะไร?

คำถาม # 2:

ข้อดี / ข้อเสียของแต่ละวิธีคืออะไร? โปรดแบ่งปันประสบการณ์ของคุณหรือลิงก์ที่ดี

ยินดีรับข้อเสนอแนะใด ๆ !

ป.ล. ฉันพยายามเข้า Google และค้นหาบางอย่างสำหรับหัวข้อนี้ แต่สิ่งเดียวที่ฉันพบคือคำอธิบาย "วิธีการ" ที่จะทำไม่ใช่ว่าทำไมมันดีหรือไม่ดี

คำตอบ:


151

คำถามที่ 1: น่าเสียดายที่สิ่งที่คุณบอกว่าใช้งานง่ายที่สุดนั้นใช้น้อยที่สุดใน Android ตามที่ฉันเข้าใจคุณควรแยก UI (XML) และฟังก์ชันการคำนวณ (Java Class Files) นอกจากนี้ยังทำให้การดีบักง่ายขึ้น มันง่ายกว่ามากที่จะอ่านด้วยวิธีนี้และคิดถึง Android imo

คำถามที่ 2: ฉันเชื่อว่าทั้งสองส่วนใหญ่ใช้คือ # 2 และ # 3 ฉันจะใช้ปุ่ม clickButton เป็นตัวอย่าง

2

อยู่ในรูปแบบของคลาสที่ไม่ระบุชื่อ

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***
            }
        });

นี่เป็นรายการโปรดของฉันเนื่องจากมีเมธอด onClick ถัดจากตำแหน่งที่ตัวแปรปุ่มถูกตั้งค่าด้วย findViewById ดูเหมือนเป็นระเบียบเรียบร้อยมากที่ทุกสิ่งที่เกี่ยวข้องกับมุมมองปุ่มคลิกปุ่มนี้จะอยู่ที่นี่

ข้อเสียที่เพื่อนร่วมงานของฉันแสดงความคิดเห็นคือจินตนาการว่าคุณมีมุมมองมากมายที่ต้องการผู้ฟังแบบคลิก คุณจะเห็นได้ว่า onCreate ของคุณจะมีความยาวมาก ด้วยเหตุนี้เขาจึงชอบใช้:

3

สมมติว่าคุณมีปุ่มคลิก 5 ปุ่ม:

ตรวจสอบให้แน่ใจว่า Activity / Fragment ของคุณใช้ 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
    }
}

วิธีนี้ตามที่เพื่อนร่วมงานของฉันอธิบายว่าเป็นวิธีที่ดีกว่าในสายตาของเขาเนื่องจากการคำนวณ onClick ทั้งหมดได้รับการจัดการในที่เดียวและไม่ทำให้เมธอด onCreate แออัด แต่ข้อเสียที่ฉันเห็นคือ:

  1. ดูตัวเอง
  2. และวัตถุอื่น ๆ ที่อาจอยู่ใน onCreate ที่ใช้โดยเมธอด onClick จะต้องสร้างเป็นฟิลด์

โปรดแจ้งให้เราทราบหากคุณต้องการข้อมูลเพิ่มเติม ฉันไม่ได้ตอบคำถามของคุณทั้งหมดเนื่องจากเป็นคำถามที่ค่อนข้างยาว และถ้าฉันพบบางไซต์ฉันจะขยายคำตอบของฉันตอนนี้ฉันแค่ให้ประสบการณ์


1
สำหรับตัวเลือกที่ 2 คุณจะต้องทำ: clickButton.setOnClickListener (View OnClickListener ใหม่ () {@Override โมฆะสาธารณะ onClick (View v) {// TODO what you want to do}}); เพื่อช่วยแก้ปัญหา OnClickListener
ColossalChris

ตัวเลือกที่ 3 น่าจะเป็นรูปแบบ MVP ที่สะอาดและง่ายที่สุดในการขยาย
Raffaeu

ทางเลือกที่ 2 ยังคงสามารถผลิตonCreate()ได้โดยใช้เวลาไม่นาน onCreate()การกำหนดคลิกฟังและเรียนที่ไม่ระบุชื่อสามารถเอาเรื่องเป็นวิธีการช่วยเหลือที่แยกต่างหากที่เรียกว่าจาก
Nick Alexeev

@ Colossal: คุณไม่จำเป็นต้องทำ เพิ่มส่วนขยายให้กับคลาสกิจกรรมเช่น "ใช้ View OnClickListener"
TomeeNS

11

# 1ฉันใช้ปุ่มสุดท้ายบ่อยๆเมื่อมีปุ่มบนเค้าโครงที่ไม่ได้สร้างขึ้น (แต่เห็นได้ชัดว่าคงที่)

หากคุณใช้ในทางปฏิบัติและในแอปพลิเคชันทางธุรกิจโปรดให้ความสนใจเป็นพิเศษที่นี่เพราะเมื่อคุณใช้แหล่งที่มาที่ซับซ้อนเช่น ProGuard คุณจะต้องทำเครื่องหมายวิธีการเหล่านี้ในกิจกรรมของคุณเพื่อไม่ให้ยุ่งเหยิง

สำหรับการเก็บถาวรประเภทของการรักษาความปลอดภัยในการคอมไพล์ด้วยวิธีนี้ให้ดูที่Android Lint ( ตัวอย่าง )


# 2ข้อดีข้อเสียสำหรับวิธีการทั้งหมดเกือบจะเหมือนกันและบทเรียนควรเป็น:

ใช้สิ่งที่เคยเหมาะสมที่สุดหรือรู้สึกว่าใช้งานง่ายที่สุดสำหรับคุณ

หากคุณต้องกำหนดOnClickListenerอินสแตนซ์ปุ่มเดียวกันให้บันทึกไว้ในขอบเขตคลาส (# 1) หากคุณต้องการผู้ฟังที่เรียบง่ายสำหรับปุ่มให้ใช้งานโดยไม่ระบุชื่อ:

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

ฉันมักจะไม่นำไปใช้OnClickListenerในกิจกรรมนี้ทำให้เกิดความสับสนเล็กน้อยในบางครั้ง (โดยเฉพาะเมื่อคุณใช้ตัวจัดการเหตุการณ์อื่น ๆ หลายตัวและไม่มีใครรู้ว่าthisกำลังทำอะไรอยู่)


ฉันกำลังติดตามสิ่งเดียวกัน แต่ยังไม่ได้รับเอาต์พุตสำหรับฟังก์ชันโค้ดและแบบสอบถามของฉันอยู่ที่นี่: stackoverflow.com/questions/25107427/…
Rocket

8

ฉันชอบตัวเลือกที่ 4 แต่มันสมเหตุสมผลสำหรับฉันเพราะฉันทำงานใน Grails, Groovy และ JavaFX มากเกินไป การเชื่อมต่อแบบ "เวทย์มนตร์" ระหว่างมุมมองและคอนโทรลเลอร์เป็นเรื่องธรรมดา สิ่งสำคัญคือต้องตั้งชื่อวิธีการให้ดี:

ในมุมมองเพิ่มเมธอด onClick ลงในปุ่มหรือวิดเจ็ตอื่น ๆ :

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

จากนั้นในชั้นเรียนให้จัดการกับวิธีการ:

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

อีกครั้งตั้งชื่อวิธีการให้ชัดเจนสิ่งที่คุณควรทำต่อไปและการบำรุงรักษาจะกลายเป็นลักษณะที่สอง

ข้อดีอย่างหนึ่งคือคุณสามารถเขียนการทดสอบหน่วยสำหรับวิธีนี้ได้แล้ว ตัวเลือกที่ 1 ทำได้ แต่ 2 และ 3 ยากกว่า


1
ฉันจะทำวาฟเฟิลเล็กน้อยและแนะนำตัวเลือกที่ห้า (ไม่ใช่ไม่ใช่นำแสดงโดยบรูซวิลลิส :)) ตัวเลือกที่ 2: ใช้คลาสผู้นำเสนอในกรอบงาน Model-View-Presenter เพื่อจัดการกับการคลิก ทำให้การทดสอบอัตโนมัติง่ายขึ้นมาก ดูข้อมูลเพิ่มเติมที่ลิงค์นี้: codelabs.developers.google.com/codelabs/android-testing/…
Steve Gelman

4

วิธีที่ใช้มากที่สุดคือการประกาศแบบไม่ระบุตัวตน

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

นอกจากนี้คุณยังสามารถสร้างออบเจ็กต์ View OnClickListener และตั้งค่าเป็นปุ่มในภายหลัง แต่คุณยังต้องแทนที่เมธอด onClick เช่น

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

เมื่อกิจกรรมของคุณใช้อินเทอร์เฟซ OnClickListener คุณต้องแทนที่เมธอด onClick (View v) ในระดับกิจกรรม จากนั้นคุณสามารถกำหนดกิจกรรมนี้เป็นปุ่ม Listen to ได้เนื่องจากมันใช้งานอินเทอร์เฟซแล้วและแทนที่เมธอด 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) วิธีที่ 4 ใช้เมื่อหลายปุ่มมีตัวจัดการเดียวกันและคุณสามารถประกาศวิธีการหนึ่งในคลาสกิจกรรมและกำหนดวิธีการนี้ให้กับหลายปุ่มในเลย์เอาต์ xml นอกจากนี้คุณยังสามารถสร้างวิธีการเดียวสำหรับปุ่มเดียว แต่ในกรณีนี้ฉัน ต้องการประกาศตัวจัดการภายในคลาสกิจกรรม


1

ตัวเลือกที่ 1 และ 2 เกี่ยวข้องกับการใช้คลาสภายในซึ่งจะทำให้โค้ดไม่เป็นระเบียบ ตัวเลือกที่ 2 ไม่เป็นระเบียบเนื่องจากจะมีผู้ฟังหนึ่งคนสำหรับทุกปุ่ม หากคุณมีปุ่มจำนวนน้อยก็ไม่เป็นไร สำหรับตัวเลือกที่ 4 ฉันคิดว่านี่จะยากกว่าในการดีบั๊กเนื่องจากคุณจะต้องย้อนกลับและรหัส xml และ java ที่สี่ ฉันใช้ตัวเลือก 3 เป็นการส่วนตัวเมื่อต้องจัดการกับการคลิกปุ่มหลายปุ่ม


1

ตัวอย่างของฉันทดสอบแล้วใน Android studio 2.1

กำหนดปุ่มในรูปแบบ xml

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

Java pulsation ตรวจจับ

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

เพื่อให้ง่ายขึ้น asp คำถาม 2 ที่ระบุไว้คุณสามารถใช้วิธีแลมด้าเช่นนี้เพื่อบันทึกหน่วยความจำตัวแปรและเพื่อหลีกเลี่ยงการนำทางขึ้นและลงในคลาสมุมมองของคุณ

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

แต่ถ้าคุณต้องการใช้เหตุการณ์คลิกกับปุ่มของคุณในครั้งเดียวด้วยวิธีการ

คุณสามารถใช้คำถามที่ 3 โดย @D ตอบ Tran. View.OnClickListenerแต่อย่าลืมที่จะใช้ระดับมุมมองของคุณด้วย

ในการใช้คำถาม # 3 อย่างถูกต้อง


1
นี่ควรถือเป็นคำตอบที่ทันสมัยรวมกับวิธีการอ้างอิง IMO คำตอบอื่น ๆ ส่วนใหญ่ไม่ได้ระบุความจริงที่ว่าพวกเขาเป็นรหัส Java8 รุ่นเก่าบน Android
Ryan The Leach

0

คำถาม # 1 - นี่เป็นวิธีเดียวที่จะจัดการกับการคลิกดู

คำถาม # 2 -
ตัวเลือก # 1 / ตัวเลือก # 4 - ตัวเลือก # 1 และตัวเลือก # 4 ไม่มีความแตกต่างกันมากนัก ความแตกต่างเพียงอย่างเดียวที่ฉันเห็นคือในกิจกรรมกรณีหนึ่งคือการใช้ OnClickListener ในขณะที่อีกกรณีหนึ่งจะมีการใช้งานแบบไม่ระบุตัวตน

ตัวเลือก # 2 - ในวิธีนี้จะมีการสร้างคลาสที่ไม่ระบุชื่อ วิธีนี้ค่อนข้างยุ่งยากเล็กน้อยเนื่องจากคุณต้องทำหลาย ๆ ครั้งหากคุณมีปุ่มหลายปุ่ม สำหรับคลาส Anonymous คุณต้องระมัดระวังในการจัดการการรั่วไหลของหน่วยความจำ

ตัวเลือก # 3 - แม้ว่านี่จะเป็นวิธีง่ายๆ โดยปกติโปรแกรมเมอร์พยายามที่จะไม่ใช้วิธีการใด ๆ จนกว่าพวกเขาจะเขียนมันและด้วยเหตุนี้วิธีนี้จึงไม่ได้ใช้กันอย่างแพร่หลาย คุณจะเห็นคนส่วนใหญ่ใช้ตัวเลือก # 4 เพราะมันสะอาดกว่าในแง่ของรหัส


สวัสดี Gaurav ขอบคุณสำหรับคำตอบ แต่คุณช่วยอธิบายความหมายของคุณได้ที่นี่: สำหรับคลาส Anonymous คุณต้องระมัดระวังในการจัดการการรั่วไหลของหน่วยความจำ หน่วยความจำรั่วมาที่นี่ได้อย่างไร?
Budda

คุณต้องทราบว่า: หากคุณสร้างคลาสที่ไม่ระบุตัวตนภายในเมธอดที่อาจถูกเรียกหลายครั้งในช่วงอายุการใช้งานแอปของคุณจะไม่มีการสร้างอินสแตนซ์ของคลาสเดียวหลายอินสแตนซ์ แต่มีหลายคลาสรวมถึงอินสแตนซ์ของคลาสด้วย คุณสามารถหลีกเลี่ยงสิ่งนั้นได้โดยใช้คลาสภายในปกติและสร้างอินสแตนซ์ผู้ฟังเป็นฟิลด์อินสแตนซ์ พยายามลดคลาสของผู้ฟังที่แตกต่างกันโดยการทำให้สถานะผู้ฟังรับรู้ผ่านอาร์กิวเมนต์ตัวสร้าง คลาสภายในปกติให้คุณได้รับประโยชน์จากตัวสร้างที่กำหนดเองและวิธีการอื่น ๆ
Risadinha

0

นอกจากนี้ยังมีตัวเลือกในรูปแบบของไลบรารีต่างๆที่สามารถทำให้กระบวนการนี้คุ้นเคยกับผู้ที่ใช้เฟรมเวิร์ก MVVM อื่น ๆ

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

แสดงตัวอย่างของไลบรารีอย่างเป็นทางการที่ให้คุณผูกปุ่มต่างๆดังนี้:

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

0

ขั้นตอนที่ 1: สร้างไฟล์ 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>

ขั้นตอนที่ 2: สร้าง 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!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.