一、问题描述
最近在做基于环信的即时通讯项目,聊天界面那用的是环信的 EaseUI 的 EaseChatFragment,但是一点击发送按钮就崩溃
来看看错误
什么个情况,NullPointerException?
二、问题分析
那就看看 EasePreferenceManager 类 19 行是什么鬼
package com.hyphenate.easeui.model;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import com.hyphenate.easeui.EaseUI;
import java.util.Set;
public class EasePreferenceManager {
private SharedPreferences.Editor editor;
private SharedPreferences mSharedPreferences;
private static final String KEY_AT_GROUPS = "AT_GROUPS";
@SuppressLint("CommitPrefEdits")
private EasePreferenceManager(){
//就是下面这一行出问题
mSharedPreferences = EaseUI.getInstance().getContext().getSharedPreferences("EM_SP_AT_MESSAGE", Context.MODE_PRIVATE);
editor = mSharedPreferences.edit();
}
private static EasePreferenceManager instance;
public synchronized static EasePreferenceManager getInstance(){
if(instance == null){
instance = new EasePreferenceManager();
}
return instance;
}
public void setAtMeGroups(Set<String> groups) {
editor.remove(KEY_AT_GROUPS);
editor.putStringSet(KEY_AT_GROUPS, groups);
editor.apply();
}
public Set<String> getAtMeGroups(){
return mSharedPreferences.getStringSet(KEY_AT_GROUPS, null);
}
}
getContext() 是 null ? getConext() 是什么
/**
* application context
*/
private Context appContext = null;
public Context getContext(){
return appContext;
}
原来是 Application 的 Context,看看在哪初始化的
/**
*this function will initialize the SDK and easeUI kit
*
* @return boolean true if caller can continue to call SDK related APIs after calling onInit, otherwise false.
*
* @param context
* @param options use default if options is null
* @return
*/
public synchronized boolean init(Context context, EMOptions options){
if(sdkInited){
return true;
}
appContext = context;
......
}
原来是在 EaseUI 的 init 方法中,再看看应用的 Application ,呀,只是用 EMClient 的 init 初始化,Context 给了 EMClient,却没给 EaseUI
EMClient.getInstance().init(Context context, EMOptions options);
三、问题解决
想要用 EaseUI 的聊天界面的话得用 EaseUI 调用 init 去初始化
/**
*this function will initialize the SDK and easeUI kit
*
* @return boolean true if caller can continue to call SDK related APIs after calling onInit, otherwise false.
*
* @param context
* @param options use default if options is null
* @return
*/
public synchronized boolean init(Context context, EMOptions options){
if(sdkInited){
return true;
}
appContext = context;
int pid = android.os.Process.myPid();
String processAppName = getAppName(pid);
Log.d(TAG, "process app name : " + processAppName);
// if there is application has remote service, application:onCreate() maybe called twice
// this check is to make sure SDK will initialized only once
// return if process name is not application's name since the package name is the default process name
if (processAppName == null || !processAppName.equalsIgnoreCase(appContext.getPackageName())) {
Log.e(TAG, "enter the service process!");
return false;
}
if(options == null){
EMClient.getInstance().init(context, initChatOptions());
}else{
EMClient.getInstance().init(context, options);
}
initNotifier();
registerMessageListener();
if(settingsProvider == null){
settingsProvider = new DefaultSettingsProvider();
}
sdkInited = true;
return true;
}
EaseUI 的 init 方法里有调用的
EMClient.getInstance().init(Context context, EMOptions options);
所以想用 EaseUI 库得在调用 EaseUI 的 init 方法去初始化,这样 getContext 才不是 null 的
EaseUI.getInstance().init(Context context, EMOptions options);
再运行一次,消息能发出去了,可以愉快地聊天了
官网也有说,官方文档 EaseUI 初始化,我是后来才集成 EaseUI 的,没先去看 EaseUI 部分的文档,也说明看官方文档是很重要的事情。