Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีใส่ EditText ใน Android Notification เพื่อรับข้อความจากผู้ใช้

ภาพรวม

คำถามนี้ถามถึงการใส่ EditText ใน Notification แต่ EditText ใน RemoteViews ไม่สามารถรับ Input ได้จริง บทความนี้อธิบายข้อจำกัดและเสนอวิธีที่ถูกต้องคือ RemoteInput

ทำไม EditText ใน Notification ไม่ทำงาน?

ปัญหาสาเหตุ
ไม่สามารถพิมพ์ได้RemoteViews ไม่สร้าง Input Connection ให้ EditText
ไม่ได้รับ FocusNotification UI ไม่อนุญาตให้ View ใน RemoteViews รับ Focus
Keyboard ไม่ขึ้นระบบไม่รองรับ Soft Keyboard ใน Notification Shade แบบ Custom Layout
Securityป้องกัน Keylogger และ UI Spoofing

วิธีที่ถูกต้อง: ใช้ RemoteInput (API 24+)

RemoteInput เป็น API มาตรฐานของ Android สำหรับรับข้อมูลจาก Notification โดยตรง

1. เพิ่ม Dependency (ถ้ายังไม่มี)

// build.gradle
dependencies {
    implementation "androidx.core:core:1.12.0"
    // RemoteInput อยู่ใน androidx.core.app.RemoteInput
}

2. สร้าง Notification พร้อม RemoteInput

public void createNotificationWithInput(View view) {
    // Key สำหรับดึงข้อมูลที่ผู้ใช้พิมพ์
    final String KEY_REPLY = "key_reply";
    
    // สร้าง RemoteInput
    RemoteInput remoteInput = new RemoteInput.Builder(KEY_REPLY)
        .setLabel("พิมพ์ข้อความตอบกลับ...")
        .setChoices(new String[]{"ตกลง", "ไม่ตกลง", "ภายหลัง"}) // Quick replies (optional)
        .build();

    // PendingIntent สำหรับรับผลลัพธ์ (ใช้ BroadcastReceiver หรือ Activity)
    Intent replyIntent = new Intent(this, NotificationReplyReceiver.class);
    replyIntent.setAction("REPLY_ACTION");
    PendingIntent replyPendingIntent = PendingIntent.getBroadcast(
        this, 0, replyIntent, 
        PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
    );

    // สร้าง Action
    NotificationCompat.Action action = new NotificationCompat.Action.Builder(
        R.drawable.ic_reply_icon, "ตอบกลับ", replyPendingIntent)
        .addRemoteInput(remoteInput)
        .setAllowGeneratedReplies(true)
        .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
        .build();

    // สร้าง Notification ด้วย MessagingStyle (เหมาะสำหรับแชท)
    NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle("ฉัน")
        .setConversationTitle("การสนทนา")
        .addMessage("สวัสดี! มีอะไรให้ช่วยไหม?", System.currentTimeMillis() - 10000, "ผู้อื่น")
        .addMessage("ขอสอบถามหน่อยครับ", System.currentTimeMillis(), "ฉัน");

    NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
        .setSmallIcon(R.drawable.ic_launcher_foreground)
        .setStyle(messagingStyle)
        .addAction(action)
        .setAutoCancel(true)
        .setCategory(NotificationCompat.CATEGORY_MESSAGE);

    notificationManager.notify(NOTIFICATION_ID, builder.build());
}

3. BroadcastReceiver รับข้อมูล

public class NotificationReplyReceiver extends BroadcastReceiver {
    private static final String KEY_REPLY = "key_reply";

    @Override
    public void onReceive(Context context, Intent intent) {
        if ("REPLY_ACTION".equals(intent.getAction())) {
            Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
            if (remoteInput != null) {
                CharSequence replyText = remoteInput.getCharSequence(KEY_REPLY);
                if (replyText != null) {
                    String userReply = replyText.toString();
                    // ประมวลผลข้อความตอบกลับ
                    Log.d("NOTIFICATION_REPLY", "User replied: " + userReply);
                    
                    // ส่งต่อไปยัง Server, Database, หรืออัปเดต UI
                    processReply(context, userReply);
                }
            }
        }
    }

    private void processReply(Context context, String reply) {
        // TODO: Implement your logic here
        // e.g., send to API, save to DB, update UI via EventBus/LiveData
    }
}

4. ลงทะเบียน Receiver ใน Manifest

<receiver
    android:name=".NotificationReplyReceiver"
    android:exported="true"
    android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
    <intent-filter>
        <action android:name="REPLY_ACTION" />
    </intent-filter>
</receiver>

ตัวเลือกอื่น: ใช้ Activity แทน BroadcastReceiver

// ใช้ Activity แทน Receiver (สำหรับกรณีซับซ้อน)
Intent replyIntent = new Intent(this, ReplyActivity.class);
PendingIntent replyPendingIntent = PendingIntent.getActivity(
    this, 0, replyIntent, 
    PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
);

// ใน ReplyActivity.onCreate()
Bundle remoteInput = RemoteInput.getResultsFromIntent(getIntent());
if (remoteInput != null) {
    String reply = remoteInput.getCharSequence(KEY_REPLY).toString();
    // ประมวลผล...
    finish(); // ปิด Activity ทันที
}

เปรียบเทียบ: EditText vs RemoteInput

คุณสมบัติEditText ใน RemoteViewsRemoteInput (มาตรฐาน)
รับ Input ได้จริง❌ ไม่ได้✅ ได้
แสดง Keyboard❌ ไม่ได้✅ ได้ (Inline)
Quick Replies❌ ไม่ได้✅ รองรับ (setChoices)
Voice Input❌ ไม่ได้✅ รองรับ (setAllowFreeFormInput)
รองรับ Android Versionไม่ทำงานทุก VersionAPI 24+ (Android 7.0+)
UI Consistencyแตกต่างจากระบบเข้ากับ System UI

ขั้นสูง: Smart Reply (ML Kit)

// ใช้ ML Kit Smart Reply สร้าง Quick Replies อัตโนมัติ
SmartReplyGenerator generator = SmartReply.getClient();
generator.suggestReplies(conversation)
    .addOnSuccessListener(result -> {
        if (result.getStatus() == SmartReplySuggestionResult.STATUS_SUCCESS) {
            List suggestions = result.getSuggestions();
            String[] quickReplies = suggestions.stream()
                .map(SmartReplySuggestion::getText)
                .toArray(String[]::new);
            
            // นำไปใช้กับ RemoteInput.setChoices(quickReplies)
        }
    });

สรุป

  1. อย่าใช้ EditText ใน Custom Notification Layout - ไม่ทำงาน
  2. ใช้ RemoteInput + Action + MessagingStyle - วิธีมาตรฐาน ทำงานได้จริง
  3. รองรับ Quick Replies, Voice Input, Smart Reply - ประสบการณ์ผู้ใช้ดีที่สุด
  4. ทดสอบบน Android 7.0+ - RemoteInput ต้องการ API 24+