Reputation: 2644
I have implemented chat view list using the recyclerview. But the list not showing the message to the receiver in real time.
If I send a message, the receiver needs to receive the message in real time. How can I make this to work.
I don't have an idea about the broadCastReceiver. Here I am working with the chat screen. Need to show the chat message in my app.
Issue is if a user sends me a message, I can't able to see the message. I need to receive the message via the recyclerview.
In My chatFragment:
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("");
}
}
});
My Adapter:
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, parent, 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());
}
Upvotes: 0
Views: 2027
Reputation: 542
In order to display real-time data on your RecycleView
, there are two things you need to implement:
WebSockets
, Firebase
, some message queue, etc.RecycleView
. You would like to update the RecycleView
on only with the new messages and not the entire list each time a message is received. For
that you would use the ListAdaptor
and DiffUtil.ItemCallback
. Here is a nice tutorial explaining how to manage RecycleView
updates (explained with Kotlin): https://developer.android.com/codelabs/kotlin-android-training-diffutil-databinding/#0Upvotes: 1
Reputation:
follow this step.
Add these to your app-module build.Gradle file:
dependencies {
// [...]
implementation 'com.pusher:pusher-java-client:1.8.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
Open the activity_main.xml generated for you replace the contents with the following:
<?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>
Next, let us create an adapter for the recycler view. Create a new class called RecyclerListAdapter and paste this:
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()
}
}
Finally, open the MainActivity and set it up like so:
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()
}
}
When the textview that shows the count of the new messages is clicked, it scrolls down immediately to recent messages, set the count to 0 and hides the text view.
The next method is the setupRecyclerView method. Set it up like this:
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 ")
}
The next method is the setupPusher method. Set it up like so:
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()
}
now it's visible.
Upvotes: 0