2013-02-27 5 views
0

Здравствуйте, Guys,
Я хотел сделать чат-клиент для своего Android. Но я не могу получить никакой связи.
Ну, может быть, вы можете помочь мне немного ..
В моей MainActivity.java я называю:Проблемы с AsyncTask/Thread и networkonmainthreadexception

//connect to the server 
SocketTask connection = new SocketTask(this); 
connection.execute(); 

Мой SocketTask.java выглядит следующим образом:

package chat.client; 

import java.io.DataInputStream; 
import java.io.IOException; 
import java.io.PrintStream; 
import java.net.Socket; 

import android.os.AsyncTask; 

public class SocketTask extends AsyncTask<Void, Void, Void>{ 
    private Socket socket; 
    private DataInputStream input; 
    protected PrintStream output; 
    private MainActivity main; 
    private Thread thrd; 

    public SocketTask(MainActivity main){ 
     this.main = main; 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
     try { 
      socket = new Socket("192.168.178.23", 1338); 
      input = new DataInputStream(socket.getInputStream()); 
      output = new PrintStream(socket.getOutputStream()); 

      // submittes the name of the client 
      output.println("Mobile"); 
      output.flush(); 
      thrd = new Thread(new Runnable() { 
       public void run() { 
        while (!Thread.interrupted()) { 
         try { 
          final String data = input.readLine(); 
          if (data != null) 
           main.runOnUiThread(new Runnable() { 
            //new Runnable(){ 
            @Override 
            public void run() { 
             if(!data.equals("")){ 
              //main.chatHistory.append(data+"\n"); 
              main.addText(data); 
             }else{ 
              //chatHistory.append("\n"); 
              main.addText(""); 
             } 

            } 
           }); 
          //}; 
         } catch (IOException e) { 
          //chatHistory.append("Verbindung zum Server abgebrochen!"); 
          main.addText("Verbindung zum Server abgebrochen!"); 
         } 
        } 
       } 
      }); 
      thrd.start(); 
     } catch (Exception e) { 
      //chatHistory.append("Es konnte keine Verbindung zum Server aufgebaut werden!"); 
      main.addText("Es konnte keine Verbindung zum Server aufgebaut werden!"+e); 
     } 
     return null; 
    } 
} 

Но когда я запускаю его я только получаю:
02-27 16: 32: 05,875: E/SensorManager (26146): нить начать

Кроме того, когда я пытаюсь вызвать "connection.doInBackground()" вместо «Conne ction.execute() "(я знаю, что это вообще не имеет смысла), я получаю« networkonmainthreadexception »- но я думал, что исправил это уже с помощью AsyncTask. Ну, я новичок в Android, но я уже много гугл, не знаю, я ли это глупость, но теперь я сдался, и поэтому зарегистрировал меня здесь. Может быть, кто-то из вас может сказать мне, что я делаю неправильно.

(Не уверен, что мне нужно опубликовать мой класс MainActivity ..)
Спасибо! :)

Редактировать: Спасибо, ребята, за все эти ответы, правильно знаю, я немного перенапряжен, просто дайте мне время, чтобы попробовать/понять все ваши советы, спасибо!

+0

Где брошено исключение? Какой номер строки и класс? Чем больше деталей, тем лучше. – Rawkode

+0

Если вы вызываете doInBackground напрямую, вы обходите фактическую часть с резьбой, которая обычно создается путем вызова «выполнить». Следовательно, вы просто запускаете doInBackground, как и любой другой вызов метода в потоке, который вы ему назвали, из-за чего вы получили эту ошибку. – dymmeh

+0

Вам нужно будет опубликовать немного больше трассировки стека, чтобы узнать, что вызывает исключение. connection.execute() - это правильный путь, но, возможно, что-то другое вызывает проблему. –

ответ

0

Исключение означает, что вам необходимо запустить сетевые операции в фоновом потоке. Вызов непосредственно doInBackground() просто заставляет все работать в том же потоке, что и вызов, основной, очевидно. Итак, вы должны создать новый с connection.excute(). Но вы не можете обновлять элементы пользовательского интерфейса из фонового потока. Для этого в главном потоке, необходимо реализовать onProgressUpdate() для AsyncTask как это:

@Override 
    protected void onProgressUpdate(String... arg) {    
     main.addText(arg[0]); 
    } 

теперь заменить все вызовы addText() в doInBackground() с publishProgress("whatever");. Не забудьте изменить объявление задачи Async на AsyncTask<Void, String, Void>. Когда вы закончите все выше, вам не нужно будет порождать другую нить внутри doInBackground(), она будет выполнена в фоновом режиме в любом случае. Хотя ваш текущий код делает примерно то же самое, это разрешит беспорядок (не болееи main.runOnUiThread...) и, вероятно, исправить вашу проблему.

0

Вы добавили требуемое разрешение в манифест?

<uses-permission android:name="android.permission.INTERNET"></uses-permission> 
+0

Да, это уже в моем манифесте! – Schwamm007

+1

Этот ответ лучше всего подходит для комментариев. – dymmeh

+0

Извините, я отвечаю на это, потому что много раз это является источником таких проблем. –

0

Вы пытаетесь работать с вашим MainActivity в doInBackground() это должно быть в методе onPostExecute(), который работает на UI нити и метод doInBackground() не делает.

AsyncTask

4 шагов

Когда асинхронная задача выполняются, задача проходит через 4 этапа:

onPreExecute(), вызываемый в потоке пользовательского интерфейса, прежде чем задача выполняется , Этот шаг обычно используется для настройки задачи, например, показывая индикатор выполнения в пользовательском интерфейсе.

doInBackground (Params ...), вызывается на фоне потока сразу после onPreExecute() завершает выполнение. Этот шаг используется для выполнения фоновых вычислений, которые могут занять много времени. На этот шаг передаются параметры асинхронной задачи . Результат вычисления должен быть возвращен этим шагом и будет , возвращенном на последний шаг. Этот шаг также может использовать publishProgress (Progress ...), чтобы опубликовать одну или несколько единиц прогресса. Эти значения публикуются в потоке пользовательского интерфейса, на этапе onProgressUpdate (Прогресс ...).

onProgressUpdate (Progress ...), вызываемый в потоке пользовательского интерфейса после вызова для публикацииProgress (Progress ...).Время выполнения: не определено. Этот метод используется для отображения любой формы прогресса в пользовательском интерфейсе , пока фоновое вычисление все еще выполняется. Например, он может использоваться для анимирования строки выполнения или отображения журналов в текстовом поле .

onPostExecute (Result), вызывается в потоке пользовательского интерфейса после фона вычисление завершается. Результатом вычисления фона является , переданный этому шагу в качестве параметра.

+0

Или 'onProgessUpdate()'. –

+0

Да, спасибо @MikeD, я просто так не использую, поэтому я привык говорить 'onPostExecute()' – codeMagic

0

Вместо того, чтобы пытаться работает что-то на главном потоке, как вы есть, с AsynTask, если вам нужно запустить что-то на главном потоке (т.е. UI), вы могли бы назвать publishProgess() из doInBackground(...), который, в свою очередь, звонки onProgressUpdate(...). Не звоните doInBackground напрямую, execute() - это правильный способ начать AsyncTask. Когда doInBackground() вернется, onPostExecute() будет вызываться автоматически по основному потоку.

Android docs on AsyncTask очень хорошие и имеют хороший пример использования.

1

Есть много концептуальных ошибок при реализации AsyncTask, которые действительно трудно даже понять, почему или что может быть неправильным, поэтому я напишу здесь рецепт и подсказки о том, как написать AsyncTask и применить их, если вы все еще получаете ошибки, то вы еще раз спросить:

советы:

  • не создают новый поток внутри AsyncTask, в doInBackground() уже будучи вызываемый в фоновом потоке
  • не вызывайте runO nUiThread на AsyncTask, то onPostExecute() уже называется в потоке пользовательского интерфейса
  • Если ваша деятельность приостанавливается (OnPause() называется) называют .pause() на вашем AsyncTask или иначе вы, вероятно, будет иметь некоторые NullPointerException
  • Do напрямую не вызывайте doInBackground(), как вы предложили, вызов execute() создаст новый поток и вызовет его для вас (поэтому для AsyncTask требуется)
  • не содержат объект активности или любой другой объект, который содержит контекст для вашей AsyncTask.Просто поместите объявление класса AsyncTask внутри самой операции и в целях организации сделайте doInbackground() вызовите один метод в другом классе с фактической обработкой. Таким образом, ваш onPostExecute может вызвать пользовательский интерфейс, чтобы обновить его, но держать gethering данных/ОБРАБОТКА отдельно от деятельности

рецепт:

// put this class inside your Activity and 
// just call a separate class (for organisation), 
// or just put the code all in there (for no organisation) 
private class SocketTask extends AsyncTask<Void, Void, String> { 

@Override 
protected String doInBackground(Void... params) { 
    // Whatever you do inside here 
    // DO NOT create a new thread! 
    return APIConnection.callAPI(); 
} 

@Override 
protected void onPostExecute(String result) { 
    if(result!=null){ 
    //Update your UI here 
    }else{ 
    // Some error happen? 
    } 
} 
} 
+0

Да! Первая проблема заключается в том, что она даже пытается * использовать * AT для этой цели! Кто это сказал: «Для программиста Android любая проблема параллелизма выглядит как AsyncTask?» –