2

类似或相同的问题已在此处得到解答

我正在创建一个 Android 应用程序,它向网络发送广播消息并准备响应的设备列表。

现在我做了什么:

我创建了一个调用线程的Activity类。 负责发送广播消息。DeviceManagerWindow.javaSender.javaSender.java

然后DeviceManagerWindow.java调用另一个负责监听设备响应的线程。devices设备响应后,响应将在 Activity 中列出。为此,我有一个TableLayout名为deviceList.

我写了什么代码:

DeviceManagerWindow.java This method is called when a button for search is pressed

public void searchDevice(View v) throws IOException, InterruptedException
{
    //Log.v("TableLayout:",view.toString());
    sendMulticastFlyport = new Thread(new FlyportSender(MAC));
    sendMulticastFlyport.start();
    new Thread()
    {
        public void run()
        {
            MulticastSocket socketComputer=null;
            try
            {
                socketComputer = new MulticastSocket(WifiConstants.COMPUTER_RECV_PORT);
                socketComputer.joinGroup(InetAddress.getByName(WifiConstants.COMPUTER_NETWORK_ADDR));
                socketComputer.setSoTimeout(1*60*1000);
                byte[] inBufComputer = new byte[1024];
                DatagramPacket inPacketComputer = new DatagramPacket(inBufComputer, inBufComputer.length);

                while(true)
                {
                    System.out.println("Listening...");
                    socketComputer.receive(inPacketComputer);
                    System.out.println("Received");
                    String msg = new String(inBufComputer, 0, inPacketComputer.getLength());
                    DeviceInformation device = new DeviceInformation(1, msg, inPacketComputer.getAddress().toString());

                    addDevice(device, false, 1);

                    Log.v("Received:","Received Computer From :" + inPacketComputer.getAddress() + " Msg : " + msg);
                    //System.out.write(inPacket.getData(),0,inPacket.getLength());
                    System.out.println();
                    Thread.sleep(2000);
                }
            }
            catch(Exception e)
            {
                Log.v("Exception:","During Receiving Computer: "+e.toString());
                try
                {
                    addDevice(null, true, 1);
                }
                catch (IOException e1)
                {
                    Log.v("Exception:", "Computer End Error: " +e1);
                }
            }
            finally
            {
                socketComputer.close();
            }
        }
    }.start();

以下代码创建一个列表:

public void addDevice(DeviceInformation device, boolean bool, int type) throws IOException
{
    TableLayout tb = (TableLayout) findViewById(R.id.DeviceList);
    Log.v("addDevice","Called");
    if(bool)
    {
        LayoutParams layout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        TableRow tr = new TableRow(getApplicationContext());
        TextView tv = new TextView(getApplicationContext());
        System.out.println(tb);
        tv.setLayoutParams(layout);
        tr.setLayoutParams(layout);
        String message;
        Log.v("addDevice","Device Timeout");
        switch(type)
        {
            case 1:
                computerEnd=true;
                break;
            case 2:
                raspberryEnd=true;
                break;
            case 3:
                flyportEnd=true;
                break;
        }
        if(computerEnd && raspberryEnd && flyportEnd)
        {
            if(rowCounter>0)
            {
                message = "No More Devices";
            }
            else
            {
                message = "No Devices Found"; 
            }
            tv.setText(message);
            tv.setTextColor(Color.WHITE);
            if(rowCounter%2==0)
            {
                tr.setBackgroundColor(Color.DKGRAY);
            }
            else
            {
                tr.setBackgroundColor(Color.GRAY);
            }
            tv.setVisibility(1);
            tr.addView(tv);
            tb.addView(tr);
        }
    }
    else
    {   
        LayoutParams layout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        TableRow tr = new TableRow(getApplicationContext());
        TextView tv = new TextView(getApplicationContext());

        tv.setLayoutParams(layout);
        tr.setLayoutParams(layout);

        Log.v("addDevice","Received");
        String textToDisplay = device.getDeviceTypeString()+"\n"+device.getIPAddress(); //Write the text to display
        tv.setText(textToDisplay);
        tv.setTextColor(Color.WHITE);
        Drawable img;
        if(device.getDeviceType()==1)
        {
            img = getApplicationContext().getResources().getDrawable(R.drawable.pc);
        }
        else if(device.getDeviceType()==2)
        {
            img = getApplicationContext().getResources().getDrawable(R.drawable.raspberry);
        }
        else
        {
            img = getApplicationContext().getResources().getDrawable(R.drawable.flyport);
        }
        img.setBounds(0,0,70,45);
        tv.setCompoundDrawables(null, null, img, null);
        tv.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {

            }
        });
        if(rowCounter%2==0)
        {
            tr.setBackgroundColor(Color.DKGRAY);
        }
        else
        {
            tr.setBackgroundColor(Color.GRAY);
        }
        rowCounter++;
        Log.v("Result","Device Added");
    }
}

现在它在 logCat 中向我显示一个错误:

05-11 22:01:10.165: E/AndroidRuntime(13873): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

我从中得出的结论是只允许 UIThread 访问创建的视图。

以前我试过:

new Thread()
{
    public void run()
    {
        runOnUiThread(){
        MulticastSocket socketComputer=null;
        try
        {
            ....        
            ....
            ....
    }
}

那个时候我收到一个错误:

主线程无法访问网络

在此之前,我曾尝试使用synchronizedReceiving.java线程文件中调用的方法。但它也给出了不创建列表的错误。

我已经尝试了所有可能的方法。

现在我该怎么办。?

4

1 回答 1

1

你猜对了。现在您可以学习使用 Handler 将信息传递给 UI 线程(参见http://www.techotopia.com/index.php/A_Basic_Overview_of_Android_Threads_and_Thread_handlers)或 AsyncTask(参见http://developer.android.com/reference/ android/os/AsyncTask.html )。

我个人更喜欢 AsyncTask。您可以将执行搜索的代码粘贴到 doInBackground() 方法中(不需要使用单独的线程,doInBackground() 已经为您完成了)并将与 UI 相关的代码(列表创建代码)粘贴到 onPostExecute( ) 方法。如果从链接中不够清楚它是如何工作的,请搜索 AsyncTask 的更多示例。

编辑:如果您希望您的设备搜索代码无限期地运行,那么您必须求助于 Handler,因为 AsyncTask 期望 doInBackground() 方法在运行 onPostExecute() 之前完成。看看哪个选项更适合您的需求。

于 2013-05-11T17:08:18.010 回答