2016-04-13 141 views
0

我在写一个程序,它返回一个String的ArrayList。问题是,当我调用该方法时,列表尚未填充,所以我得到一个空列表。 我尝试了一个线程,但现在我在调用方法时得到一个null引用。顺便说一下,我不得不实施异步任务,否则当尝试使用InetAddress时会出现异常。如何让一个程序在java中等待一个方法

private class DeviceManager extends Thread { 

    private ArrayList<String> deviceList; 
    private String networkIP; 

    public DeviceManager(String networkIP) { 
     this.networkIP = networkIP; 
    } 

    public void run() { 
     getDeviceList(); 
    } 

    public ArrayList<String> getDeviceList() { 
     new AsyncTask<Void, Void, Void>() { 

      @Override 
      protected Void doInBackground(Void... params) { 
       try { 
        deviceList = new ArrayList<String>(); 
        InetAddress address; 

        Log.i("NetworkIPgetDeviceList", networkIP); 

        String deviceIP = networkIP; 

        for (int i = 0; i < 255; i++) { 
         address = InetAddress.getByName(deviceIP += "" + i); 
         if (address.isReachable(2000)) {  
          Log.i("Devicefound", deviceIP); 
          deviceList.add(deviceIP); 
         } 
         deviceIP = networkIP; 
        } 

       } catch (UnknownHostException e) { 
        e.printStackTrace(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
       return null; 
      } 
     }.execute(); 
     return deviceList; 
    } 

    public ArrayList<String> getList() { 
     return this.deviceList; 
    } 
} 
+0

您应该运行在以后的另一个同步任务中使用此列表的代码 – Ferrybig

+0

我有c#的经验,以及我记得有一种简单的方法来通过实现异步方法来解决此问题,但我如何知道java中没有等效:( –

+0

如果您正在等待异步任务完成,您仍然会得到相同的异常。 Android引发这种异常的原因是,如果您挂起主线程,您的应用将无响应,导致用户体验不佳 – Ferrybig

回答

1

阿图尔你在做什么在你的代码是启动一个线程来获取设备列表,然后另一个线程(的AsyncTask),以实际创建设备名单。所以你有三个线程同时运行(假设你在UIThread中使用DeviceManager类)。 getDeviceList()正在返回的原因null是因为AsyncTasks doInBackground尚未运行尚未收集您的设备列表它可能正在等待其计划的机会。所以得出结论,你只需要一个线程(除了UIThread),它可以是线程或AsyncTask(更优选,因为它提供了更好的控制),因为生锈的大脑在他的回答中使用。我更愿意将DeviceManager设置为AsyncTask(只需稍微清洁一点,如果设备管理器只有任务是检索设备列表),如下面的代码所示。

中的AsyncTask后台线程doInBackground运行(如名字所暗示的),并onPostExecute在UI线程上运行后doInBackground

class DeviceManager extends AsyncTask<String, Void, List<String>> { 

    private ConnectionCompleteListener listener; 

    public interface ConnectionCompleteListener { 
     void onSuccess(List<String> deviceList); 

     // if you need to know reason for failure you can add 
     // parameter to onFailure 
     void onFailure(); 
    } 

    public DeviceManager(ConnectionCompleteListener listener) { 
     this.listener = listener; 
    } 

    @Override 
    protected List<String> doInBackground(String... params) { 
     List<String> deviceList = new ArrayList<>(); 
     String networkIP = params[0]; 
     try { 
      InetAddress address; 
      Log.i("NetworkIPgetDeviceList", networkIP); 

      String deviceIP = networkIP; 
      for (int i = 0; i < 255; i++) { 
       address = InetAddress.getByName(deviceIP += "" + i); 
       if (address.isReachable(2000)) { 
        Log.i("Devicefound", deviceIP); 
        deviceList.add(deviceIP); 
       } 
       deviceIP = networkIP; 
      } 
     } catch (IOException e) { 
      deviceList = null; 
      e.printStackTrace(); 
     } 
     return deviceList; 
    } 

    @Override 
    protected void onPostExecute(List<String> deviceList) { 
     if (deviceList == null) { 
      this.listener.onFailure(); 
     } else { 
      this.listener.onSuccess(deviceList); 
     } 
    } 
} 

所以在你的活动,你可以拨打

new DeviceManager(new DeviceManager.ConnectionCompleteListener 
      () { 
     @Override 
     public void onSuccess(List<String> deviceList) { 

     } 

     @Override 
     public void onFailure() { 

     } 
    }).execute("YOUR_NETWORK_IP"); 
+0

谢谢,我完成了:))) –

0

你得到空数组列表,因为当你使用异步任务越来越数组列表和异步任务doINBackground方法在不同的线程上运行(指不是在主线程)。所以当你的程序运行时,你的程序不会等待异步任务响应。

就可以解决这个像异步任务类... 使用onPostExecute方法并返回ArrayList中

@Override 
protected void onPostExecute(Void result) { 
//return array list here 
getList(); 
} 

希望这将帮助你

+0

问题是,我试图从我的MainActivity调用InetAddress方法。这导致了一个异常,我不得不实施一个asynctask来解决这个问题。 –

+0

我必须在哪里实施onPostExecute?在我的MainActivity? –

+0

顺便说一句谢谢你的回答,我会读一些有关异步任务线程和onPostExecute的文档,以获取更多信息 –

1

你这样做是完全错误的。 A Thread在后台运行,因此AsyncTask也是如此,所以基本上你正在后台运行后台任务。 成立。在其他类

public class DeviceManager { 

    private ArrayList<String> deviceList; 
    private String networkIP; 
    private ConnectionCompleteListener listener; 

    public interface ConnectionCompleteListener { 
     void onSuccess(); 

     void onFailure(); 
    } 

    public void setConnectionCompleteListener(ConnectionCompleteListener listener) { 
     this.listener = listener; 
    } 

    public DeviceManager(String networkIP) { 
     this.networkIP = networkIP; 
    } 

    public void getDeviceList() { 
     new AsyncTask<Void, Void, Boolean>() { 

      @Override 
      protected void onPostExecute(Boolean result) { 
       if(result) listener.onSuccess(); 
       else listener.onFailure(); 
      } 

      @Override 
      protected Boolean doInBackground(Void... params) { 
       try { 
        deviceList = new ArrayList<String>(); 
        InetAddress address; 

        Log.i("NetworkIPgetDeviceList", networkIP); 

        String deviceIP = networkIP; 

        for (int i = 0; i < 255; i++) { 
         address = InetAddress.getByName(deviceIP += "" + i); 
         if (address.isReachable(2000)) { 
          Log.i("Devicefound", deviceIP); 
          deviceList.add(deviceIP); 
         } 
         deviceIP = networkIP; 
        } 
        return true; 
       } catch (UnknownHostException e) { 
        e.printStackTrace(); 
        return false; 
       } catch (IOException e) { 
        e.printStackTrace(); 
        return false; 
       } 
       return null; 
      } 
     }.execute(); 
    } 

    public ArrayList<String> getList() { 
     return this.deviceList; 
    } 
} 

然后:

试试这个

private class classname{ 
    DeviceManager manager=new DeviceMnager(networkIp); 
    manger.setConnectionCompleteListener(new DeviceManager.ConnectionCompleteListener() { 
     @Override 
     public void onSuccess() { 
      // get your list here 
      manager.getList(); 
     } 

     @Override 
     public void onFailure() { 
      // connection failed show error 
     } 
    }); 
} 
+0

如果你要调用监听器方法从doInBackground它将在后台线程中运行。使用onPostExecute进行回调 – Shashank

+0

@Shashank很好的接收!编辑。 –

+0

应该工作。请注意,如果Artur仅使用设备管理器来检索该列表,为什么不使DeviceManager类成为AsyncTask,并且如果您提供回调,为什么不使用回调函数来提供devicelist而不是manager.getList(); – Shashank

0

的所有你不需要做DeviceManager一个线程中,您将在getDeviceList运行任务将首先从另一个新线程开始。其次,你不应该在主线程(UI)上等待,而是等待回调是一个更好的机制。

如果你坚持相同的代码试试这个..

public class DeviceManager extends Thread { 
private ArrayList<String> deviceList; 

private String networkIP; 
private boolean dataAvailable; 

public DeviceManager(String networkIP) { 
    this.networkIP = networkIP; 
} 

public void run() { 
    getDeviceList(); 
} 

public ArrayList<String> getDeviceList() { 

    new AsyncTask<Void, Void, Void>() { 
     @Override 
     protected Void doInBackground(Void... params) { 
      try { 
       deviceList = new ArrayList<String>(); 
       InetAddress address; 

       Log.i("NetworkIPgetDeviceList", networkIP); 

       String deviceIP = networkIP; 

       for (int i = 0; i < 255; i++) { 
        System.out.println("checking " + i); 
        address = InetAddress.getByName(deviceIP += "" + i); 
        if (address.isReachable(2000)) { 

         Log.i("Devicefound", deviceIP); 

         deviceList.add(deviceIP); 
        } 
        deviceIP = networkIP; 
       } 

      } catch (UnknownHostException e) { 
       e.printStackTrace(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
      dataAvailable = true; 
      synchronized (DeviceManager.this) { 
       DeviceManager.this.notify(); 
      } 
      return null; 
     } 

    }.execute(); 

    return deviceList; 
} 

synchronized public ArrayList<String> getList() { 

    while (!dataAvailable) { 
     try { 
      wait(); 
     } catch (InterruptedException e) { 
     } 

    } 
    return this.deviceList; 
} 



} 
相关问题