截止到這篇,我們已經完成了後端的部分。
接下來,要讓我們的 Agent 真的能在前端上與使用者互動。
這篇會示範如何在 Android 前端中,建立一個簡單的 聊天介面。
使用者輸入訊息並按下「發送」後,畫面上就會出現一則回覆(目前先模擬 Agent 的回應)。
前端會使用 Java 編寫 Android 程式。
我們先從最基本的聊天畫面開始。
每一則訊息都會以「對話氣泡」的方式呈現,並區分 User 與 Agent。
在 res/drawable
資料夾中新增以下兩個檔案,分別設定使用者與 Agent 的對話框樣式。
agent_message_bg.xml
(Agent 對話框)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#2196F3"/> <!-- 藍色 -->
<corners android:radius="16dp"/>
<padding
android:left="12dp"
android:top="8dp"
android:right="12dp"
android:bottom="8dp" />
</shape>
user_message_bg.xml
(User 對話框)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#4CAF50"/> <!-- 綠色 -->
<corners android:radius="16dp"/>
<padding
android:left="12dp"
android:top="8dp"
android:right="12dp"
android:bottom="8dp" />
</shape>
item_message.xml
)這是每一條訊息在 RecyclerView 裡的樣式。
它包含一個 Agent 的氣泡與一個 User 的氣泡(實際顯示時會擇一顯示)。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<!-- Agent 訊息 -->
<TextView
android:id="@+id/itemMessage_bot_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/agent_message_bg"
android:padding="8dp"
android:textColor="#FFFFFF"
android:layout_alignParentStart="true"
android:visibility="gone" />
<!-- User 訊息 -->
<TextView
android:id="@+id/itemMessage_user_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/user_message_bg"
android:padding="8dp"
android:textColor="#FFFFFF"
android:layout_alignParentEnd="true"
android:visibility="gone" />
</RelativeLayout>
activity_main.xml
)主畫面包含:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<!-- RecyclerView 用於顯示聊天訊息 -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_chat_rv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:scrollbars="vertical" />
<!-- 輸入欄位 + 發送按鈕 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.1"
android:orientation="horizontal"
android:paddingTop="4dp">
<EditText
android:id="@+id/main_message_et"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:hint="輸入訊息..." />
<Button
android:id="@+id/main_send_btn"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.3"
android:text="發送" />
</LinearLayout>
</LinearLayout>
MainActivity.java
這裡是前端邏輯的核心,負責控制整個聊天流程。
public class MainActivity extends AppCompatActivity {
private RecyclerView chatRv;
private EditText messageEt;
private Button sendbtn;
private MessageAdapter adapter;
private ArrayList<Message> messageList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 綁定 UI 元件
chatRv = findViewById(R.id.main_chat_rv);
messageEt = findViewById(R.id.main_message_et);
sendbtn = findViewById(R.id.main_send_btn);
// 初始化訊息清單與 Adapter
messageList = new ArrayList<>();
adapter = new MessageAdapter(messageList);
// 設定 RecyclerView
chatRv.setLayoutManager(new LinearLayoutManager(this));
chatRv.setAdapter(adapter);
// 設定按鈕點擊事件
sendbtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String msg = messageEt.getText().toString(); // 取得輸入文字
if (!msg.isEmpty()) { // 確保文字不是空的
// 加入 user 訊息
messageList.add(new Message(msg, true));
adapter.notifyItemInserted(messageList.size() - 1);
chatRv.scrollToPosition(messageList.size() - 1);
messageEt.setText(""); // 清空輸入框
// 模擬 Agent 回覆
String botReply = "你說的是: " + msg;
messageList.add(new Message(botReply, false));
adapter.notifyItemInserted(messageList.size() - 1);
chatRv.scrollToPosition(messageList.size() - 1);
}
}
});
}
}
MessageAdapter.java
這個 Adapter 會負責控制訊息的顯示方向與樣式。
public class MessageAdapter extends RecyclerView.Adapter<MessageAdapter.ViewHolder> {
private List<Message> messageList; // 用來儲存所有訊息的清單
// 建構子
public MessageAdapter(List<Message> messageList) {
this.messageList = messageList;
}
// 用來儲存單一訊息項目的 UI 元件
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView userTv; // 顯示 user 訊息的 TextView
public TextView agentTv; // 顯示 Agent 訊息的 TextView
public ViewHolder(View view) {
super(view);
// 綁定 UI 元件
userTv = view.findViewById(R.id.itemMessage_user_tv);
agentTv = view.findViewById(R.id.itemMessage_bot_tv);
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// 將 item_message.xml 佈局轉換成可顯示的 View
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_message, parent, false);
return new ViewHolder(view); // 回傳 ViewHolder
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// 綁定每一筆資料到畫面上
Message msg = messageList.get(position); // 取得當前訊息物件
if (msg.isUser()) {
// 若是 user 的訊息時,顯示 user 文字,隱藏 Agent 文字
holder.userTv.setText(msg.getContent());
holder.userTv.setVisibility(View.VISIBLE);
holder.agentTv.setVisibility(View.GONE);
} else {
// 若是 Agent 訊息時,顯示 Agent 文字,隱藏 user 文字
holder.agentTv.setText(msg.getContent());
holder.agentTv.setVisibility(View.VISIBLE);
holder.userTv.setVisibility(View.GONE);
}
}
@Override
public int getItemCount() {
// 回傳訊息總數,用來告訴 RecyclerView 要顯示幾項
return messageList.size();
}
Message.java
這個是用來儲存每一則訊息的內容與屬性。
public class Message {
private String content; // 訊息文字內容
private boolean isUser; // 用來判斷這則訊息是 user 還是 Agent (true = user, false = Agent)
// 建構子,用來建立 Message 物件
public Message(String content, boolean isUser) {
this.content = content;
this.isUser = isUser;
}
// 取得訊息內容
public String getContent() {
return content;
}
// 回傳是否為 user 訊息
public boolean isUser() {
return isUser;
}
}