2016-04-13 4 views
0

Я пишу программу, которая возвращает мне ArrayList of Strings. Проблема в том, что когда я вызываю метод, список еще не заполнен, поэтому я возвращаю пустой список. Я пробовал это с потоком, но теперь я получаю ссылку null, когда я вызываю метод. Кстати, мне пришлось реализовать задачу async, иначе я получаю исключение при попытке использовать 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#, и как я помню, был простой способ решить эту проблему, реализовав метод async, но как я знаю, что в java нет эквивалента :( –

+0

Если вы ожидаете завершения задачи async, вы все равно получите то же исключение. Причина, по которой андроид выбрасывает это исключение, заключается в том, что если вы повесите основной поток, ваше приложение будет не отвечать на запросы, что приведет к плохому пользовательскому опыту – Ferrybig

ответ

1

Артур, что вы делаете в вашем коде начинает поток для получения списка устройств, а затем другой поток (AsyncTask) на самом деле создает устройство список. Таким образом, вы одновременно запускаете три потока (при условии, что вы используете класс DeviceManager в UIThread). Причина getDeviceList() возвращается null объясняется тем, что AsyncTasks doInBackground еще не запустил свой список устройств, и он мог ожидать его получения. поэтому, чтобы сделать вывод, что вам нужен только один поток (кроме UIThread), он может быть либо Thread, либо AsyncTask (более предпочтительным, поскольку он дает лучший контроль), так как ржавый мозг использовал в своем ответе. Я предпочитаю делать DeviceManager как AsyncTask (только немного чище, и если диспетчер устройств - это только задача получить список устройств) в качестве кода ниже.

в AsyncTask doInBackground работает в фоновом потоке (как предполагает название) и onPostExecute работает на потоке пользовательского интерфейса после 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 в асинхронном классе задач и вернуть Список_массивы

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

Надеется, что это поможет вам

+0

Проблема в том, что я попытался вызвать метод InetAddress из моего MainActivity. Это вызвало исключение, и мне пришлось реализовать асинтез, чтобы решить эту проблему. –

+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

, который должен работать. просто заметите, если Артур использует диспетчер устройств только для извлечения этого списка, почему бы не сделать класс 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; 
} 



} 
Смежные вопросы