源码分析Mms--ConversationList短信主界面会话列表

项目总结之关于系统通讯录的操作 最近做了个项目, 主要是基于系统通讯录操作的, 大概的功能说下把, 联系人列表, 通话记录列表, 联系人名片, 新增群组与智能分组, 联系人收藏列表, 短信群发, 导航电话与位置分享功能, 自定义拨号键盘, 通讯录备份, 换肤功能. 其实做完这个项目后, 我觉得我对通讯录的关键的那几张表有了更深入的了解, 之前我并没有接触过类似的项目, 在做这个项目的时候也做得很蛋疼, 因为对表的不熟悉 阅读详情

ConversationList是短信很重要的一个Activity,单布局也很简单,就是一个ListActivity。

layout.conversation_list_screen

<RelativeLayout  xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"  >

    <ListView android:id="@android:id/list"
        style="?android:attr/listViewWhiteStyle"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/banner_sms_promo"
        android:drawSelectorOnTop="false"
        android:scrollbarStyle="insideOverlay"
        android:background="@android:color/white"
        android:cacheColorHint="@android:color/white"
        android:fadingEdgeLength="16dip" />

    <TextView android:id="@+id/empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="@string/loading_conversations"
        android:textAppearance="?android:attr/textAppearanceMedium" />

     <include layout="@layout/banner_sms_promo" />
</RelativeLayout>

layout.banner_sms_promp,貌似是给运营商做的需求,原生代码不确定有没有,当不是默认短信时,显示此View,点击可以设置为默认短信,这么一个功能,显示在ListView的上面。按照常规的写法,在RelativeLayout中,banner_sms_promo应该写在ListView之前的。

此empty TextView当ListView没有数据时显示的,还有一个功能是当加载列表比较慢的情况下,显示正在加载,但这个会话多的时候会覆盖在内容列表上面,后来的项目有提这个bug,后来改了就不提示正在加载了。


/**
 * This activity provides a list view of existing conversations.
 */
public class ConversationList extends ListActivity implements DraftCache.OnDraftChangedListener {<span style="font-family: Arial, Helvetica, sans-serif;">...</span>
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.conversation_list_screen);

        mSmsPromoBannerView = findViewById(R.id.banner_sms_promo);

        mQueryHandler = new ThreadListQueryHandler(getContentResolver());//查询使用的Handler,经常使用

        ListView listView = getListView();
        listView.setOnCreateContextMenuListener(mConvListOnCreateContextMenuListener);//长按事件,弹出来的菜单,在ActionBar位置显示,比之前的,长按弹出菜单好用
        listView.setOnKeyListener(mThreadListKeyListener);
        listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
        listView.setMultiChoiceModeListener(new ModeCallback());

        // Tell the list view which view to display when the list is empty
        listView.setEmptyView(findViewById(R.id.empty));

        initListAdapter();

        setupActionBar();

        setTitle(R.string.app_label);

        mHandler = new Handler();
        mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        boolean checkedMessageLimits = mPrefs.getBoolean(CHECKED_MESSAGE_LIMITS, false);
        if (DEBUG) Log.v(TAG, "checkedMessageLimits: " + checkedMessageLimits);
        if (!checkedMessageLimits) {
            runOneTimeStorageLimitCheckForLegacyMessages();
        }

        if (savedInstanceState != null) {
            mSavedFirstVisiblePosition = savedInstanceState.getInt(LAST_LIST_POS,
                    AdapterView.INVALID_POSITION);
            mSavedFirstItemOffset = savedInstanceState.getInt(LAST_LIST_OFFSET, 0);
        } else {
            mSavedFirstVisiblePosition = AdapterView.INVALID_POSITION;
            mSavedFirstItemOffset = 0;
        }
    }
<pre name="code" class="java">private final class ThreadListQueryHandler extends ConversationQueryHandler {//重点掌握


    private final class ThreadListQueryHandler extends ConversationQueryHandler {
        public ThreadListQueryHandler(ContentResolver contentResolver) {
            super(contentResolver);
        }
        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
            switch (token) {
            case THREAD_LIST_QUERY_TOKEN:
                mListAdapter.changeCursor(cursor);
case UNREAD_THREADS_QUERY_TOKEN:
...break;
case HAVE_LOCKED_MESSAGES_TOKEN:
...break;

        @Override
        protected void onDeleteComplete(int token, Object cookie, int result) {
            super.onDeleteComplete(token, cookie, result);
            switch (token) {
            case DELETE_CONVERSATION_TOKEN:
...break;
case DELETE_OBSOLETE_THREADS_TOKEN:
… break;
}

======================================================================
public static class ConversationQueryHandler extends AsyncQueryHandler {…}
===========================================================================
package android.content;
/**
 * A helper class to help make handling asynchronous {@link ContentResolver}
 * queries easier.
 */
public abstract class AsyncQueryHandler extends Handler {
    private static final int EVENT_ARG_QUERY = 1;
    private static final int EVENT_ARG_INSERT = 2;
    private static final int EVENT_ARG_UPDATE = 3;
    private static final int EVENT_ARG_DELETE = 4;

//使用弱引用避免对象一直被引用而无法释放,导致内存泄露,WeakReference GC可以自动回收
    /* package */ final WeakReference<ContentResolver> mResolver;

    private static Looper sLooper = null;

    private Handler mWorkerThreadHandler;

//查询等操作需要的参数
    protected static final class WorkerArgs {
        public Uri uri;
        public Handler handler;
        public String[] projection;
        public String selection;
        public String[] selectionArgs;
        public String orderBy;
        public Object result;
        public Object cookie;
        public ContentValues values;
}

//使用Handler去查询等耗时的操作
    protected class WorkerHandler extends Handler {
        public WorkerHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
//mResolver.get()使用WeakReference
            final ContentResolver resolver = mResolver.get();
//如果mResolver.get()为空,表示对象已经回收了,此短信例子中对应的ConversationList Activity
            if (resolver == null) return;

            WorkerArgs args = (WorkerArgs) msg.obj;

            int token = msg.what;
            int event = msg.arg1;

            switch (event) {
                case EVENT_ARG_QUERY:
                    Cursor cursor;
                    try {
                        cursor = resolver.query(args.uri, args.projection,
                                args.selection, args.selectionArgs,
                                args.orderBy);
                        // Calling getCount() causes the cursor window to be filled,
                        // which will make the first access on the main thread a lot faster.
                        if (cursor != null) {
                            cursor.getCount();
                        }
                    } catch (Exception e) {
                        Log.w(TAG, "Exception thrown during handling EVENT_ARG_QUERY", e);
                        cursor = null;
                    }

                    args.result = cursor;
                    break;

                case EVENT_ARG_INSERT:
                    args.result = resolver.insert(args.uri, args.values);
                    break;

                case EVENT_ARG_UPDATE:
                    args.result = resolver.update(args.uri, args.values, args.selection,
                            args.selectionArgs);
                    break;

                case EVENT_ARG_DELETE:
                    args.result = resolver.delete(args.uri, args.selection, args.selectionArgs);
                    break;
            }

            // passing the original token value back to the caller
            // on top of the event values in arg1.
            Message reply = args.handler.obtainMessage(token);
            reply.obj = args;
            reply.arg1 = msg.arg1;

            if (localLOGV) {
                Log.d(TAG, "WorkerHandler.handleMsg: msg.arg1=" + msg.arg1
                        + ", reply.what=" + reply.what);
            }

            reply.sendToTarget();//返回给自己AsyncQueryHandler处理,因为StartQuery等方法WorkerArgs.handler传的是this
        }
    }

//构造函数
    public AsyncQueryHandler(ContentResolver cr) {
        super();
        mResolver = new WeakReference<ContentResolver>(cr);
        synchronized (AsyncQueryHandler.class) {
            if (sLooper == null) {
                HandlerThread thread = new HandlerThread("AsyncQueryWorker");
                thread.start();
//使用HandlerThread的Looper而不使用主线程的Looper就不会阻塞主线程
                sLooper = thread.getLooper();
            }
        }
        mWorkerThreadHandler = createHandler(sLooper);
    }

//暴露给外部调用
    public void startQuery(int token, Object cookie, Uri uri,
            String[] projection, String selection, String[] selectionArgs,
            String orderBy) {
        // Use the token as what so cancelOperations works properly
        Message msg = mWorkerThreadHandler.obtainMessage(token);
        msg.arg1 = EVENT_ARG_QUERY;

        WorkerArgs args = new WorkerArgs();
        args.handler = this;//最后WorkerHandler处理的结果还是给自己的HandleMessage()处理
        args.uri = uri;
        args.projection = projection;
        args.selection = selection;
        args.selectionArgs = selectionArgs;
        args.orderBy = orderBy;
        args.cookie = cookie;
        msg.obj = args;
//最终给WorkerHandler,用ContentResolver查询等操作。
//这里为什么不直接查询完再调用onQueryComplete()方法,反而又加多一个WorkerHandler那么麻烦呢?如果这样,必然会阻塞主线程,因为外部调用此StartQuery的handler(即该AsyncQueryHandler的子类实例)是在主线程中执行的,而WorkerHandler使用的HanderThread就不会阻塞主线程。
        mWorkerThreadHandler.sendMessage(msg);
    }

    public final void cancelOperation(int token) {
        mWorkerThreadHandler.removeMessages(token);
}

    public final void startInsert(int token, Object cookie, Uri uri,
            ContentValues initialValues) {
        // Use the token as what so cancelOperations works properly
        Message msg = mWorkerThreadHandler.obtainMessage(token);
        msg.arg1 = EVENT_ARG_INSERT;

        WorkerArgs args = new WorkerArgs();
...
        mWorkerThreadHandler.sendMessage(msg);
    }

    public final void startUpdate(int token, Object cookie, Uri uri,
            ContentValues values, String selection, String[] selectionArgs) {...}

    public final void startDelete(int token, Object cookie, Uri uri,
            String selection, String[] selectionArgs) {...}

    protected Handler createHandler(Looper looper) {
        return new WorkerHandler(looper);
    }

protected void onQueryComplete(int token, Object cookie, Cursor cursor) {// Empty}
protected void onInsertComplete(int token, Object cookie, Uri uri) {// Empty}
protected void onUpdateComplete(int token, Object cookie, int result) {// Empty}
protected void onDeleteComplete(int token, Object cookie, int result) {// Empty}
    @Override
    public void handleMessage(Message msg) {
        WorkerArgs args = (WorkerArgs) msg.obj;

        if (localLOGV) {
            Log.d(TAG, "AsyncQueryHandler.handleMessage: msg.what=" + msg.what
                    + ", msg.arg1=" + msg.arg1);
        }

        int token = msg.what;
        int event = msg.arg1;

        // pass token back to caller on each callback.
        switch (event) {
            case EVENT_ARG_QUERY:
//回调给子类处理,父类AsynQueryHandler的onQueryComplete是空方法,把结果传回给子类处理想要的逻辑
                onQueryComplete(token, args.cookie, (Cursor) args.result);
                break;

            case EVENT_ARG_INSERT:
                onInsertComplete(token, args.cookie, (Uri) args.result);
                break;

            case EVENT_ARG_UPDATE:
                onUpdateComplete(token, args.cookie, (Integer) args.result);
                break;

            case EVENT_ARG_DELETE:
                onDeleteComplete(token, args.cookie, (Integer) args.result);
                break;
        }
    }
}

======================================================================
package android.os;

/**
 * Handy class for starting a new thread that has a looper. The looper can then be 
 * used to create handler classes. Note that start() must still be called.
 */
//HandlerThread 是一个Thread不是Handler
public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;//使用自己的Looper而不是主线程的

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    
    /**
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
    }

    public void run() {
        mTid = Process.myTid();
        Looper.prepare();//不能漏,Looper.loop ()前先调用一次,prepare有new Looper。
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
    
    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason is isAlive() returns false, this method will return null. If this thread 
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
    
    /**
     * Ask the currently running looper to quit.  If the thread has not
     * been started or has finished (that is if {@link #getLooper} returns
     * null), then false is returned.  Otherwise the looper is asked to
     * quit and true is returned.
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    
    /**
     * Returns the identifier of this thread. See Process.myTid().
     */
    public int getThreadId() {
        return mTid;
    }
}

android.os.Looper 略



}//ConversationList class end




融云集成(单聊+会话列表) 根据融云官方提供的SDK下载下来,然后根据融云官方提供的文档进行导包操作等,接下来开始咱们代码实现单聊的旅途:在清单文件里加入: <provider android:name="android.support.v4.content.FileProvider" //自己的包名.FileProvider android:autho 阅读详情

相关推荐

Android 系统中同时删除多条SMS的具体实现

昨天,遇到了一个同时删除多条记录的问题,在android系统中删除操作过慢导致了,导致用户体验不佳的现象。      该问题一直都没有很好的解决,现在将整体的解决方案记录一下。    一。AsyncQueryHander的具体实现       通过代码我们看到这里是通过一个AsyncQueryHander实现的删除操作,该handler的具体实现 public sta

底层码农 1544

短信ui分析--会话列表

会话列表 1、前言      短信会话列表,对于一位使用android智能机的同胞来说,这个界面肯定不陌生。它就是我们进入短信应用看到的第一个界面,它也是短信UI中最重要的组成部分之一,它给用户提供了哪些功能,这里简单概括:       一、显示短信话,“会话”是什么含义了?简单的讲,张三给李四发短信,              张三和李四之间的这种关系就是一个会话;       二、新

ceko_wu的专栏 5606

AI赋能工业自动化:传感器大数据实战

工业自动化中AI与传感器大数据的结合,显著提升了生产效率与可靠性。关键技术包括实时数据处理、边缘计算和数字孪生,未来将进一步向自主决策系统演进。

AFAGA_x的博客 413

Mms conversation部分学习总结

一、代码结构 Conversation中整体结构主要包括com.Android.mms.data和com.android.mms.ui,如名字所示,大概就是数据处理部分和UI部分。数据部分主要是获取/缓存联系人信息、获取/缓存会话信息等。ui部分主要是convesation 的列表功能实现 ConversationList类是程序的主activity,派生于ListActivity,就是

zhaoweixing1989的专栏 4034

Mac OS X 工具技巧:一文搞定个性化命令行窗口(iTerm2 + zsh + oh-my-zsh 配置Powerline风格)

本不想写这篇文章的,因为在Linux下已经配置过很多次,想着mac应该找篇文章一次就搞定了,结果还是踩坑,看了很多文章,不是某一点没不清楚,就是截图有问题或者命令有问题,官网又难得找等等……花了3个多小时才搞定,所以,还是来总结一篇文章就能够搞定的教程。 为什么要用zsh?用了这么多年的bash,不能说bash不好,不过当我用了zsh后发现,什么叫更好用。 配置过程稍微有点繁琐,但是你看过效果...

mickjoust的技术小屋 1万+

TC397 EB配置ADC软件触发:从零实现周期采样与中断处理

本文详细介绍了如何在Infineon AURIX TC397芯片上使用EB Tresos工具配置ADC软件触发,实现周期采样与中断处理。通过硬件连接、EB模块配置、代码初始化及数据处理的全流程解析,帮助开发者快速掌握ADC软件触发技术,提升嵌入式系统开发效率。

root9的博客 231

AsyncQueryHandler

android.content.AsyncQueryHandler继续于android.os.Handler 虽然Handler自己是没另开新线程,但是AsyncQueryHandler自己却是另开了一个线程来进行数据的查询     实例1 AsyncQueryHandler -->同步更新  class QueryHandler extends AsyncQueryHandler {

Robin Hu的专栏 6040

Sigrity SPEED2000 General SI Simulation模式如何进行信号仿真分析操作指导-DDR

本例是几个简单的板载DDR颗粒的结构,本例中使用General SI Simulation模式仿真DDR信号,结构拓扑如下,Addcmd,clk,cke都是T拓扑。Sigrity SPEED2000 General SI Simulation模式可以对信号进行仿真分析,仿真将电源视为理想电源,以下图为例进行说明。DQS的接收端模型设置为DQS_34_ODT60_1333。模式如何进行信号仿真分析操作指导-DDR。附带驱动和接收端的IBIS模型。

weixin_54787054的博客 510

Handler Looper的结合

[size=medium]/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with t...

异读心寒 224

AWS DevOps Agent 完全指南

AI 驱动的 SRE 队友,7×24 自主调查告警、定位根因、生成修复方案、预防未来故障。

探索云原生与智能化驱动下的安全运维新范式。关注DevSecOps、可观测性、AIOps等前沿领域,与您共赴技术前沿。 381

Sigrity Power DC Resitance Network Model Generation模式生成电阻SPICE模型操作指导

Sigrity Power DC Resitance Network Model Generation模式是用于提取负载每个pin电阻SPICE模型的,结果以spice网表形式展现,仍然以Motherboard.spd为例进行说明。目的是模拟实际情况,via的孔壁电镀1mil,中间是空心的,让via不完全被填充金属成为实心via。Upper/lower Tolerance:上下公差,设置为5%,也就是压降允许的范围。P/F Mode:通过/失败模式,选择Worst,最差的情况。

weixin_54787054的博客 416

解析短信发送和接收流程

MMS 应用主要源码汇总及简要说明 主动发生短信流程分析 进入短信回话列表界面: 短信应用包路径:packages/app/Mms 打开AndroidMainfest.xml 配置文件,入口就是ConversationList.java "新建短信"按钮,调用createNewMessage函数 发送短信,调用confirmSendMessageIfNeeded 方法:

Utopia 2370

基于深度学习的X光安检危险品检测系统(YOLOv8 + UI界面 + 数据集)

随着全球安全形势的变化,机场、车站、地铁等场所的安检工作日益重要。X光安检系统已经成为现代公共安全领域中不可或缺的部分,能够有效地检测物品的内部结构,识别潜在的危险品。然而,传统的X光图像分析方法仍然依赖人工操作,检测效率较低,并且易受到人为因素的影响。近年来,深度学习技术的应用在图像分析领域取得了显著的突破,特别是在目标检测任务中,YOLO(You Only Look Once)模型因其高效性和精度,成为了许多目标检测任务的首选模型。

YOLO 1059

android开发笔记之ContentProvider使用样例一

参考资料: 1.

hfreeman2008的专栏 1794

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

通过AsyncQueryHandler异步对数据库进行增删查操作

AsyncQueryHandler的作用异步对数据库进行增加、删除、更新、查询操作。避免在主线程中直接调用数据库相关操作导致的ANR异常。AsyncQueryHandler使用步骤 自定义继承AsyncQueryHandler的子类,实现相关的方法。 void onDeleteComplete(int token, Object cookie, int result)

a day a better 1104

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Android异步处理技术

《Android 高级进阶》读书笔记 Android中,异步处理技术有很多种,常见的有Thread、AsyncTask、Handler&Looper、Executors等,在实际项目中,我们需要根据具体业务需求进行选择、一个完整的异步处理技术继承树如下: 1. Thread线程是Java语言的一个概念,它是实际执行任务的基本单元,创建线程有两种方法。 继承Thread类并重写run方法,语句如

论一个程序员的自我修养 760

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Handler机制的一些理解

// Handler允许你去发送/处理消息message和Runnable对象。每个handler对象对应一个 // Thread和与这个Thread对应的MessageQueue。当你创建一个Handler的时候,它就和 // Thread以及相对应的MessageQueue绑定在一起。从绑定成功的那一刻开始,Handler // 就可以向MessageQueue中发送消息和Runnable对象

752

Mms模块ConversationList流程分析

一 代码位置结构及相关类 ..\packages\apps\Mms\src\com\android\mms\ui:存放界面显示相关的类 ..\packages\apps\Mms\src\com\android\mms\data:存放界面显示需要的数据相关的类   主要的类: ConversationList:信息对话界面——>ListActivity ConversationListA

cuishiying的专栏 2378

信息首页ConversationList

ConversationList这个Activity绘制的就是进入信息首页界面所看到的信息列表。它继承自ListActivity。ListActivity是用于显示一个列表界面,它包含一个可以与不同数据源进行绑定的ListView视图组件,其id为“@android:id/list”。同时包含一个ListAdapter对象,就是 “绑定”操作的实施者。ListView比较典型的可以与数组或者数据库

ukiliu8793的专栏 1341

融云集成4--会话列表,会话界面的集成

参考资料:http://www.rongcloud.cn/docs/android.html#配置会话列表一.静态注册 1.在需要显示会话列表的Activity布局文件中,直接引用: 注意 android:name 固定为融云的 ConversationListFragment。 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmln

Rose 1万+

加载ConversationListActivity以及延迟的使用

1. 加载会话列表分两步加载。 且第1步和第2步之间有些延迟,便于第1步的结果及时在ListView中显示出来。 mHandler.postDelayed(new LoadThreadsExtra(), 200); 第1步。从threads表中查找出数据,封装成TxrjThread,构建ConversationAdapter,在ListView中显示出来。 第2步。从sms, canoni...

weixin_33757911的博客 180

融云即时通讯

1、单聊功能 下载最新sdk.导入IMKit、IMLib库 打开 IMLib Module 的 AndroidManifest.xml 文件,把 meta-data RONG_CLOUD_APP_KEY 的值修改为自己的 AppKey 初始化, public class App extends Application { @Override public void

woshixiaoning的专栏 2741

集成融云 即时通讯总结

应用加入及时通讯,自己写,需要需要很多资源,继承第三方是面前比较快捷的办法,第三方有融云,环信,网易云信  最近集成融云的sdk, 安装官方说明引入jar包 RongIM.class 为融云消息启动类 RongCloudEvent.class为消息推送类 如果需要消息推送,这两个都要初始化: 在Application类中初始化 /** * 初始化融云sdk *

xiaobijia的专栏 1万+

Android融云会话及会话列表的实现

一、服务端好友关系列表在自己的服务器上已部署完成,并且实现了与融云服务器的交互 二、通过App发送消息到自己的服务端,得到App与自己服务器交互的token以及App与融云服务器交互的token 1、App自己服务器token(令牌),用于App与自己服务器交互 2、App融云服务器token(令牌),用户App与融云服务器交互 三、在融云官方网站上下载IMKit、IMLib,并进行添加配

CDUT100的专栏 1万+

Android常用应用市场包名

常用应用市场包名: com.tencent.android.qqdownloader 腾讯应用宝 com.dragon.android.pandaspace 91手机助手 com.hiapk.marketpho 安智应用商店 com.yingyonghui.market 应用汇 com.tencent.qqpimsecure QQ手机管家 com.mappn.gfan 机锋应用市场 ...

csdnwr的博客 4041
上一篇: 源码分析Mms--AndroidManifest.xml分析
下一篇: android源码分析--MMS--ComposeMessageActivity
djyjava
博客等级 码龄19年 3粉丝 10原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值