Я создаю приложение android, которое будет проводить чат с моим чат-ботом. Я создал чат-бота в Dialogflow, и я уже интегрировался с android studio.
Для создания интерфейса я создал три файла XML.
1) activity_main. xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_above="@id/inputLayout"/>
<RelativeLayout
android:id="@+id/inputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@android:color/white"
android:gravity="bottom"
android:paddingBottom="9dp"
android:paddingRight="8dp"
android:paddingLeft="8dp"
android:paddingTop="8dp">
<ImageView
android:id="@+id/sendBtn"
android:layout_width="49dp"
android:layout_height="28dp"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignBottom="@+id/queryEditText"
android:layout_marginBottom="20dp"
android:contentDescription="This is the button to send your
message!"
android:paddingTop="4dp"
app:srcCompat="@drawable/chatbot_send_btn" />
<EditText
android:id="@+id/queryEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_toStartOf="@+id/sendBtn"
android:layout_toLeftOf="@+id/sendBtn"
android:hint="Aa"
android:imeOptions="actionSend"
android:inputType="textMultiLine"
android:paddingTop="4dp"
android:textSize="18sp" />
</RelativeLayout>
</RelativeLayout>
Здесь мы создаем входной EditText и ImageView для отправки сообщения. А затем внутри scrollview, LinearLayout chatLayout, который будет размещать все пузыри чата.
2) bot_msg_layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/yo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<TextView
android:id="@+id/timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:text="time"
android:textSize="13dp"
android:visibility="invisible"
/>
<LinearLayout
android:id="@+id/bot_msg_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginTop="12dp"
android:layout_marginBottom="4dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:background="@drawable/bot_chat_bubble"
android:gravity="start|center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/chatMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:padding="12dp"
android:text="skereeeeeeeeeeee"
android:textSize="18sp"
android:clickable="true"/>
<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
</FrameLayout>
</LinearLayout>
</FrameLayout>
Здесь мы создаем интерфейс для когда бот отвечает пользователю, и ответ отображается в текстовом окне.
3) user_msg_layout Это точно такое же, как и выше, но с другим расположением.
Наконец, мой код MainActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView sendBtn = findViewById(R.id.sendBtn);
queryEditText = findViewById(R.id.queryEditText);
sendBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendMessage(v);
}
});
queryEditText.setOnKeyListener((view, keyCode, event) -> {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
sendMessage(sendBtn);
return true;
default:
break;
}
}
return false;
});
initV2Chatbot();
messageList = new ArrayList<MsgClass>();
mMessageRecycler = findViewById(R.id.recyclerview);
mMessageAdapter = new MessageListAdapter(this, messageList);
mMessageRecycler.setLayoutManager(new LinearLayoutManager(this));
mMessageRecycler.setHasFixedSize(true);
mMessageRecycler.setAdapter(mMessageAdapter);
}
private void initV2Chatbot(){
try{
//V2 api
//Initializing the chatbot from json
InputStream stream =
getResources().openRawResource(R.raw.test_agent_credentials);
GoogleCredentials credentials =
GoogleCredentials.fromStream(stream);
String projectId =
((ServiceAccountCredentials)credentials).getProjectId();
SessionsSettings.Builder settingsBuilder =
SessionsSettings.newBuilder();
sessionsClient = SessionsClient.create(sessionsSettings);
session = SessionName.of(projectId, uuid);
}
catch (Exception e){
e.printStackTrace();
}
}
private void sendMessage(View view){
//Retrieving the query written by user
String msg = queryEditText.getText().toString();
//if queryEditText is empty show the warning!
if(msg.trim().isEmpty()){
Toast.makeText(MainActivity.this, "Please enter your query!",
Toast.LENGTH_SHORT).show();
}
else{
//adding user message
MsgClass msg_To = new MsgClass(MsgClass.FROM_USER, msg,
quickR);
messageList.add(msg_To);
int NewMsgPosition = messageList.size() - 1;
// Notify recycler view insert one new data.
mMessageAdapter.notifyItemInserted(NewMsgPosition);
// Scroll RecyclerView to the last message.
mMessageRecycler.scrollToPosition(NewMsgPosition);
// Empty the input edit text box.
queryEditText.setText("");
// Java V2 sending query to cloud
QueryInput queryInput =
QueryInput.newBuilder().setText(TextInput.newBuilder()
.setText(msg).setLanguageCode("en")).build();
new com.example.smokebot.RequestJavaV2Task(MainActivity.this,
session, sessionsClient, queryInput).execute();
}
}
public void callbackV2(DetectIntentResponse response) {
quickR.removeAll(quickR);
if(response != null){
//process aiResponse here
int responsesCount =
response.getQueryResult().getFulfillmentMessagesCount();
String botReply= "";
QuickReplies hasQuickReply;
//Checking if Fullfillment has more than one responses in
order to view them all
if(responsesCount >=2){
//Looping through Fullfillment responses
for(int i=0; i < responsesCount; i++){
Message botReplies =
response.getQueryResult().getFulfillmentMessages(i);
//Counting the text amount of each response
int TextResponseCount =
botReplies.getText().getTextCount();
for(int y=0; y < TextResponseCount; y++){
botReply += botReplies.getText().getText(y) +
"\n";
}
//checking if response contains any QuickReply
hasQuickReply =
response.getQueryResult().getFulfillmentMessages(i).getQuickReplies();
if(hasQuickReply.toString() != " "){
//counting the quick replies existing
int QuickRepliesCount =
hasQuickReply.getQuickRepliesCount();
//Looping through quickreplies to fetch them all
for (int q = 0; q < QuickRepliesCount; q++){
//Updating the list with the new QuickReplies
quickR.add(hasQuickReply.getQuickReplies(q));
System.out.println(quickR);
}
}
}
MsgClass msg_To = new MsgClass(MsgClass.FROM_BOT,
botReply, quickR);
messageList.add(msg_To);
int NewMsgPosition = messageList.size() - 1;
// Notify recycler view insert one new data.
mMessageAdapter.notifyItemInserted(NewMsgPosition);
// Scroll RecyclerView to the last message.
mMessageRecycler.scrollToPosition(NewMsgPosition);
}
//if response is only one
else{
botReply = response.getQueryResult().getFulfillmentText();
MsgClass msg_To = new MsgClass(MsgClass.FROM_BOT,
botReply, quickR);
messageList.add(msg_To);
int NewMsgPosition = messageList.size() - 1;
// Notify recycler view insert one new data.
mMessageAdapter.notifyItemInserted(NewMsgPosition);
// Scroll RecyclerView to the last message.
mMessageRecycler.scrollToPosition(NewMsgPosition);
}
}
else{
String ErrorMessage = "There was some communication issue.
Please Try again!";
MsgClass msg_To = new MsgClass(MsgClass.FROM_BOT,
ErrorMessage, quickR);
messageList.add(msg_To);
int NewMsgPosition = messageList.size() - 1;
// Notify recycler view insert one new data.
mMessageAdapter.notifyItemInserted(NewMsgPosition);
// Scroll RecyclerView to the last message.
mMessageRecycler.scrollToPosition(NewMsgPosition);
}
}
}
MessageListAdapter. java
public class MessageListAdapter extends
RecyclerView.Adapter<RecyclerView.ViewHolder>{
private Context mContext;
private List<MsgClass> mMessageList;
private static final int FROM_BOT = 0;
private static final int FROM_USER = 1;
public MessageListAdapter(Context context, List<MsgClass> messageList) {
mContext = context;
mMessageList = messageList;
}
// Determines the appropriate ViewType according to the sender of the
message.
@Override
public int getItemViewType(int position) {
MsgClass msg_obj = this.mMessageList.get(position);
if (MsgClass.FROM_BOT == msg_obj.getMsgType()) {
// If the current user is the sender of the message
return FROM_BOT;
} else {
// If some other user sent the message
return FROM_USER;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int
viewType) {
View view;
if (viewType == FROM_BOT) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.bot_msg_layout, parent, false);
return new BotMessageHolder(view);
} else if (viewType == FROM_USER) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.user_msg_layout, parent, false);
return new UserMessageHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int
position) {
MsgClass msg_obj = this.mMessageList.get(position);
List<String> QR = msg_obj.getQuickR();
if(getItemViewType(position) == FROM_BOT){
BotMessageHolder botHolder = (BotMessageHolder) holder;
botHolder.bind(msg_obj.getMsgContent());
if(QR.size() != 0){
addButtons(QR, botHolder);
}
}
else{
UserMessageHolder userHolder = (UserMessageHolder) holder;
userHolder.bind(msg_obj.getMsgContent());
}
// switch (holder.getItemViewType()) {
// case FROM_BOT:
// ((BotMessageHolder)
holder).bind(msg_obj.getMsgContent());
// break;
// case FROM_USER:
//
// ((UserMessageHolder)
holder).bind(msg_obj.getMsgContent());
// default:
// break;
// }
}
@Override
public int getItemCount() {
if(mMessageList==null)
{
mMessageList = new ArrayList<MsgClass>();
}
return mMessageList.size();
}
private void addButtons(List<String> QR, BotMessageHolder botHolder){
int QRcount = QR.size();
System.out.println(QRcount);
LinearLayout ll = botHolder.bot_layout;
LinearLayout.LayoutParams layout_params = new
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.MATCH_PARENT);
layout_params.setMargins(4,4,4,4);
layout_params.gravity = Gravity.CENTER_HORIZONTAL;
// int ViewCount = ll.getChildCount();
// View v = null;
// for(int x=0; x< ViewCount; x++){
// v = ll.getChildAt(x);
// if(v instanceof Button){
// if(v.getTag().equals(1) || v.getTag().equals(2) ||
v.getTag().equals(3)){
// ll.removeView(v);
// }
// }
// }
for (int i = 0; i< QRcount; i ++){
Button qr_btn = new Button(mContext);
qr_btn.setId(i);
qr_btn.setTag(i);
qr_btn.setText(QR.get(i));
qr_btn.setBackgroundColor(Color.rgb(255,255,255));
ll.addView(qr_btn);}
}
}
UserMessageHolder. java
public class UserMessageHolder extends RecyclerView.ViewHolder {
TextView user_msg;
LinearLayout user_layout;
UserMessageHolder(View itemView) {
super(itemView);
if(itemView != null){
user_msg = itemView.findViewById(R.id.chatMessage);
user_layout = itemView.findViewById(R.id.user_msg_layout);
}
}
void bind(String message){
user_msg.setText(message);}
}
6) BotMessageHolder. java То же, но для ссылок на ботов.
Дело в том, что я получаю быстрые ответы из облака и хочу просмотреть их как кнопки, чтобы пользователь мог просто щелкнуть их. Я вызываю метод addButtons (List QR, BotMessageHolder botHolder) для выполнения этой работы внутри onBindViewHolder (). первые ответы кажутся правильными, как кнопки, но затем они накладываются друг на друга. Я приложу несколько изображений, чтобы вы поняли, о чем я говорю. Этот, первые быстрые ответы кажутся прекрасными. Они находятся на правом пузыре.
Но когда я прокручиваю первое сообщение бота, они тоже там есть!
И когда сообщение бота со следующими быстрыми ответами они просто накладываются на другие и на другие предыдущие пузыри бота, а не только на текущий. Также кажется, что каждый раз, когда я прокручиваю, они получают больше .. Я не могу понять ..