私のアプリでは、私のスマートフォン(PHONE1と呼ぶ)から別のもの(PHONE2)にメッセージと通知を送信します。メッセージはPHONE2によって受信されます。 PHONE2はPHONE1に応答メッセージを送信します。 PHONE1は通知を受信し、メッセージを読み取ります。 PHONE1はPHONE2に返信メッセージを送信し、アプリがクラッシュします。メッセージチャットが正常に機能しない
Messages.java:
public class Messages extends AppCompatActivity {
private static final String TAG = "ChatActivity";
Context context;
private ChatArrayAdapter chatArrayAdapter;
private ListView listView;
private EditText chatText;
private Button buttonSend;
private boolean side = false;
String from, to, mess;
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messages);
buttonSend = (Button) findViewById(R.id.send);
listView = (ListView) findViewById(R.id.chatMessage);
chatArrayAdapter = new ChatArrayAdapter(getApplicationContext(), R.layout.row_messages_right);
listView.setAdapter(chatArrayAdapter);
chatText = (EditText) findViewById(R.id.msg);
chatText.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
return sendChatMessage();
}
return false;
}
});
buttonSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
sendChatMessage();
}
});
listView.setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
listView.setAdapter(chatArrayAdapter);
//to scroll the list view to bottom on data change
chatArrayAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
super.onChanged();
listView.setSelection(chatArrayAdapter.getCount() - 1);
}
});
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
receiveChatMessage();
}
}, 0, 1000);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private boolean receiveChatMessage(){
InternalDatabaseOperations DB = new InternalDatabaseOperations(this);
Cursor CR = DB.getInformation(DB);
CR.moveToLast();
from = CR.getString(0);
to = CR.getString(1);
if(!Objects.equals(mess, CR.getString(2))){
mess = CR.getString(2);
chatArrayAdapter.add(new ChatMessage(!side, mess));
return true;
}
return false;
}
//Send chat message
private boolean sendChatMessage() {
mess = chatText.getText().toString();
chatArrayAdapter.add(new ChatMessage(side,mess));
chatText.setText("");
InternalDatabaseOperations DB = new InternalDatabaseOperations(this);
Cursor CR = DB.getInformation(DB);
CR.moveToLast();
from = CR.getString(1);
to = CR.getString(0);
BackgroundTaskSendingMessage sendingMessage = new BackgroundTaskSendingMessage(this);
sendingMessage.execute(to, from, mess);
return true;
} }
chatArrayAdapter.java:
class ChatArrayAdapter extends ArrayAdapter<ChatMessage> {
private TextView chatText;
private List<ChatMessage> chatMessageList = new ArrayList<>();
private Context context;
@Override
public void add(ChatMessage object) {
chatMessageList.add(object);
super.add(object);
}
public ChatArrayAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
this.context = context;
}
public int getCount() {
return this.chatMessageList.size();
}
//Retrieve message position
public ChatMessage getItem(int index) {
return this.chatMessageList.get(index);
}
//Change layout inflater if necessary
public View getView(int position, View convertView, ViewGroup parent) {
ChatMessage chatMessageObj = getItem(position);
View row = convertView;
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (chatMessageObj.left) {
row = inflater.inflate(R.layout.row_messages_right, parent, false);
}else{
row = inflater.inflate(R.layout.row_messages_left, parent, false);
}
chatText = (TextView) row.findViewById(R.id.msgr);
chatText.setText(chatMessageObj.message);
return row;
}
}
MessagingServiceNotification:
public class MyFirebaseMessagingService extends FirebaseMessagingService{
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
String message = remoteMessage.getData().get("message");
String from = remoteMessage.getData().get("From");
String to = remoteMessage.getData().get("to");
InternalDatabaseOperations DB = new InternalDatabaseOperations(this);
DB.putInformation(DB, from, to, message);
showNotification(message);
}
private void showNotification(String message) {
Intent i = new Intent(this, Messages.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setAutoCancel(true)
.setContentTitle("BookStore")
.setContentText(message)
.setSmallIcon(R.drawable.book)
.setContentIntent(pendingIntent);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.notify(0, builder.build());
}
}
logcat:
14007-14681/gamingproject.sellmybooks E/AndroidRuntime: FATAL EXCEPTION: Timer-0
Process: gamingproject.sellmybooks, PID: 14007
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6353)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:875)
at android.view.View.requestLayout(View.java:17524)
at android.view.View.requestLayout(View.java:17524)
at android.view.View.requestLayout(View.java:17524)
at android.view.View.requestLayout(View.java:17524)
at android.view.View.requestLayout(View.java:17524)
at android.view.View.requestLayout(View.java:17524)
at android.view.View.requestLayout(View.java:17524)
at android.widget.AbsListView.requestLayout(AbsListView.java:2027)
at android.widget.AbsListView.setSelectionFromTop(AbsListView.java:7045)
at android.widget.ListView.setSelection(ListView.java:2018)
at gamingproject.sellmybooks.Messages$3.onChanged(Messages.java:74)
at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
at android.widget.ArrayAdapter.notifyDataSetChanged(ArrayAdapter.java:286)
at android.widget.ArrayAdapter.add(ArrayAdapter.java:182)
at gamingproject.sellmybooks.ChatArrayAdapter.add(ChatArrayAdapter.java:22)
at gamingproject.sellmybooks.Messages.receiveChatMessage(Messages.java:104)
at gamingproject.sellmybooks.Messages.access$300(Messages.java:23)
at gamingproject.sellmybooks.Messages$4.run(Messages.java:83)
at java.util.Timer$TimerImpl.run(Timer.java:284)
は助けを事前にありがとうございます。
ログに基づいて、別のスレッドからビューを更新しようとしています。これはできません。 –
このエラーを調整するにはどうすればよいですか? – Carlo
私はエキスパートではありませんが、データをメインスレッドに渡すことができるかどうかを確認してください。サービスを使用してメッセージを受信し、メインアクティビティにデータを渡します。もう一度、あいまいな言葉を残して申し訳ありません。 –