Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Chèn EditText vào thông báo Android để nhập văn bản

Giới thiệu

Ví dụ này minh họa việc đặt EditText trong custom notification layout. Tuy nhiên, RemoteViews không hỗ trợ tương tác thực sự với EditText (không focus, không gõ, không lấy text). Bài viết giải thích hạn chế và đưa ra giải pháp thay thế RemoteInput.

Các bước thực hiện (Demo hiển thị)

Bước 1: Tạo dự án mới

Tạo project Android Studio mới.

Bước 2: Layout chính (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:onClick="createNotification"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_margin="16dp"
        android:text="Tạo thông báo có EditText" />

</RelativeLayout>

Bước 3: Custom Layout với EditText (res/layout/custom_notification_layout.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="96dp"
    android:padding="10dp">

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentStart="true"
        android:layout_marginEnd="10dp"
        android:contentDescription="@string/app_name"
        android:src="@mipmap/ic_launcher" />

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toEndOf="@id/image"
        android:text="Nhập văn bản"
        android:textColor="#000"
        android:textSize="18sp" />

    <EditText
        android:id="@+id/etInput"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/title"
        android:layout_marginTop="8dp"
        android:layout_toEndOf="@id/image"
        android:hint="Nhập nội dung..."
        android:inputType="text"
        android:textSize="14sp"
        android:background="@android:drawable/edit_text"
        android:padding="8dp" />

</RelativeLayout>

Bước 4: MainActivity (src/MainActivity.java)

package app.tutorialspoint.com.notifyme;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.RemoteViews;

public class MainActivity extends AppCompatActivity {
    public static final String NOTIFICATION_CHANNEL_ID = "10001";
    private final static String default_notification_channel_id = "default";

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

    public void createNotification(View view) {
        RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.custom_notification_layout);

        // CHỈ SET HINT/TEXT BAN ĐẦU - KHÔNG THỂ LẤY DỮ LIỆU SAU KHI USER NHẬP
        contentView.setTextViewHint(R.id.etInput, "Gõ tin nhắn tại đây...");

        NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
            MainActivity.this, default_notification_channel_id);

        mBuilder.setContent(contentView);
        mBuilder.setSmallIcon(R.drawable.ic_launcher_foreground);
        mBuilder.setAutoCancel(true);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel notificationChannel = new NotificationChannel(
                NOTIFICATION_CHANNEL_ID, "Kênh EditText Demo", importance);
            mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);
            assert mNotificationManager != null;
            mNotificationManager.createNotificationChannel(notificationChannel);
        }

        assert mNotificationManager != null;
        mNotificationManager.notify((int) System.currentTimeMillis(), mBuilder.build());
    }
}

Bước 5: AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.tutorialspoint.com.notifyme">

    <uses-permission android:name="android.permission.VIBRATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>

⚠️ VẤN ĐỀ: EditText trong RemoteViews KHÔNG HOẠT ĐỘNG

Tại sao không thể nhập liệu?

  • RemoteViews chạy trong process SystemUI, không phải process app
  • EditText cần focus, input connection, IME - không khả thi cross-process
  • RemoteViews chỉ render tĩnh, không xử lý event touch/text change
  • User thấy EditText nhưng không tap được, không gõ được

✅ GIẢI PHÁP CHUẨN: RemoteInput (API 20+)

Android cung cấp RemoteInput cho phép nhập văn bản trực tiếp từ notification shade:

// 1. Tạo RemoteInput
RemoteInput remoteInput = new RemoteInput.Builder("key_reply")
    .setLabel("Nhập phản hồi")
    .setChoices(new String[]{"Đồng ý", "Từ chối", "Sau"}) // Quick replies tùy chọn
    .build();

// 2. Tạo PendingIntent cho action "Trả lời"
Intent replyIntent = new Intent(this, NotificationActionReceiver.class);
replyIntent.setAction("REPLY_ACTION");
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(
    this, 0, replyIntent, PendingIntent.FLAG_IMMUTABLE);

// 3. Tạo Action với RemoteInput
NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder(
    R.drawable.ic_reply, "Trả lời", replyPendingIntent)
    .addRemoteInput(remoteInput)
    .setAllowGeneratedReplies(true)
    .build();

// 4. Thêm vào Builder
mBuilder.addAction(replyAction);

Nhận kết quả trong BroadcastReceiver/Service:

public class NotificationActionReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
        if (remoteInput != null) {
            CharSequence reply = remoteInput.getCharSequence("key_reply");
            if (reply != null) {
                // XỬ LÝ VĂN BẢN USER NHẬP
                String userText = reply.toString();
                Log.d("REPLY", "User nhập: " + userText);
                
                // Gửi lên server, cập nhật DB, v.v.
            }
        }
    }
}

So sánh các phương pháp

Phương pháp Có nhập được? Lấy text được? Độ phức tạp
EditText trong RemoteViews ❌ Không ❌ Không Dễ (nhưng vô dụng)
RemoteInput + Action ✅ Có ✅ Có Trung bình
Mở Activity khi nhấn ✅ Có ✅ Có Dễ
Bubble Notification (API 30+) ✅ Có ✅ Có Cao

Chạy thử nghiệm (Demo)

Chạy app → Tạo thông báo → Kéo shade → Thấy EditText hiển thị nhưng không thể gõ. Đây là hành vi mong đợi của RemoteViews.

Chèn EditText vào thông báo Android để nhập văn bản