服务问题中的Android线程

Posted

技术标签:

【中文标题】服务问题中的Android线程【英文标题】:Android thread in service issue 【发布时间】:2011-07-30 15:45:31 【问题描述】:

我正在运行一个远程服务,其中我正在生成一个新线程以继续轮询通过套接字传入的消息,然后每隔一段时间我想停止套接字并稍后重新启动...停止工作正常(stopUARTConnection( )) 但重新启动(startUARTConnection) 不会再次导致 while 循环。有人可以告诉我有什么问题吗?

public class BackgroundService extends Service

ServerSocket server = null;
Socket socketClient = null;
InputStream is = null;
BufferedReader br = null;
char[] buff = null;
boolean threadRunning = true;

private static final String TAG = BackgroundService.class.getSimpleName();
private Thread socketThread = null;
int temp = 0;

@Override
public IBinder onBind(Intent intent) 
    if (BackgroundService.class.getName().equals(intent.getAction())) 
        Log.d(TAG, "Bound by intent " + intent);
        return apiEndpoint;
     else 
        return null;
    


private final Object latestIncomingMessage = new Object();
private List<MessageCollectorListener> listeners = new ArrayList<MessageCollectorListener>();
private Message message = new Message(" ");

private MessageCollectorApi.Stub apiEndpoint = new MessageCollectorApi.Stub() 
    @Override
    public void removeListener(MessageCollectorListener listener) throws RemoteException 
        synchronized (listener) 
            listeners.remove(listener);
        
    

    @Override
    public Message getValue() throws RemoteException 
        synchronized (latestIncomingMessage) 
            return message;
        
    

    @Override
    public void addListener(MessageCollectorListener listener) throws RemoteException 
        synchronized (listener) 
            listeners.add(listener);
        
    

    @Override
    public void startBroadCastConn() throws RemoteException 
        try 
            startUARTConnection();
         catch (IOException e) 
            Log.d("B Service", "Stop UART CONNECTION");
        

    

    @Override
    public void stopBroadCastConn() throws RemoteException 
        try 
            stopUARTConnection();
         catch (IOException e) 
            Log.d("B Service", "Stop UART CONNECTION");
                   
    
;

public boolean createSocket(int port) 
    try
        server = new ServerSocket(port);
     catch (IOException e) 
        return false;
    
    return true;


public boolean listenSocket()
    try
        socketClient = server.accept();
     catch (IOException e) 
        return false;
    
    return true;


@Override
public void onCreate() 
    super.onCreate();
    socketThread = new Thread()
        @Override
        public void run() 
            while(threadRunning)
                boolean socketCreated = createSocket(8080);
                boolean socketListen = listenSocket();
                if(socketListen == true && socketCreated == true)
                    //To add code for processing data..
                    threadRunning = true;
                
                try 
                    recycle();
                 catch (IOException e) 
                    //e.printStackTrace();
                
            
           
    ;
    socketThread.start();

public void stopUARTConnection() throws IOException
    recycle();
    threadRunning = false;


public void startUARTConnection() throws IOException
    recycle();
    threadRunning = true;


private void recycle() throws IOException
    if(socketClient != null)
        socketClient.close();
        socketClient = null;
       
    if(is != null)
        is.close();
    if(server != null)
        server.close();
        server = null;
    


@Override
public void onDestroy() 
    super.onDestroy();
    try 
        recycle();
     catch (IOException e) 
        Log.d("B Service", "Failed to recycle all values");
    
    socketThread = null;

【问题讨论】:

【参考方案1】:

当您调用 stopUARTConnection 时,您正在设置 threadRunning=false...此时,您的 while 循环正在退出...在 startUARTConnection 中,您将 threadRunning 设置为 true,但您没有重新启动线程。

正如@Marvin 指出的,you can't just call start on the thread object,您需要重新创建它。

【讨论】:

-1 因为您无法启动已经启动过一次的线程。第二次调用 startUARTConnection 时会抛出 IllegalThreadStateException。 听说我必须在重新开始之前销毁该线程..我们可以通过分配 thread = null 来销毁吗? ??? @Arun Abraham:请参阅 Marvin 的回复。您不必销毁线程(它会退出),您可以在现有引用上创建一个新的 @MarvinLabs:感谢您的指点。我不知道您无法重新启动线程对象,我假设它进入退出状态就可以了。我想这不是我需要做的事情,通常如果我启动一个线程,我不希望在应用程序准备退出之前将其关闭。 始终明确关闭您启动的线程,否则它们将继续在后台运行,您会泄漏内存...【参考方案2】:

您只创建一次线程。因此,循环只运行一次,直到被指示退出。

public void startUARTConnection() throws IOException
    recycle();
    socketThread = new SocketThread();
    socketThread.start();


public void stopUARTConnection() throws IOException
    recycle();
    socketThread = null;


private class SocketThread extends Thread 
    @Override
    public void run() 
        // Loop until socketThread is assigned something else 
        // (a new Thread instance or simply null)
        while (socketThread==this)
            boolean socketCreated = createSocket(8080);
            boolean socketListen = listenSocket();
            if(socketListen == true && socketCreated == true)
                // To add code for processing data..
            
            try 
                recycle();
             catch (IOException e) 
                //e.printStackTrace();
            
        
       
;

【讨论】:

hmmm...看起来不错...但是我们是否应该在重新开始之前销毁线程...我应该将线程分配给 null 来执行它吗? socketThread==this 会检测到你创建了一个新的 SocketThread,然后旧的 Thread 会退出。如果您需要确保没有同时运行 2 个线程,则需要基于 join() 实施检查。 嘿....非常感谢...您的解决方案是正确的..非常感谢..对线程真的很陌生...:) @Arun Abraham:如果马文解决了你的问题,你真的应该接受这个答案......【参考方案3】:

我认为最好使用 TimerTask 而不是 thread/while 和 ConditionVariable 而不是布尔变量 threadRunning

【讨论】:

以上是关于服务问题中的Android线程的主要内容,如果未能解决你的问题,请参考以下文章

UI线程或背景中的Android音乐播放器

Android中的线程实现不起作用

浅谈Android和java中的多线程下载

Android中的线程或服务中的蓝牙通信?

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

在哪里停止/销毁 Android Service 类中的线程?