Анонимный чат клиент

Размещайте ссылки на ваши собственные приложения с целью пиара или для бета-тестирования.
Правила форума
О возможности разместить информацию о вашем приложении на главной странице сайта читайте здесь: http://startandroid.ru/ru/about/pomosch ... henii.html
Ответить
iandryxa
Сообщения: 58
Зарегистрирован: 23 янв 2014, 20:40

Анонимный чат клиент

Сообщение iandryxa » 28 окт 2014, 21:13

Всем доброго времени суток!)
Пишу приложение для колледжа- анонимный чат, так как в Android недавно (преимущественно занимаюсь java), есть определенные недоработки.

Имеется клиент приложение(android) и сервер (java), изначально написанный для чата на яве, затем решил приспособить его под андройд, однако есть множество косяков, помощь в решении которых я и прошу.

Код сервера:

Код: Выделить всё

public class Server {

	//создаем ArrayList ля хранения входящих сообщений
	ArrayList clientsOutputStreams;
	
	public class ClientHandler implements Runnable{
		

		BufferedReader reader;
		Socket sock;

		public ClientHandler(Socket sockClient){
			try{
				sock = sockClient;
				InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
				reader = new BufferedReader(isReader);
			}catch(Exception e){
				
			}
		}
		
		@Override
		public void run() {
			String message;
			try{
				while((message = reader.readLine()) != null){
					System.out.println("read "+message);
					tellEveryone(message);
				}
			}catch(Exception e){
				e.printStackTrace();
			}
			
		}
	}
	
	public static void main(String[] args){
		new Server().go();
	}
		
		public void go(){
			clientsOutputStreams = new ArrayList();
			try{
				ServerSocket serverSocket = new ServerSocket(5050);
				System.out.println("Ожидаю клиента..");
				while(true){
					Socket clientSocket = serverSocket.accept();
					System.out.println("Клиент подключен");
					PrintWriter writer = new PrintWriter(clientSocket.getOutputStream());
					clientsOutputStreams.add(writer);
					
					Thread t = new Thread(new ClientHandler(clientSocket));
					t.start();
				}
			}catch(Exception e){
				e.printStackTrace();
			}
		}
		
		public void tellEveryone(String message){
			Iterator it = clientsOutputStreams.iterator();
			while(it.hasNext()){
				try{
					PrintWriter writer = (PrintWriter) it.next();
					writer.println(message);
					writer.flush();
					System.out.println("Сообщение разослано");
				}catch(Exception e){
					
				}
			}
		}
		
	
	
	
	
}
Сервер одновременно принимает(go()) и рассылает(tellEveryone) сообщения, так вот, в версии с ява клиентом все работает прекрасно, однако с андройдом все немного иначе -хотя логи и показывают что сообщение пришло, в ListView оно не отображается.
Код клиента

Код: Выделить всё

public class MainActivity extends ActionBarActivity {
	
	BufferedReader reader;
	PrintWriter writer;
	Socket sock;
	
	Button btnSend;
	EditText mEditText;
	ListView lvMessage;
	
	String messageInput, messageOutput;
	ArrayList<String> messages;
	ArrayAdapter<String>adapter;
	
	setUpNetwork setUp;
	Send send;
	Output out;
	
	private static final String TAG = "myLog";
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        setUp = new setUpNetwork();
		setUp.execute();
		
		messages = new ArrayList<String>();
		
		lvMessage = (ListView)findViewById(R.id.lvMessage);
		
		
		adapter = new ArrayAdapter<String>(this,
				android.R.layout.simple_list_item_1, messages);
		
		lvMessage.setAdapter(adapter);
		
        mEditText = (EditText)findViewById(R.id.editText1);
        btnSend = (Button)findViewById(R.id.button1);
        btnSend.setOnClickListener(new OnClickListener(){
   
		@Override
		public void onClick(View v) {
		messageInput = mEditText.getText().toString();
		
		send = new Send();
		send.execute();
		
		out = new Output();
		out.execute();
		
		mEditText.setText("");
			}   
       });
    }
    
//-----------------------Класс отправки сообщений-----------------------------------------------------------------------------------------    
    class Send extends AsyncTask<Void,Void,Void>{

		@Override
		protected Void doInBackground(Void... params) {
			try{
			writer.println(messageInput);
			writer.flush();
			Log.e(TAG, "Подключение выполнено");
			}catch(Exception e){
				e.printStackTrace();
				Log.e(TAG, "Сообщение не отправлено метод выдал исключение");
			}
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			
			Toast t = Toast.makeText(getApplicationContext(), "Сообщение отправленно!", Toast.LENGTH_SHORT);
			t.show();
		}
    	
    }
    
    //---------------------Класс получения сообщений---------------------------------------------------------------------------------------
    class Output extends AsyncTask<Void,Void,Void>{
    	String message;
		@Override
		protected Void doInBackground(Void... params) {
				try {
					while((messageOutput = reader.readLine()) != null){
						messages.add(0, messageOutput);	
			                        //adapter.notifyDataSetChanged();
						Log.e(TAG, "Сообщение получено и добавлено в список "+messageOutput);			
					}
				} catch (IOException e) {
					e.printStackTrace();
					
				}
			return null;
		}
		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			
		}
		
		
    }
//---------------------------Класс подключения к серверу----------------------------------------------------------------------------------
    class setUpNetwork extends AsyncTask<Void,Void,Void>{

		@Override
		protected Void doInBackground(Void... params) {
			try {
				sock = new Socket("192.168.0.104", 5050);
				InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());
				reader = new BufferedReader(streamReader);
				writer = new PrintWriter(sock.getOutputStream());
				Log.e(TAG, "Подключение выполнено");
			} catch (Exception e) {
				e.printStackTrace();
				Log.e(TAG, "подключение провалилось!");
			}
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			// TODO Auto-generated method stub
			super.onPostExecute(result);
			Toast t = Toast.makeText(getApplicationContext(), "Подключение выполнено", Toast.LENGTH_LONG);
			t.show();
		}
    	
    }
}
Вкратце о самом клиенте:
1)При запуске выполняется подключение к серверу

Код: Выделить всё

 class setUpNetwork extends AsyncTask<Void,Void,Void>{

		@Override
		protected Void doInBackground(Void... params) {
			try {
				sock = new Socket("192.168.0.104", 5050);
				InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());
				reader = new BufferedReader(streamReader);
				writer = new PrintWriter(sock.getOutputStream());
				Log.e(TAG, "Подключение выполнено");
			} catch (Exception e) {
				e.printStackTrace();
				Log.e(TAG, "подключение провалилось!");
			}
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			// TODO Auto-generated method stub
			super.onPostExecute(result);
			Toast t = Toast.makeText(getApplicationContext(), "Подключение выполнено", Toast.LENGTH_LONG);
			t.show();
		}
    	
    }
2)Далее после того как пользователь ввел данные, и нажал кнопку "Отправить" данные считываются с EditText и передаются на сервер

Код: Выделить всё

class Send extends AsyncTask<Void,Void,Void>{

		@Override
		protected Void doInBackground(Void... params) {
			try{
			writer.println(messageInput);
			writer.flush();
			Log.e(TAG, "Подключение выполнено");
			}catch(Exception e){
				e.printStackTrace();
				Log.e(TAG, "Сообщение не отправлено метод выдал исключение");
			}
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			
			Toast t = Toast.makeText(getApplicationContext(), "Сообщение отправленно!", Toast.LENGTH_SHORT);
			t.show();
		}
    	
3) Далее принимаем сообщения от сервера и полученные сообщения помещаем в ListView, после чего сообщаем адаптеру об изменениях

Код: Выделить всё

class Output extends AsyncTask<Void,Void,Void>{
    	String message;
		@Override
		protected Void doInBackground(Void... params) {
				try {
					while((messageOutput = reader.readLine()) != null){
						messages.add(0, messageOutput);	
			                        //adapter.notifyDataSetChanged();
						Log.e(TAG, "Сообщение получено и добавлено в список "+messageOutput);			
					}
				} catch (IOException e) {
					e.printStackTrace();
					
				}
			return null;
		}
		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			
		}
Буду очень рад критике,советам, комментариям и помощи с вашей стороны)
P.S. если раскоментить adapter.notifyDataSetChanged(); то приложение аварийно вылетает, в чем может быть проблема, ведь как я понял мы сообщаем адаптеру что произошли изменения в ArrayList?
исходники на дропбоксе (https://www.dropbox.com/s/x4ix1crbsmyrw ... r.rar?dl=0)

Аватара пользователя
KamiSempai
Сообщения: 1339
Зарегистрирован: 17 фев 2012, 21:23
Откуда: Мордор

Re: Анонимный чат клиент

Сообщение KamiSempai » 28 окт 2014, 23:52

Использовать AsyncTask для таких целей я бы не рекомендовал, а зацикливать поток в doInBackground тем более. Этим вы можете нечаяно затормозить работу остальных AsyncTask-ов.
Если интересно почему может посмотреть вот этот вебинар viewtopic.php?f=60&t=2754 Там подробно разобрана работа AsyncTask-ов.

Касаемо, того, почему не обновляется список:
Вы добавляете строку в список но ни как не информируете ListView о том, что содержимое списка изменилось.
Делается это так: adapter.notifyDataSetChanged();

Если попробовать вызвать вышеупомянутый метод в doInBackground нарветесь на ошибку. Обновлять UI нужно только в UI потоке.
Как вариант можно использовать onProgress AsyncTask-а, но я его ранее не рекомендовал использовать.

Поэтому лучше создайте обычный поток и обновляйте UI через runOnUiThread(Runnable action).

Как-то так:
[syntax=java5]class OutputReaderThread extends Theread{
@Override
public void run() {
String messageOutput = null;
try {
while(!isInterrupted() && (messageOutput = reader.readLine()) != null){
messages.add(0, messageOutput);
runOnUiThread(mListNotifier);
Log.e(TAG, "Сообщение получено и добавлено в список "+messageOutput);
}
} catch (IOException e) {
e.printStackTrace();
}
}

private Runnable mListNotifier = new Runnable() {
adapter.notifyDataSetChanged();
}
} [/syntax]
R.id.team
Хватит таскать макулатуру на тренировку! Используй T Note.

iandryxa
Сообщения: 58
Зарегистрирован: 23 янв 2014, 20:40

Re: Анонимный чат клиент

Сообщение iandryxa » 29 окт 2014, 10:19

спасибо за совет)

Ответить