单独线程中的 XMPP 连接 - 仍然被 Android 操作系统关闭?

Posted

技术标签:

【中文标题】单独线程中的 XMPP 连接 - 仍然被 Android 操作系统关闭?【英文标题】:XMPP Connection in seperate thread - Still gets closed by Android OS? 【发布时间】:2014-03-18 10:36:57 【问题描述】:

我有一个包含许多服务的应用程序(企业的交付应用程序),它连接到 XMPP 服务器以发布报告。它主要是出色地工作。但是,在通过(1/3G)连接时,连接时间过长并且操作系统会终止应用程序。让我烦恼的是,连接是由警报管理器启动的服务产生的,我正在使用 androidConnectionConfiguration (aSmack lib),它显然产生了一个单独的线程来连接以摆脱 NetworkOnMainUIException。然而,每隔一段时间,我的应用程序仍然会收到一个 sigabrt 信号 6。为什么会发生这种情况?我没有在 UI 上或附近做任何事情,并认为无论时间如何,Android 都会让它不理会,直到它完成或自行超时?还是我错了?

我还能做些什么来阻止这种情况发生吗?我不在乎 XMPP 是否已连接,因为它总是会在有能力时重试并发送,但我不能让应用程序崩溃。

编辑 我应该说我使用的是 aSmack 0.8.10 - 和 Openfire 3.9.1。但它们不是问题并且工作得非常好。只有在奇怪的情况下,连接时间过长而被 Android 杀死。

编辑 2 一些代码:

package com.goosesys.dta_pta_test.Singletons;

import org.jivesoftware.smack.AndroidConnectionConfiguration;
import org.jivesoftware.smack.ChatManagerListener;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.SmackAndroid;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;

import android.content.Context;

import com.google.gson.Gson;
import com.goosesys.dta_pta_test.MessageListenerService;
import com.goosesys.gooselib.Logging;
import com.goosesys.gooselib.Utilities.AppSettings;
import com.goosesys.gooselib.Utilities.Utility;

public class XmppConnector 

    private static XmppConnector instance;
    private static boolean isConnected = false;
    private static AndroidConnectionConfiguration acc;
    private static XMPPConnection xConnection;
    private static Context context;


    public static void init(Context contxt)
    
        if(instance == null)
        
            instance = new XmppConnector();
        

        context = contxt;
    

    public static XmppConnector getInstance()
    
        return instance;
    

    public static boolean connect() throws XMPPException
    
        if(isConnected)
            return true;

        SmackAndroid.init(context);
        acc = new AndroidConnectionConfiguration(AppSettings.XMPP_SERVER_HOST,
                AppSettings.XMPP_SERVER_PORT, "Smack");
        acc.setSecurityMode(SecurityMode.disabled);
        xConnection = new XMPPConnection(acc);

        xConnection.addConnectionListener(new ConnectionListener()
            @Override
            public void reconnectionSuccessful()
            
                Logging.Debug("XmppConnector", "...reconnected to XMPP Server");
            

            @Override
            public void reconnectionFailed(Exception e)
            
                Logging.Debug("XmppConnector", "...reconnection failed: " + e);
            

            @Override
            public void reconnectingIn(int seconds)
            
                Logging.Debug("XmppConnector", "...reconnecting in: " + seconds);
            

            @Override
            public void connectionClosedOnError(Exception e)
            
                Logging.Debug("XmppConnector", "...connection closed on error: " + e);
            

            @Override
            public void connectionClosed()
            
                Logging.Debug("XmppConnector", "...connection closed");
                               
        );

        xConnection.connect();
        if(xConnection.isConnected())
        
            isConnected = true;

            // LOGIN ONCE CONNECTED TO THE SERVER //
            xConnection.login(Utility.getAndroidID(context),
                    AppSettings.XMPP_KEYSTORE_PASSWORD);
            // CREATE CHAT MANAGER //
            xConnection.getChatManager().addChatListener(new ChatManagerListener()
                @Override
                public void chatCreated(final Chat chat, boolean createdLocally)
                
                    if(!createdLocally)
                        chat.addMessageListener(new MessageListenerService(context));
                
            );
        
        else
        
            isConnected = false;
        

        return isConnected;
    

    public static boolean sendMessage(String jsonObj)
    
        Message m = new Gson().fromJson(jsonObj, Message.class);
        if(m == null)
        
            Logging.Error("XmppConnector", "Message object is null.. Aborting");
            return false;
        

        if(isConnected)
        
            xConnection.sendPacket(m);
            return true;
        
        else
        
            return false;
        
    

以及启动它的小服务:

公共类 BGCollectorProc 扩展 IntentService 私有DatabaseHelper dbHelper;

public BGCollectorProc() 

    super("BGCollectorProc");       


@Override
public int onStartCommand(Intent intent, int flags, int startId)
   
    Logging.Debug("BGCollectorProc", "Spinning...");    
    //dbHelper = DatabaseHelper.getHelper(getApplicationContext());

    try
    
        // initialise the connection
        XmppConnector.init(this);
        // get the static reference
        XmppConnector.getInstance();
        // connect to the server
        if(XmppConnector.connect())
        
            Logging.Info("BGCollectorProc", "CONNECTED TO XMPP SERVER");
        
    
    catch(XMPPException e)
    
        e.printStackTrace();
    

    /*
    // Worker thread area //
    try 
        postDeliveries();
     catch (FileNotFoundException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    
    postGeoLogs();
    */

    return Service.START_NOT_STICKY;

干杯。

【问题讨论】:

这里真正有趣的是从 Android 日志中截取的相关内容。 Android 在需要时杀死进程。但是粘性服务会重新启动。 感谢我没有提供任何 logcat,但我之前得到的唯一输出是:libc - Fatal signal 6 (SIGABRT) at 0x000000149 (code=0), thread 24939 (ys. dta_pta_test) - 真的不认为这是相关的,因为它并没有太大的帮助。我的服务并不意味着一直旋转,所以它们设置为不粘,并通过 AlarmManager 每分钟重新启动一次。我现在想知道的是,我是否可以指定一个超时时间(略低于 Android 的 sigabrt 信号)来阻止应用程序被杀死? 【参考方案1】:

SIGABRT 通常意味着 dalvik 内部发生了致命的事情。杀死您的进程的不是 Android ActivityManager。由于 VM 故障,VM 会自行终止。通常会有更多关于故障的信息。也许您没有识别出与SIGABRT 相关的日志。至少我希望在日志中找到有关SIGABRT 原因的更多信息。

顺便说一句:拥有活动 XMPPConnection 的服务是粘性 Android 服务的理想候选者,只要 XMPPConnection 处于活动状态,该服务就应该运行。

【讨论】:

以上是关于单独线程中的 XMPP 连接 - 仍然被 Android 操作系统关闭?的主要内容,如果未能解决你的问题,请参考以下文章

我是不是必须为 smack xmpp 连接创建两个单独的类,一个用于后台侦听器,另一个用于前台侦听器?

是否可以在 Tomcat 服务器中使用 XMPP 模块?

XMPP 服务连接中断

Smack XMPP 连接状态,数据不正确

XMPP Openfire 连接被拒绝

XMPP框架下微信项目总结授权登陆/注销/注册