【问题标题】:Runnables not being executed by Handler in androidandroid中的Handler未执行可运行程序
【发布时间】:2013-01-21 04:30:59
【问题描述】:

我的 android 应用程序中有一个 IntentService 类,它将 UDP 数据包发送到服务器。在我早期的实现中,我没有使用处理程序并且代码运行良好。我想在发送之前实现数据包的排队。因此,我创建了两个可运行文件,分别用于写入和读取队列。并尝试使用处理程序执行它们。但是可运行对象不会被执行并且会抛出 NullPointerExecption。我认为我的处理程序实现有问题。我想知道使用处理程序执行可运行文件的正确方法。提前致谢。我在下面发布了一些代码 sn-p 和 logcat:

wHandler = new Handler();
rHandler = new Handler();
writer = new Runnable(){
    public void run(){
            switch (pType) {
            case 0:
                while (send) {
                    queueMessageForSending(msg.getBytes());
                }
            case 1:
                // Float f = new Float(delayField.getString());
                // for(int i=0;i<2000;i++)
                while (send) {
                    try {
                        Thread.currentThread().sleep(delay);
                    } catch (Exception e) {
                    }
                    if(send)
                        queueMessageForSending(msg.getBytes());
                }
                // break;
            case 2:
                // for(int i=0;i<10000;i++)
                while (send) {
                    int u = want(30);
                    // int e=(int)Math.floor(-1*log(u)/(log((float)2.718)*2));
                    // System.out.println(e);
                    String data1 = "";
                    while ((u--) > 0)
                        data1 = data1 + msg;
                    if(send)
                        queueMessageForSending(data1.getBytes());
                }
                // break;
            case 3:
                //float f2 = Float.parseFloat(delayField.getText().toString());
                // for(int i=0;i<50;i++)
                while (send) {
                    int u = want(30);
                    // int e=(int)Math.floor(-1*log(u)/(log((float)2.718)*2));
                    System.out.println(u);
                    String data1 = "";
                    while ((u--) > 0)
                        data1 = data1 + msg;
                    System.out.println("data length :" + data1.length());
                    try {
                        Thread.currentThread().sleep(delay);
                    } catch (Exception e) {
                    }
                    if(send)
                        queueMessageForSending(data1.getBytes());
                }

            }
            wHandler.post(this);
        }
    };
    reader = new Runnable(){
        public void run(){
            while(send){
                if (!writeQueue.isEmpty())
                {
                    byte[] sendData = (byte[]) writeQueue.elementAt(0);
                    sendPacket(sendData);
                }
            }
            rHandler.post(this);
        }
    };

wHandler.post(writer);
rHandler.post(reader);

void sendPacket(byte[] data) {
    //if(socket!=null){
    try {
        System.out.println("\nClient:: Sending packet: " + " to " + addr
                + port);
        if(seq==100000)
        {
         seq=0;
        }
        Date d = new Date();
        Calendar c = Calendar.getInstance();
        c.setTime(d);
        String time = c.get(Calendar.HOUR_OF_DAY) + ":" +
        c.get(Calendar.MINUTE) + ":" +
        c.get(Calendar.SECOND);
    //System.out.println(time);
        long sentTime = c.getTime().getTime();
        //System.out.println(sentTime+"  "+seq);
        header=" "+seq+" "+sendData.length+"  "+sentTime+"  "+time+"  ";
        seq++;

        String s1= new String(sendData);
        String s2= header+s1;
       // System.out.println(s2);
        byte[] sendDataFinal = (byte[]) s2.getBytes();
        spacket = new DatagramPacket(sendDataFinal, sendDataFinal.length, addr, port);
        socket.send(spacket);
        writeQueue.remove(data);
        String resultTxt="Sent Packet at:"+DateFormat.format("MM/dd/yy h:mmaa", System.currentTimeMillis());
        broadcastIntent1.putExtra(PARAM_OUT_MSG, resultTxt);
        sendBroadcast(broadcastIntent1);
    } catch (Exception e) {
        System.out.println("Error:" + e.getMessage());
        e.printStackTrace();
        return;
    }
}

void queueMessageForSending(byte[] data)
{
    if (data.length > DEFAULT_DATAGRAM_SIZE)
    {
    throw new IllegalArgumentException(
    "Message too long: limit is " +
    DEFAULT_DATAGRAM_SIZE + " bytes");
    }
    synchronized(writeQueue)
    {
    writeQueue.addElement(data);
    writeQueue.notify();
    }
}

Logcat:

01-21 09:46:59.022: E/AndroidRuntime(915): FATAL EXCEPTION: IntentService[UdpService]
01-21 09:46:59.022: E/AndroidRuntime(915): java.lang.NullPointerException
01-21 09:46:59.022: E/AndroidRuntime(915):  at com.example.udpmessageclient.UdpSendService$1.run(UdpSendService.java:119)
01-21 09:46:59.022: E/AndroidRuntime(915):  at android.os.Handler.handleCallback(Handler.java:615)
01-21 09:46:59.022: E/AndroidRuntime(915):  at android.os.Handler.dispatchMessage(Handler.java:92)
01-21 09:46:59.022: E/AndroidRuntime(915):  at android.os.Looper.loop(Looper.java:137)
01-21 09:46:59.022: E/AndroidRuntime(915):  at android.os.HandlerThread.run(HandlerThread.java:60)

【问题讨论】:

  • 无法确定,因为您没有发布所有代码,但我敢打赌,问题是 writeQueue 的生产者/消费者问题 - 在 isEmpty 调用之间删除了最后一个元素和接听电话。您确实应该使用某种锁定来防止出现问题。计数信号量在这里是完美的,它还可以让您在没有可用数据时不忙于等待。
  • @Gabe 我现在已经发布了函数sendPacket() 和'queueMessageForSending()` 的代码,它们在runnables 中被调用。
  • UdpSendService.java:119 是哪一行
  • 它的wHandler.post(this);
  • 好的...我将队列编写器线程移至AsyncTask。并且队列是从IntentService的主线程中读取的。但是由于AsyncTask 仅用于短期后台任务,而我的线程运行了很长时间(直到被用户停止),我不确定这是否是一个好方法。虽然代码现在执行

标签: android multithreading handler runnable


【解决方案1】:

像这样在Thread 中启动这些runnables

Thread t =new Thread(new Runnable() {

        public void run() {
            // do whatever you want to do inside runnable

            // after functionality inside runnable is complete...call handler
            Message msg= new Message();
            msg.what=1;
            h.sendMessage(msg);
        }
});

之后,您可以在handler 中执行所需的功能

 Handler h =new Handler(){
        public void handleMessage(android.os.Message msg)
        {
            // do whatever you want to do in handler            
        } 
    };

【讨论】:

  • 感谢您的回答。我应该在线程上调用start() 方法吗? runnables 应该在哪里声明?
  • yes...start() 方法应该在线程上调用。此外,您可以在线程构造函数中声明可运行对象。检查以查看我的更新答案。
  • 您建议的方法是将消息传递给处理程序。但我想将 Runnables 传递给处理程序。你能告诉我这个的代码吗?我不想单独执行线程,因为 android 不是线程安全的。如果您可以建议除处理程序之外的任何其他方式来执行此操作。再次感谢
  • 我想建议你使用 ExecutorService executorService = Executors.newSingleThreadExecutor() 和 executorService.submit(Runnable) 方法来按顺序执行你的 2 Runnable。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-08
  • 2023-03-05
  • 2018-12-26
  • 1970-01-01
  • 1970-01-01
  • 2011-02-05
  • 1970-01-01
相关资源
最近更新 更多