4

我的 Android 应用程序使用线程来侦听来自通过 USB 连接的 PC 的套接字连接。在 PC 打开连接后的某个时刻(响应某些用户驱动的事件),我想通过它发送一些数据。

public void onCreate(Bundle savedInstanceState) {

    // SNIP: stuff and nonsense

    connection = new Thread(new ServerThread());
    connection.start();
}

public boolean onTouchEvent(MotionEvent event) {

    // SNIP: decide what to do; create string 'coordString'

    Message coordMsg = coordHandler.obtainMessage();
    Bundle coordMsgData = new Bundle();
    coordMsgData.putString("coords", coordString);
    coordMsg.setData(coordMsgData);
    if(coordHandler!=null)
    {
        coordHandler.sendMessage(coordMsg);
    }

    return false;
}

public class ServerThread extends Thread
{   
    public void run() {

        this.setName("serverThread");

        Looper.prepare();

        coordHandler = new Handler()
        {
            @Override
            public void handleMessage(Message msg) {
                Log.v(INNER_TAG,"here");
            }
        };

        // SNIP: Connection logic here

        Looper.loop();
    }
}.

很长一段时间以来,我一直在挠头,想知道为什么INNER_TAG在触摸事件之后我从未在日志中看到 的值。我可以使用日志调试来跟踪coordHandler!=null块中的执行,但处理程序似乎从未触发。

然后它让我印象深刻:完成连接后线程可能正在退出。啊!不太确定我之前认为发生了什么,但我会将其归咎于一种Loop正在做一些神奇事情的信念。

所以我的问题是:我怎样才能保持我的线程运行?关于线程的官方Android 开发参考简要提到

一个线程也可以成为一个守护进程,使它在后台运行。

这自然让我的*nix 感觉刺痛。(顺便说一句,你看过新的蜘蛛侠电影了吗?它很不错。) 守护进程是答案吗?还是我完全失去了情节?

4

2 回答 2

2

在 Android 中使用服务。

您可以使用服务在后台运行..

请参阅此链接:

http://developer.android.com/reference/android/app/Service.html

有关示例,请参见此链接:

示例:使用消息传递在 Activity 和 Service 之间进行通信

于 2012-07-11T18:59:14.117 回答
0
  1. 更改connection = new Thread(new ServerThread());为:connection = new ServerThread();

  2. 可能在设置/获取处理程序实例时添加同步块(毕竟它在不同的线程中:))

  3. 循环实际上具有魔力;)

  4. 在 onDestroy 中退出 Looper for serverThread

  5. 最后但并非最不重要的一点(尽管它与 Handler/Looper 主题无关,这可能是您在日志中从未看到您所期望的原因):由于文档而不是用作 onTouchEvent,boolean onTouchEvent(MotionEvent event)因此可能永远不会调用此处理程序方法boolean dispatchTouchEvent(MotionEvent ev)Called when a touch screen event was not handled by any of the views under it.

编辑:你确定它执行 sendMessage 吗?顺便说一句,你为什么使用Log.v?它假定您将日志记录级别设置为详细,否则日志将被放弃。我建议使用相当Log.i

也许试试这个代码:

ServerThread connection;
Handler coordHandler;

public void onCreate(Bundle savedInstanceState) {
    connection = new ServerThread();
    connection.start();
}

@Override
protected void onDestroy() {
    synchronized (this) {
        if(coordHandler != null) {
            coordHandler.getLooper().quit();
        }
    }
    super.onDestroy();
}

public boolean dispatchTouchEvent(MotionEvent event) {

    synchronized (this) {
        if(coordHandler == null) {
            Log.i(INNER_TAG, "Handler is null");
        }
        else {
            Log.i(INNER_TAG, "Handler exists");
            coordHandler.sendMessage(
                    coordHandler.obtainMessage(
                            0, event.toString()));
        }
    }

    return false;
}

synchronized void setCoordHandler(Handler handler) {
    coordHandler = handler;
}

public class ServerThread extends Thread {

    public void run() {

        this.setName("serverThread");

        Looper.prepare();

        setCoordHandler(new Handler() {

            @Override
            public void handleMessage(Message msg) {
                Log.i(INNER_TAG, "Inside handler");
            }
        });

        Looper.loop();
    }
}
于 2012-07-11T21:51:30.683 回答