问题描述
我已经使用 recyclerview 实现了聊天视图列表。但是列表没有实时向接收者显示消息。
如果我发送消息,接收方需要实时接收消息。我怎样才能让它发挥作用。
我不知道 broadCastReceiver。在这里,我正在使用聊天屏幕。需要在我的应用中显示聊天消息。
问题是,如果用户向我发送消息,我无法看到该消息。我需要通过 recyclerview 接收消息。
在我的聊天片段中:
private RecyclerView mChatMessageRecyclerView;
@Override
public void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter("Message_send");
registerForContextMenu(mChatMessageRecyclerView);
}
@Override
public void onPause() {
super.onPause();
unregisterForContextMenu(mChatMessageRecyclerView);
}
private final broadcastReceiver mReceiverRecyclerview = new broadcastReceiver() {
@Override
public void onReceive(Context context,Intent intent) {
mAdapter.notifyDataSetChanged();
mAdapter.notifyItemInserted(getItemCount() + 1);
mChatMessageRecyclerView.smoothScrollToPosition(getItemCount() + 1);
}
};
linearlayoutmanager linearlayoutmanager = new linearlayoutmanager(getActivity());
@Override
public void onViewCreated(View v,@Nullable Bundle b) {
super.onViewCreated(v,b);
linearlayoutmanager.setorientation(linearlayoutmanager.VERTICAL);
linearlayoutmanager.setStackFromEnd(true);
linearlayoutmanager.setSmoothScrollbarEnabled(true);
linearlayoutmanager.setReverseLayout(false);
mChatMessageRecyclerView.setLayoutManager(linearlayoutmanager);
LocalbroadcastReceiver br = new LocalbroadcastReceiver() {
@Override
public void onReceiveIntent(@NonNull Context context,@NonNull Intent intent) {
mAdapter.notifyDataSetChanged();
}
};
mChatMessageRecyclerView.getLayoutManager().smoothScrollToPosition(mChatMessageRecyclerView,new RecyclerView.State(),mChatMessageRecyclerView.getAdapter().getItemCount());
int newMsgPosition = mAdapter.getItemCount();
mChatMessageRecyclerView.setHasFixedSize(true);
mChatMessageRecyclerView.setAdapter(mAdapter);
}
mSendMsg.setonClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String msgContent = mSendMsginputBox.getText().toString();
if(!TextUtils.isEmpty(msgContent))
{
execute(new PostMessageRequest(message,Chatmessage.getmId(),mPostMessageListener);
mSendMsginputBox.setText("");
}
}
});
我的适配器:
private static final int VIEW_TYPE_MESSAGE_SENT = 1;
private static final int VIEW_TYPE_MESSAGE_RECEIVED = 2;
private List<MyMessageModel> msgDtoList;
MyMessageModel msgDto = this.msgDtoList.get(position);
@Override
public int getItemViewType(int position) {
MyMessageModel message = (MyMessageModel) msgDtoList.get(position);
if (message.getId().equals(Profile.getId())) {
// If the current user is the sender of the message
return VIEW_TYPE_MESSAGE_SENT;
} else {
// If some other user sent the message
return VIEW_TYPE_MESSAGE_RECEIVED;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
View view;
if (viewType == VIEW_TYPE_MESSAGE_SENT) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.sender_message_layout,parent,false);
return new SenderMessageHolder(view);
} else if (viewType == VIEW_TYPE_MESSAGE_RECEIVED) {
view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.receiver_message_layout,false);
return new ReceiverMessageHolder(view);
}
return null;
}
public void onBindViewHolder(RecyclerView.ViewHolder holder,int position) {
LastMessageContent message = (LastMessageContent) msgDtoList.get(position);
switch (holder.getItemViewType()) {
case VIEW_TYPE_MESSAGE_SENT:
populateSentViewHolder(holder,position); break;
case VIEW_TYPE_MESSAGE_RECEIVED:
populateReceivedViewHolder(holder,position);
}
@SuppressLint("ResourceAsColor")
private void populateSentViewHolder(RecyclerView.ViewHolder holder,int position) {
MyMessageModal msgDto = this.msgDtoList.get(position);
((SenderMessageHolder) holder).rightMsgTextView.setText(msgDto.getmMSg());
}
@SuppressLint("ResourceAsColor")
private void populateReceivedViewHolder(RecyclerView.ViewHolder holder,int position) {
MyMessageModal msgDto = this.msgDtoList.get(position);
((ReceiverMessageHolder) holder).leftMsgTextView.setText(msgDto.getmMSg());
}
解决方法
为了在您的 RecycleView
上显示实时数据,您需要实现两件事:
- 您监听实时数据的数据源。这可能是
来自例如
WebSockets
、Firebase
、一些消息队列等 - 然后您需要将传入的消息通知您的适配器
然后更新您的
RecycleView
。您希望在每次收到消息时仅使用新消息而不是整个列表更新RecycleView
。为了 您将使用ListAdaptor
和DiffUtil.ItemCallback
。这是一个很好的教程,解释了如何管理RecycleView
更新(用 Kotlin 解释):https://developer.android.com/codelabs/kotlin-android-training-diffutil-databinding/#0
遵循此步骤。
将这些添加到您的应用模块 build.Gradle 文件中:
dependencies {
// [...]
implementation 'com.pusher:pusher-java-client:1.8.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
打开为您生成的activity_main.xml,将内容替换为以下内容:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
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"
tools:context=".MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerViewContents"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:textSize="16sp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_margin="16dp"
android:background="@drawable/rounded_corner"
android:textColor="@android:color/black"
android:visibility="gone"
android:layout_gravity="right|bottom"
android:id="@+id/textViewNewContents" />
</FrameLayout>
**Create a new drawable named rounded_corner and paste this:**
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<stroke
android:width="1dp" />
<solid android:color="#ffffff" />
<padding
android:left="1dp"
android:right="1dp"
android:bottom="1dp"
android:top="1dp" />
<corners android:radius="5dp" />
</shape>
接下来,让我们为回收者视图创建一个适配器。创建一个名为 RecyclerListAdapter 的新类并粘贴:
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
class RecyclerListAdapter(private val listener:OnLastPositionReached): RecyclerView.Adapter<RecyclerListAdapter.ViewHolder>() {
private val contentList: ArrayList<String> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater
.from(parent.context)
.inflate(android.R.layout.simple_list_item_1,parent,false)
)
}
override fun onBindViewHolder(holder: ViewHolder,position: Int) {
holder.bind(contentList[position])
if (position == contentList.size-1){
listener.lastPositionReached()
} else {
listener.otherPosition()
}
}
override fun getItemCount(): Int = contentList.size
fun addItem(item:String) {
contentList.add(item)
notifyDataSetChanged()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val userName: TextView = itemView.findViewById(android.R.id.text1)
fun bind(item: String) = with(itemView) {
userName.text = item
}
}
interface OnLastPositionReached {
fun lastPositionReached()
fun otherPosition()
}
}
最后,打开 MainActivity 并进行如下设置:
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.view.View
import com.pusher.client.Pusher
import com.pusher.client.PusherOptions
import kotlinx.android.synthetic.main.activity_main.*
import org.json.JSONObject
class MainActivity : AppCompatActivity(),RecyclerListAdapter.OnLastPositionReached {
private var count = 0
private val recyclerListAdapter = RecyclerListAdapter(this)
private var lastPosition = false
override fun otherPosition() {
lastPosition = false
}
override fun lastPositionReached() {
lastPosition = true
textViewNewContents.visibility = View.GONE
count = 0
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupClickListeners()
setupRecyclerView()
setupPusher()
}
}
点击显示新消息计数的文本视图时,它会立即向下滚动到最近的消息,将计数设置为 0 并隐藏文本视图。
下一个方法是 setupRecyclerView 方法。像这样设置:
private fun setupRecyclerView() {
with(recyclerViewContents){
layoutManager = LinearLayoutManager(this@MainActivity)
adapter = recyclerListAdapter
}
recyclerListAdapter.addItem("Hello World")
recyclerListAdapter.addItem("New article alert!")
recyclerListAdapter.addItem("Pusher is actually awesome")
recyclerListAdapter.addItem("Realtime functionality freely provided ")
recyclerListAdapter.addItem("Checkout pusher.com/tutorials")
recyclerListAdapter.addItem("You can also checkout blog.pusher.com")
recyclerListAdapter.addItem("Learn how to update contents properly ")
recyclerListAdapter.addItem("Hello World")
recyclerListAdapter.addItem("New article alert!")
recyclerListAdapter.addItem("Pusher is actually awesome")
recyclerListAdapter.addItem("Realtime functionality freely provided ")
recyclerListAdapter.addItem("Checkout pusher.com/tutorials")
recyclerListAdapter.addItem("You can also checkout blog.pusher.com")
recyclerListAdapter.addItem("Learn how to update contents properly ")
}
下一个方法是 setupPusher 方法。像这样设置:
private fun setupPusher() {
val options = PusherOptions()
options.setCluster("PUSHER_CLUSTER")
val pusher = Pusher("PUSHER_KEY",options)
val channel = pusher.subscribe("my-channel")
channel.bind("my-event") { channelName,eventName,data ->
runOnUiThread {
if (!lastPosition){
count ++
textViewNewContents.text = count.toString()
textViewNewContents.visibility = View.VISIBLE
recyclerListAdapter.addItem(JSONObject(data).getString("message"))
} else {
recyclerListAdapter.addItem(JSONObject(data).getString("message"))
recyclerViewContents.scrollToPosition(recyclerListAdapter.itemCount-1)
}
}
}
pusher.connect()
}
现在它是可见的。