Skip to main content

User Profile Hosting Page Design

tip

This feature is supported starting from version 5.12.0.

Page Architecture Design

The User Profile Hosting adopts the MVVM (Model-View-ViewModel) pattern, combining Android's Fragment and Activity lifecycle management with a layered decoupling design philosophy. Each layer has clearly defined responsibilities in the architecture, aiming to improve code readability, maintainability, and extensibility.

  • Activity: Serves as the entry point of the page, responsible for loading and displaying Fragments and passing necessary parameters.
  • Fragment: Handles UI display and user interaction logic, fetching data through ViewModel and updating views.
  • ViewModel: Acts as the intermediary layer for data and business logic, processing data retrieval, manipulation, and updates, and notifying Fragments of data changes.
  • Handler: Serves as the core layer for business data processing, encapsulating specific implementations of data retrieval and operations, and providing interfaces for data manipulation.
  • Component: Encapsulates commonly used UI controls and interaction logic to enhance component reusability.
  • XML Layout Files: Define the structure, style, and layout of views, providing UI support for Fragments.

Architecture Module Roles

Page Architecture Hierarchy

Activity Layer

  • Role:
    • Serves as the entry point of the page, responsible for initializing and loading Fragments.
    • Manages page navigation, parameter passing, and communication between Fragments.

Fragment Layer

  • Role:
    • Acts as the primary layer for UI display and interaction logic, responsible for loading and managing view components.
    • Handles user interaction events such as button clicks and input field changes.
    • Observes data changes through ViewModel and updates views accordingly.
  • Custom Methods:
    • onCreateViewModel():
      • Creates a ViewModel instance via ViewModelProvider. Can be overridden to return a custom ViewModel class.
    • onCreateView():
      • Calls the parent class's layout loading logic via super.onCreateView() and adds or adjusts custom views on top of the parent class.
    • onViewReady():
      • Binds LiveData, sets click event listeners, and updates the UI.

ViewModel Layer

  • Role:
    • Acts as the bridge between Fragments and the data layer, managing and processing business logic.
    • Notifies Fragments of data changes via mechanisms like LiveData.
    • Calls Handlers for data retrieval, updates, or submissions.
  • Custom Methods:
    • Add new business logic processing methods or create new LiveData properties.

Handler Layer

  • Role:
    • Serves as the concrete implementation layer for data operations, encapsulating calls to data sources to avoid memory leaks.
    • Provides methods for data retrieval, saving, updating, and deletion, offering interfaces for ViewModel.

Component Layer

  • Role:
    • Encapsulates commonly used view components to improve reusability.

XML Layout File Layer

  • Role:
    • Defines the structure, style, and layout of views, forming the foundation for UI display.
    • Allows quick definition and modification of view structures through layout files.

Architecture Flow

Customization Guide

Role of KitFragmentFactory

KitFragmentFactory is a factory class in Kit for creating Fragments, enabling developers to flexibly manage and replace Fragments. By extending KitFragmentFactory and overriding methods like newGroupProfileFragment(), you can return a custom GroupProfileFragment.

public class CustomKitFragmentFactory extends KitFragmentFactory {  
@NonNull
@Override
public GroupProfileFragment newGroupProfileFragment(@NonNull Bundle args) {
CustomGroupProfileFragment fragment = new CustomGroupProfileFragment();
fragment.setArguments(args);
return fragment;
}
}

// Set the custom factory during IMUIKit initialization in the Application class:
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
// Set the custom Fragment factory
IMCenter.setKitFragmentFactory(new CustomKitFragmentFactory());
}
}

Customizing Fragments

  • Scope:

    • Override onCreateView() and onViewReady() to add custom view components and interaction logic.
    • Handle specific UI logic and user interactions, such as button clicks or page refreshes.
  • Recommendations:

    • Delegate all business logic to ViewModel, with Fragment focusing solely on UI display and user interaction event handling.
    • Fetch data and observe changes via ViewModel, avoiding direct interaction with data sources.
// Custom Fragment (e.g., CustomGroupProfileFragment)  
public class CustomGroupProfileFragment extends GroupProfileFragment {

// Override to return a custom ViewModel (e.g., CustomGroupProfileViewModel)
@Override
protected GroupProfileViewModel onCreateViewModel(Bundle bundle) {
return new ViewModelProvider(this, new ViewModelFactory(bundle))
.get(CustomGroupProfileViewModel.class);
}

@Override
protected void onViewReady(@NonNull GroupProfileViewModel viewModel) {
super.onViewReady(viewModel);

// Change the title text
headComponent.setTitleText("New Title");

// Override the back button click event in the title bar
headComponent.setLeftClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Custom back button logic
}
});

// Override the right button click event in the title bar (if applicable)
headComponent.setRightClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Custom right button logic
}
});

// Set the right button icon in the title bar
headComponent.setRightTextDrawable(R.drawable.rc_right_icon);
}
}

Customizing ViewModel

  • Scope:

    • Add custom business logic methods, such as data filtering or transformation.
    • Create new LiveData properties for Fragments to observe data changes.
  • Recommendations:

    • Encapsulate all business logic in ViewModel, avoiding logic in Fragment or Handler.
    • Use Handler for data retrieval and operations, preventing direct interaction with data sources in ViewModel.
// Custom ViewModel (e.g., CustomGroupProfileViewModel)  
public class CustomGroupProfileViewModel extends GroupProfileViewModel {

public CustomGroupProfileViewModel(@NonNull Bundle arguments) {
super(arguments);
}

// Add custom business logic
}

Customizing XML Layout Files

  • Scope:

    • Copy the original Kit page's XML layout files to the app's res/layout directory and modify or add view components as needed.
    • Define custom view attributes and styles, such as colors, sizes, and spacing.
  • Notes:

    • Do not delete original views: Even if certain default views are unnecessary, avoid deleting them. Instead, hide them by setting visibility to GONE or INVISIBLE.
    • Do not modify original view IDs: Changing original view IDs may cause GroupProfileFragment logic to malfunction.

Handler Function Overview

Role: Serves as the core layer for business data processing, encapsulating concrete implementations of data retrieval and operations, and providing interfaces for data manipulation.

GroupInfoHandler

GroupInfoHandler is primarily used to fetch basic group information and details of specified members, with DataKey identifying different data operation types for easy monitoring and handling. Below are the external interface descriptions and DataKey definitions for GroupInfoHandler:

public class GroupInfoHandler extends MultiDataHandler {  

// DataKey for fetching group information
public static final DataKey<GroupInfo> KEY_GROUP_INFO =
MultiDataHandler.DataKey.obtain("KEY_GROUP_INFO", GroupInfo.class);

// DataKey for fetching group member information
public static final DataKey<List<GroupMemberInfo>> KEY_GET_GROUP_MEMBERS =
MultiDataHandler.DataKey.obtain("KEY_GET_GROUP_MEMBERS",
(Class<List<GroupMemberInfo>>) (Class<?>) List.class);

// DataKey for searching group members
public static final DataKey<List<GroupMemberInfo>> KEY_SEARCH_GROUP_MEMBERS =
MultiDataHandler.DataKey.obtain("KEY_SEARCH_GROUP_MEMBERS",
(Class<List<GroupMemberInfo>>) (Class<?>) List.class);

/**
* Fetch group information
* @description Fetches detailed information of the specified group and notifies the caller via listener callback.
*/
public void getGroupsInfo() {
// Fetches detailed group information (e.g., group name, announcement, avatar) from the server.
// Results are returned via listener callback: group info on success, error code on failure.
}

/**
* Fetch group member information
* @param userIds List of user IDs
* @description Fetches group member information for the specified user IDs and notifies the caller via listener callback.
*/
public void getGroupMembers(List<String> userIds) {
// Fetches detailed member information (e.g., role, join time) for the specified user IDs in the current group.
// Results are returned via listener callback: member info list on success, error code on failure.
}

/**
* Search group members
* @param name Member name
* @description Searches group members by name and notifies the caller via listener callback.
*/
public void searchGroupMembers(String name) {
// Searches for member information matching the name in the current group.
// Results are returned via listener callback: member info list on success, error code on failure.
}
}

DataKey Descriptions

  • KEY_GET_GROUP_MEMBERS: Identifies the data key for fetching group member information, type: List<GroupMemberInfo>.
  • KEY_TOTAL_GROUP_MEMBERS: Identifies the data key for total group member count, type: Integer.
  • KEY_LOAD_MORE: Identifies the data key for whether more group member data can be loaded, type: Boolean.

GroupMembersPagedHandler

GroupMembersPagedHandler is used to fetch group member lists in a paginated manner, supporting fetching by role and providing load-more functionality. Below are the external interface descriptions and DataKey definitions for GroupMembersPagedHandler:

public class GroupMembersPagedHandler extends MultiDataHandler {  

// DataKey for fetching group member information
public static final DataKey<List<GroupMemberInfo>> KEY_GET_GROUP_MEMBERS =
MultiDataHandler.DataKey.obtain("KEY_GET_GROUP_MEMBERS",
(Class<List<GroupMemberInfo>>) (Class<?>) List.class);

// DataKey for whether more group member data can be loaded
private static final DataKey<Boolean> KEY_LOAD_MORE =
DataKey.obtain("KEY_LOAD_MORE", Boolean.class);

/**
* Fetch group member information
* @param groupMemberRole Group member role
* @description Fetches member lists by specified role (e.g., owner, admin, regular member) with pagination support.
*/
public void getGroupMembersByRole(@NonNull GroupMemberRole groupMemberRole) {
// Fetches member lists by role with pagination.
// Results are returned via listener callback: member list on success, error code on failure.
}

/**
* Load next page of group member data
* @param listener Data change listener
* @description Loads more group member information and notifies the caller via listener callback.
*/
public void loadNext(OnDataChangeListener<Boolean> listener) {
// Loads the next page of data for the current member role.
// Returns true via listener on success, false otherwise.
}

/**
* Check if more data is available
* @description Checks if more group member data can be loaded.
* @return true if more data is available, false otherwise.
*/
public boolean hasNext() {
// Returns whether more data can be loaded.
return !TextUtils.isEmpty(nextPageToken);
}
}

DataKey Descriptions

  • KEY_GET_GROUP_MEMBERS: Identifies the data key for fetching group member information, type: List<GroupMemberInfo>.
  • KEY_TOTAL_GROUP_MEMBERS: Identifies the data key for total group member count, type: Integer.
  • KEY_LOAD_MORE: Identifies the data key for whether more group member data can be loaded, type: Boolean.

GroupOperationsHandler

GroupOperationsHandler provides interfaces for various group operations, such as creating groups, inviting users, kicking members, updating group info, disbanding, and leaving groups. Below are the external interface descriptions and DataKey definitions for GroupOperationsHandler:

public class GroupOperationsHandler extends MultiDataHandler {  

// DataKey for group creation operation
public static final DataKey<IRongCoreEnum.CoreErrorCode> KEY_CREATE_GROUP =
DataKey.obtain("KEY_CREATE_GROUP", IRongCoreEnum.CoreErrorCode.class);

// DataKey for inviting users to a group
public static final DataKey<Boolean> KEY_INVITE_USERS_TO_GROUP =
DataKey.obtain("KEY_INVITE_USERS_TO_GROUP", Boolean.class);

// DataKey for kicking group members
public static final DataKey<Boolean> KEY_KICK_GROUP_MEMBERS =
DataKey.obtain("KEY_KICK_GROUP_MEMBERS", Boolean.class);

// DataKey for updating group info
public static final DataKey<Boolean> KEY_UPDATE_GROUP_INFO =
DataKey.obtain("KEY_UPDATE_GROUP_INFO", Boolean.class);

// DataKey for leaving a group
public static final DataKey<Boolean> KEY_QUIT_GROUP =
DataKey.obtain("KEY_QUIT_GROUP", Boolean.class);

// DataKey for disbanding a group
public static final DataKey<Boolean> KEY_DISMISS_GROUP =
DataKey.obtain("KEY_DISMISS_GROUP", Boolean.class);

/**
* Create a group
* @param groupInfo Group info
* @param inviteeUserIds List of user IDs to invite
* @description Creates a group and invites specified users, notifying the caller via listener callback.
*/
public void createGroup(GroupInfo groupInfo, List<String> inviteeUserIds) {
// Creates a new group and invites specified users.
// Results are returned via listener callback: success result on success, error code on failure.
}

/**
* Invite users to a group
* @param userIds List of user IDs
* @description Invites specified users to the group and notifies the caller via listener callback.
*/
public void inviteUsersToGroup(@NonNull List<String> userIds) {
// Invites specified users to the current group.
// Returns true via listener on success, false otherwise.
}

/**
* Kick group members
* @param userIds List of user IDs
* @param config Group exit configuration
* @description Kicks specified users from the group and notifies the caller via listener callback.
*/
public void kickGroupMembers(List<String> userIds, QuitGroupConfig config) {
// Kicks specified users from the group (requires owner or admin permissions).
// Returns true via listener on success, false otherwise.
}

/**
* Update group info
* @param groupInfo Group info
* @description Updates basic group info (e.g., name, avatar, announcement) and notifies the caller via listener callback.
*/
public void updateGroupInfo(@NonNull GroupInfo groupInfo) {
// Updates basic group info.
// Returns true via listener on success, false otherwise.
}

/**
* Leave a group
* @param config Group exit configuration
* @description Leaves the current group and notifies the caller via listener callback.
*/
public void quitGroup(QuitGroupConfig config) {
// Leaves the current group (typically called when a user chooses to exit).
// Returns true via listener on success, false otherwise.
}

/**
* Disband a group
* @description Disbands the current group and notifies the caller via listener callback.
*/
public void dismissGroup() {
// Disbands the current group (requires owner permissions).
// Returns true via listener on success, false otherwise.
}
}

DataKey Descriptions

  • KEY_CREATE_GROUP: Identifies the data key for group creation, type: IRongCoreEnum.CoreErrorCode.
  • KEY_INVITE_USERS_TO_GROUP: Identifies the data key for inviting users to a group, type: Boolean.
  • KEY_KICK_GROUP_MEMBERS: Identifies the data key for kicking group members, type: Boolean.
  • KEY_UPDATE_GROUP_INFO: Identifies the data key for updating group info, type: Boolean.
  • KEY_QUIT_GROUP: Identifies the data key for leaving a group, type: Boolean.
  • KEY_DISMISS_GROUP: Identifies the data key for disbanding a group, type: Boolean.

GroupMembersFullHandler

GroupMembersFullHandler is used to fetch all member information of a group at once, including fetching by role. It notifies external classes of member info retrieval status via data change and error callbacks.

public class GroupMembersFullHandler extends MultiDataHandler {  

// DataKey for fetching all group members by role
public static final DataKey<List<GroupMemberInfo>> KEY_GET_ALL_GROUP_MEMBERS_BY_ROLES =