Как программировать вне основного потока пользовательского интерфейса

Я не знаю, существует ли поток пользовательского интерфейса по умолчанию, как его создать, если нет, или как сообщить когда я «в нем», где он начинается и заканчивается, если это так. Как убедиться, что PacketListener не является частью основного потока пользовательского интерфейса?

Я продолжаю сталкиваться с этим NetworkOnMainThreadException. Я понимаю, что это означает, что я пытаюсь сделать что-то в основном потоке пользовательского интерфейса, который должен иметь свой отдельный поток. Тем не менее, я не могу найти много, чтобы сказать мне, КАК на самом деле это сделать.

Я думал, что класс MainActivity БУДЕТ потоком пользовательского интерфейса, поскольку у меня был пользовательский интерфейс, и он работал. Тем не менее, я создал отдельный класс, который реализует Runnable, и поместил туда материалы для сетевого подключения, и я все еще получаю исключение, так что это все еще часть основного потока, да? Я вижу, что MainActivity не расширяет Thread, так что, возможно, это было глупое предположение. У меня нет ощущения, что что-то изменится, если я добавлю еще один класс, который реализует Runnable/extends Thread. Будет ли он?


MainActivity.java

public class MainActivity extends AppCompatActivity {

    ArrayList<String> listItems;
    ArrayAdapter<String> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listItems = new ArrayList<>();
        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listItems);
        ListView listview = (ListView) findViewById(R.id.listview);
        listview.setAdapter(adapter);

        (new Thread(new PacketListener(adapter))).run();
    }
}

PackageListener.java:

public class PacketListener implements Runnable {
    ArrayAdapter<String> adapter;

    public PacketListener(ArrayAdapter<String> adapter) {
        this.adapter = adapter;
    }

    public void run() {
        byte[] buf = new byte[256];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);

        try {
            DatagramSocket socket = new DatagramSocket();
            socket.receive(packet);
        }
        catch(Exception e) {
            adapter.add("Exception: " + e.toString() );
            e.printStackTrace();
        }
        catch(Error e) {
            adapter.add("Unspecified Error: " + e.toString() );
            e.printStackTrace();
        }
    }
}

РЕДАКТИРОВАТЬ:

Моя последняя попытка, попытка следовать примеру этой страницы , пошел по пути большинства моих попыток и полностью сломал приложение. SendAnother — метод тестирования, привязанный к кнопке:

public void sendAnother(View view) {
    adapter.add("button clicked");

    new Thread(new Runnable() {
        public void run() {
            listview.post(new Runnable() {
                public void run() {
                    adapter.add("inside worker thread");
                }
            });
        }
    });
}

Думаю, в следующий раз наконец-то попробую AsyncTask. Меня больше не волнует, "грязный" ли он.


person donutguy640    schedule 22.09.2017    source источник


Ответы (3)


поток пользовательского интерфейса является основным потоком. вы знаете о текущей теме от

Thread.currentThread().getName();

извините, я не прочитал весь ваш вопрос, но вам нужно выполнить процесс блокировки в другом потоке, а не в mainThread.

есть много способов сделать это: AsyncTask, Services, ExecutorService и RxJava. и какой из них выбрать, зависит от ваших потребностей

эта ссылка будет полезна :)

person SemyColon.Me    schedule 22.09.2017
comment
Хорошо, но как мне создать новый поток, отдельный от потока пользовательского интерфейса? Я думал, что создание класса, реализующего Runnable, сделает это, но, похоже, это не так. Я не могу сказать, делаю ли я что-то не так, или это даже жизнеспособный способ сделать это. - person donutguy640; 22.09.2017
comment
Долгосрочный ответ - многопоточность Google в Java, а затем в Android. - person SemyColon.Me; 22.09.2017
comment
Не могли бы вы предложить учебник, пожалуйста? - person donutguy640; 23.09.2017
comment
Я ценю, по крайней мере, вашу публикацию, поскольку, похоже, никто другой не хочет этого делать (включая другие мои вопросы...). Я все равно был бы очень признателен за предложенную ссылку, поскольку материал, который я нашел с помощью этой строки поиска еще не были более полезными, чем то, что я нашел сам. - person donutguy640; 23.09.2017
comment
я сделаю все возможное, чтобы помочь людям :) ... извините за задержку, я не был в сети - person SemyColon.Me; 23.09.2017
comment
Хех, да, я так и думал, спасибо. В настоящее время пересматриваю тему, значительно укорачивая ее. - person donutguy640; 23.09.2017
comment
Ну, это не ответило на мой вопрос, но я думаю, что это, возможно, сыграло свою роль, помогая мне узнать, как определить, когда что-то стало отдельным потоком, благодаря getName() - person donutguy640; 30.09.2017

Ваш последний метод верен, за исключением того, что поток еще не запущен. Итак, вам нужно вызвать start():

public void sendAnother(View view) {
  //adapter.add("button clicked");

  new Thread(new Runnable() {
    public void run() {
      listview.post(new Runnable() {
        public void run() {
          adapter.add("inside worker thread");
        }
      });
    }
  }).start();
}
person ישו אוהב אותך    schedule 24.09.2017
comment
Ах, хороший момент. Однако никаких изменений, он по-прежнему отказывается запускаться, даже не продвинувшись достаточно далеко, чтобы дать мне NetworkOnMainThreadException, для которого я начал поток. - person donutguy640; 24.09.2017
comment
Ну, даже мои резервные копии не работают, и совершенно новый проект, который я начал пытаться снова заставить ЧТО-ТО работать, тоже сломан. Я понятия не имею, что произошло, но, может быть, мне следует отложить этот вопрос, пока я решу эту проблему... уииии -_- - person donutguy640; 25.09.2017

Я все еще не уверен, что мне нравится AsyncTask для этого проекта, поэтому, если кто-то может дать совет или ссылку на учебник по использованию Handler или Runnable, ПОЖАЛУЙСТА, опубликуйте его!

Строго говоря, это, по крайней мере, наконец-то позволяет мне делать что-то вне потока пользовательского интерфейса, и это был вопрос. Оооо, для чего это стоит всем, у кого есть эта проблема, вот что сначала сработало для меня.

public class MainActivity extends AppCompatActivity {
    ArrayAdapter<String> adapter;
    private static final int PORT= 8888;
    private static final int TIMEOUT_MS = 500;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ArrayList<String> listItems = new ArrayList<>();
        ListView listview = (ListView) findViewById(R.id.lvMain);
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, listItems);
        listview.setAdapter(adapter);

        UpdateView task = new UpdateView();
        task.execute();

        //just to show these parts are in different threads
        String temp = Thread.currentThread().getName();
        adapter.add("onCreate: " + temp);
    }

    private class UpdateView extends AsyncTask<URL, Integer, Long> {
        protected Long doInBackground(URL... urls) {
            //just to show these parts are in different threads
            String temp = Thread.currentThread().getName();
            adapter.add("UpdateView: " + temp);

            byte[] buf = new byte[256];
            byte[] ipAddress = {(byte)192,(byte)168,0,1};

            try {
                InetAddress address = InetAddress.getByAddress(ipAddress);

                String message = "\"xyz\"";
                DatagramSocket socket = new DatagramSocket(PORT);
                DatagramPacket packet = new DatagramPacket(message.getBytes(), message.length(), address, PORT);
                socket.send(packet);

                packet = new DatagramPacket(buf, buf.length);
                socket.receive(packet);
            }
            catch(IOException e) {
                adapter.add("IO Exception: " + e.toString() );
                e.printStackTrace();
            }

            adapter.notifyDataSetChanged();
            return 0L;
        }
    }
}
person donutguy640    schedule 29.09.2017