Real Time Updates

Real-time update is the most important part in building an instant chat messaging application. Applozic provides very simple methods to register and listen for the events to update them on the UI. The publish-subscribe pattern is used here in which the senders of messages, called publishers, do not program the messages to be sent directly to specific receivers, called subscribers, but instead categorize published messages into classes without knowledge of which subscribers, if any, there may be. Similarly, subscribers express interest in one or more classes and only receive messages that are of interest, without knowledge of which publishers, if any, there are.

Connecting to publish

Use the below code to connect to publish.

There are two ways to connect using applozic methods :

A) Connect and Verifying token internally and shows the loader with the message passed in the below method .

Applozic.connectPublishWithVerifyToken(context, "Please wait...");
Applozic.connectPublishWithVerifyToken(context, "Please wait...")

B) Connect publish and Show your own loading indicator

if (AlAuthService.isTokenValid(context)) {
  Applozic.connectPublish(context);
} else {
  // Getting new token from server and on success call the connect publish will be called.
  AlAuthService.refreshToken(context, new AlCallback() {
    @Override
    public void onSuccess(Object response) {
      Applozic.connectPublish(context);
    }

    @Override
    public void onError(Object error) {

}
  });
}
if (AlAuthService.isTokenValid(context)) {
       Applozic.connectPublish(context)
    } else {
       // Getting new token from server and on success call the connect publish will be called.
     AlAuthService.refreshToken(context, object : AlCallback {
          override fun onSuccess(response: Any) {
              Applozic.connectPublish(context)
          }

          override fun onError(error: Any) {}
    })
}

Disconnecting from publish

Use the below code to disconnect from publish.

Applozic.disconnectPublish(context);
Applozic.disconnectPublish(context)

📘

Note

The connect and disconnect must be called only once during the lifecycle of an activity/fragment. The best place would be onCreate() for connectPublish and onDestroy() for disconnectPublish. Once a user has called the connectPublish method, he will be marked as online until the disconnectPublish method is called.

Handling the UI listener

After the publish has been connected, you will need to register the ApplozicUIListener to listen for different events that occur in real time. Follow these steps to register the listener:

  • Implement ApplozicUIListener in your activity/fragment.
  • Register the listener when user enters the chat fragment/activity
  • Update the events received from the callback on the UI
  • Unregister the listener when user leaves the chat fragment/activity

Implement ApplozicUIListener in your activity/fragment

public class ConversationActivity extends AppCompatActivity implements ApplozicUIListener{ 
}
class ConversationActivity : AppCompatActivity(), ApplozicUIListener {
        
 }

Register the listener

You can register the listener using the below code. Every instance of the listener must be registered with a unique ID. In the below code we are registering the listener using id as "listener2":

AlEventManager.getInstance().registerUIListener("listener2", this);
AlEventManager.getInstance().registerUIListener("listener2", this)

Updating the events on the UI

You need to override all the methods of the ApplozicUIListener in your activity/fragment that implements this listener. The methods are described below:

@Override
    public void onMessageSent(Message message) {
     //When a message has been sent     
    }

   @Override
    public void onMessageReceived(Message message) {
        //when a new message is received. You could reload the message list or add this message to the existing message list to update this message on UI.
    }

    @Override
    public void onLoadMore(boolean loadMore) {
      //If message list pagination has been called
    }

    @Override
    public void onMessageSync(Message message, String key) {
       //If a message has been synced with server.
    }

    @Override
    public void onMessageDeleted(String messageKey, String userId) {
       //If a message was deleted successfully for a user
    }

    @Override
    public void onMessageDelivered(Message message, String userId) {
       //If a message has been delivered to a User with userId
    }

    @Override
    public void onAllMessagesDelivered(String userId) {
      //If all the pending messages have been delivered with to the User
    }

    @Override
    public void onAllMessagesRead(String userId) {
       //If all messages have been read by the User
    }

    @Override
    public void onConversationDeleted(String userId, Integer channelKey, String response) {
       //If a conversation thread has been deleted. If channelKey is not null, it is for the group else it is for the user.
    }

    @Override
    public void onUpdateTypingStatus(String userId, String isTyping) {
       //If the typing status has been updated for the user.
        //if isTyping is 1, the user has started typing
        //if isTyping is 0, the user has stopped typing
    }

    @Override
    public void onUpdateLastSeen(String userId) {
      //Will be received if the User's last seen has been updated or if login user blocked some one or blocked by some one to login user
         ContactDatabase service = new ContactDatabase(this);
        Contact contact = service.getContactById(userId);
        if (contact != null) {
            Log.i("Blocked"," Is Login user blocked the userID ? :" + contact.getUserId() + "blocked ?" + contact.isBlocked());
            Log.i("Blocked BY"," Is Some one blocked the login user ? :" + contact.getUserId() + "blockedBy ?" + contact.isBlockedBy());
        }
    }
 
    @Override
    public void onMqttDisconnected() {
       //call connectPublish method here
    }

    @Override
    public void onMqttConnected() {
        //Will be received when Mqtt connection is successfull
    }

    @Override
    public void onUserOnline() {
         //Will be received when the logged in user goes online(when connectPublish is called)
    }

    @Override
    public void onUserOffline() {
         //Will be received when the logged in user goes offline(when disconnectPublish is called).
    }

    @Override
    public void onChannelUpdated() {
      //When the channel sync call has been completed
    }

    @Override
    public void onConversationRead(String userId, boolean isGroup) {
      //If the conversation has been read by a user
      //if isGroup is true, the user has read the conversation in a group
    }

    @Override
    public void onUserDetailUpdated(String userId) {
      //When the user details have been updated for a user
    }

    @Override
    public void onMessageMetadataUpdated(String keyString) {
      //When message metadata is updated
    }

    @Override
    public void onUserMute(boolean mute, String userId) {
      //When a user is muted by the logged in user
    }

    @Override
    public void onGroupMute(Integer groupId) {
     // When group is mute from same user from differnt device
    }
override fun onMessageSent(message: Message?) {
   //When a message has been sent
}

override fun onMessageReceived(message: Message?) {
   //when a new message is received. You could reload the message list or add this message to the existing message list to update this message on UI.
}

 override fun onLoadMore(loadMore: Boolean) {
    //If message list pagination has been called
 }

override fun onMessageSync(message: Message?, key: String?) {
   //If a message has been synced with server.
}

override fun onMessageDeleted(messageKey: String?, userId: String?) {
   //If a message was deleted successfully for a user
}

override fun onMessageDelivered(message: Message?, userId: String?) {
   //If a message has been delivered to a User with userId
}

override fun onAllMessagesDelivered(userId: String?) {
    //If all the pending messages have been delivered with to the User
}

override fun onAllMessagesRead(userId: String?) {
    //If all messages have been read by the User
}

override fun onConversationDeleted(userId: String?, channelKey: Int?, response: String?) {
    //If a conversation thread has been deleted. If channelKey is not null, it is for the group else it is for the user.
}

override fun onUpdateTypingStatus(userId: String?, isTyping: String?) {
    //If the typing status has been updated for the user.
    //if isTyping is 1, the user has started typing
    //if isTyping is 0, the user has stopped typing
}

override fun onUpdateLastSeen(userId: String?) {
   //Will be received if the User's last seen has been updated or if login user blocked some one or blocked by some one to login user
   //Will be received if the User's last seen has been updated or if login user blocked some one or blocked by some one to login user

        if (userId != null) {
            val service = ContactDatabase(this)
            val contact = service.getContactById(userId)
            if (contact != null) {
                Log.i("Blocked", " Is Login user blocked the userID ? :" + contact.userId + "blocked ?" + contact.isBlocked)
                Log.i("Blocked BY", " Is Some one blocked the login user ? :" + contact.userId + "blockedBy ?" + contact.isBlockedBy)
            }
        }
}

override fun onMqttDisconnected() {
    //call connectPublish method here
}

override fun onMqttConnected() {
    //Will be received when Mqtt connection is successfull
}

override fun onUserOnline() {
    //Will be received when the logged in user goes online(when connectPublish is called)
}

override fun onUserOffline() {
    //Will be received when the logged in user goes offline(when disconnectPublish is called).
}
override fun onUserActivated(isActivated: Boolean) {
}

override fun onChannelUpdated() {
    //When the channel sync call has been completed
}
override fun onConversationRead(userId: String?, isGroup: Boolean) {
    //If the conversation has been read by a user
    //if isGroup is true, the user has read the conversation in a group
}

override fun onUserDetailUpdated(userId: String?) {
    //When the user details have been updated for a user
}

override fun onMessageMetadataUpdated(keyString: String?) {
    //When message metadata is updated
}
override fun onUserMute(mute: Boolean, userId: String?) {
   //When a user is muted by the logged in user
}
override fun onGroupMute(groupId: Int?) {
    // When group is mute from same user from differnt device
}

Unregister the listener

Once the user leaves the chat activity/fragment, the real time update is no longer needed. You can unregister the listener at that point using the unique id with which it was registered. Use the below code to unregister the ApplozicUIListener:

AlEventManager.getInstance().unregisterUIListener("listener2");
AlEventManager.getInstance().unregisterUIListener("listener2")

📘

Note

The best place for register would be onCreate(), and for unregister, it would be onDestroy().This will ensure you get the updates even if your activity/fragment is in background. You can register as many instances of the listener as you want with unique ids.

Sending Typing status

The user can publish his/her typing status to any one who has subscribed for the same. You can publish your typing status using the below code :

Applozic.publishTypingStatus(context, channel, contact, isTypingStarted);
Applozic.publishTypingStatus(context, channel, contact, isTypingStarted)

Argument

Type

Description

context

Context/Activity

The calling context

channel

Channel

Publishing your typing status to a particular channel

contact

Contact

Publishing your typing status to a particular User

isTypingStarted

boolean

true if typing has started
false if typing has stopped

Call the above method in the onTextChangedListener() call back of the TextWatcher attached to the EditText.

Subscribing to typing status

You need to subscribe to a users typing status to get notified for the same. Use the below code to subscribe for the typing status for a user or in a group.

Applozic.subscribeToTyping(Context context, Channel channel, Contact contact);
Applozic.subscribeToTyping(context,  channel, contact)

Argument

Type

Description

context

Context/Activity

The calling context

channel

Channel

The Group to which the user wants to subscribe. Should be null if it is for 1-to-chat.

contact

Contact

The user to whose typing status you want to subscribe to

UnSubscribe for typing status

If you have subscribed for a user's typing status, you need to unsubscribe for the same too. Use the below code to un-subscribe for a user's typing status:

Applozic.unSubscribeToTyping(Context context, Channel channel, Contact contact);
Applozic.unSubscribeToTyping(context, channel, contact)

Updating the user status

When a user calls the connectPublish method, he/she will be marked as online in applozic platform until a call to disconnectPublish method has been made. Whenever the status changes the callback
onUpdateLastSeen(String userId) from ApplozicUIListener(If registered) will be fired. The Contact would be automatically updated in the local DB irrespective of if the callback is registered or not. But you would need the callback to update the status on the UI in real time.

For e.g If you have a chat thread opened with a Contact mUser and ApplozicUIListener is registered in the fragment/activity. Whenever the status of mUser changes the callback will be fired and you need to update the contact in the fragment/activity as below:

@Override
    public void onUpdateLastSeen(String userId) {
    //to avoid update if chat thread is opened with different contact or group
    if(userId != null && mUser != null && userId.equals(mUser.getUserId())) {
      //we have updated the current contact
      mUser = appContactService.getContactById(userId);
      processLastSeenStatus(mUser);
    }
override fun onUpdateLastSeen(userId: String?) {
   //to avoid update if chat thread is opened with different contact or group
  if (mUser != null && userId.equals(mUser.getUserId())) {
    //we have updated the current contact
     mUser = contact.getContactById(userId)
     processLastSeenStatus(mUser)
   }
}

Your logic to display the status goes inside the method processLastSeenStatus()

public void processLastSeenStatus(Contact contact){
   if(contact.isBlocked() || contact.isBlockedBy() || contact.isDeleted()){
      statusTv.setText("");
     return;
   }
  
  if(contact.isConnected()){
    statusTv.setText("Online");
  }else if(contact.getLastSeenAt() != 0){
    //Use formate from applozic as below or create your own format from contact.getLastSeenAt()
    statusTv.setText(getContext().getString(R.string.subtitle_last_seen_at_time) + " " + DateUtils.getDateAndTimeForLastSeen(getContext(), contact.getLastSeenAt(), R.string.JUST_NOW, R.plurals.MINUTES_AGO, R.plurals.HOURS_AGO, R.string.YESTERDAY));
  }else {
    statusTv.setText("");
  }
}
fun processLastSeenStatus(contact: Contact) {
    if (contact.isBlocked || contact.isBlockedBy || contact.isDeleted) {
            statusTv.setText("")
            return
        }
        if (contact.isConnected) {
            statusTv.setText("Online")
        } else if (contact.lastSeenAt != 0L) {
            //Use formate from applozic as below or create your own format from contact.getLastSeenAt()
            statusTv.setText(getContext().getString(R.string.subtitle_last_seen_at_time).toString() + " " + DateUtils.getDateAndTimeForLastSeen(getContext(), contact.lastSeenAt, R.string.JUST_NOW, R.plurals.MINUTES_AGO, R.plurals.HOURS_AGO, R.string.YESTERDAY))
        } else {
            statusTv.setText("")
        }
 }

Did this page help you?