首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

環信 SDK 實戰:邀請信息列表頁面開發——複雜狀態適配器與廣播驅動刷新

     編輯:Java 綜合教學

前言:邀請列表的複雜性在於「多類型、多狀態、雙向操作」

好友邀請、群邀請、群申請,每類又有「新邀請、已接受、已拒絕、對方接受、對方拒絕」等多種狀態。UI 需動態顯示原因、顯示/隱藏接受拒絕按鈕,點擊後需調用環信 API、更新本地數據庫、刷新列表。本文完整拆解 InviteAdapter 狀態機設計、OnInviteListener 回調鏈、LocalBroadcastManager 跨組件刷新機制。

頁面佈局:標題欄 + ListView

<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.hyphenate.easeui.widget.EaseTitleBar
        app:titleBarTitle="邀請信息列表"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ListView
        android:id="@+id/lv_invite"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

適配器架構:BaseAdapter + ViewHolder + 狀態機

public class InviteAdapter extends BaseAdapter {
    private final Context context;
    private final List<InvationInfo> data = new ArrayList<>();
    private final OnInviteListener listener;

    public InviteAdapter(Context context, OnInviteListener listener) { ... }

    public void refresh(List<InvationInfo> newData) {
        if (newData != null) {
            data.clear();
            data.addAll(newData);
            notifyDataSetChanged();
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = View.inflate(context, R.layout.item_invite, null);
            holder.name = convertView.findViewById(R.id.tv_invite_name);
            holder.reason = convertView.findViewById(R.id.tv_invite_reason);
            holder.accept = convertView.findViewById(R.id.bt_invite_accept);
            holder.reject = convertView.findViewById(R.id.bt_invite_reject);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        InvationInfo info = data.get(position);
        bindView(holder, info); // 核心:狀態機綁定邏輯
        return convertView;
    }
    // ...
}

核心邏輯:bindView 狀態機(200+ 行的精華)

InvationInfo 區分 聯系人邀請(user ≠ null)與 群邀請/申請(group ≠ null),每類有獨立狀態枚舉:

聯系人邀請狀態機

狀態顯示原因按鈕操作回調
NEW_INVITE理由或「添加好友」顯示接受/拒絕onAccept / onReject
INVITE_ACCEPT理由或「接受邀請」隱藏無
INVITE_ACCEPT_BY_PEER理由或「邀請被接受」隱藏無

群邀請/申請狀態機(更複雜)

狀態常量場景顯示文本按鈕/回調
NEW_GROUP_INVITE收到群邀請「您收到了群邀請」接受/拒絕 → onInviteAccept/Reject
NEW_GROUP_APPLICATION收到入群申請「您收到了群申請」接受/拒絕 → onApplicationAccept/Reject
GROUP_INVITE_ACCEPTED我的邀請被接受「您的群邀請已被接收」隱藏
GROUP_APPLICATION_ACCEPTED我的申請被接受「您的群申請已被接受」隱藏
GROUP_INVITE_DECLINED我的邀請被拒絕「您的群邀請已被拒絕」隱藏
GROUP_APPLICATION_DECLINED我的申請被拒絕「您的群申請已被拒絕」隱藏
GROUP_ACCEPT_INVITE我接受了邀請「你接受了群邀請」隱藏
GROUP_REJECT_INVITE我拒絕了邀請「您拒絕了群邀請」隱藏
GROUP_ACCEPT_APPLICATION我批准了申請「您批准了群申請」隱藏
GROUP_REJECT_APPLICATION我拒絕了申請「您拒絕了群申請」隱藏

按鈕點擊綁定(關鍵:使用 final 變量捕獲當前 info)

holder.accept.setOnClickListener(v -> listener.onAccept(info));
holder.reject.setOnClickListener(v -> listener.onReject(info));
// 群邀請按鈕綁定對應回調...
// 注意:Java 7 需用 final InvationInfo finalInfo = info; 匿名內部類捕獲

回調接口:OnInviteListener(6 種操作)

public interface OnInviteListener {
    // 聯系人
    void onAccept(InvationInfo info);
    void onReject(InvationInfo info);
    // 群邀請
    void onInviteAccept(InvationInfo info);
    void onInviteReject(InvationInfo info);
    // 群申請
    void onApplicationAccept(InvationInfo info);
    void onApplicationReject(InvationInfo info);
}

Activity 實現:異步線程池 + 環信 API + 本地 DB + UI 刷新

private final OnInviteListener inviteListener = new OnInviteListener() {
    @Override
    public void onAccept(final InvationInfo info) {
        Model.getInstance().getGlobalThreadPool().execute(() -> {
            try {
                // 1. 調用環信服務端接受好友邀請
                EMClient.getInstance().contactManager().acceptInvitation(info.getUser().getHxid());
                // 2. 更新本地數據庫狀態
                Model.getInstance().getDbManager().getInviteTableDao()
                    .updateInvitationStatus(InvitationStatus.INVITE_ACCEPT, info.getUser().getHxid());
                // 3. UI 線程刷新
                runOnUiThread(() -> {
                    Toast.makeText(this, "接受了邀請", Toast.LENGTH_SHORT).show();
                    refresh(); // 重新查詢 DB 並 adapter.refresh()
                });
            } catch (HyphenateException e) {
                runOnUiThread(() -> Toast.makeText(this, "接受失敗", Toast.LENGTH_SHORT).show());
            }
        });
    }
    // 其他 5 種回調結構完全一致...
    // 群邀請用 groupManager().acceptInvitation/declineInvitation
    // 群申請用 groupManager().acceptApplication/declineApplication
    // 狀態更新為對應 GROUP_* 枚舉
};

跨組件刷新:LocalBroadcastManager

// Activity onCreate 註冊
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
lbm.registerReceiver(inviteChangedReceiver, 
    new IntentFilter(Constant.CONTACT_INVITE_CHANGED));

private final BroadcastReceiver inviteChangedReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 收到邀請變化廣播(如收到新邀請推送、其他端操作同步)
        adapter.refresh(Model.getInstance().getDbManager().getInviteTableDao().getInvitations());
    }
};

// 發送廣播的時機(例如 ContactManager 的邀請監聽器中)
LocalBroadcastManager.getInstance(context).sendBroadcast(
    new Intent(Constant.CONTACT_INVITE_CHANGED));

總結:邀請列表的工程化模式

  1. 數據模型:InvationInfo 封裝 user/group、狀態枚舉、原因
  2. 適配器:BaseAdapter + ViewHolder + 狀態機綁定邏輯 集中在 bindView
  3. 回調接口:OnInviteListener 定義 6 種操作語義,Activity 實現異步執行鏈
  4. 執行鏈:線程池 → 環信 API → 本地 DB 更新 → UI 線程 Toast + refresh()
  5. 跨組件同步:LocalBroadcastManager 解耦推送接收/多端同步與 UI 刷新

這套模式可直接複用到「系統通知」、「好友動態」等列表頁,實現高內聚、低耦合、易維護的 IM 交互頁面開發。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved