Building a chat client Android app, how should I approach recieving messages? - android

I'm making an Android application that connects to my computer, with this I am trying to make it so I can send messages back and forth. As of right now messages can be sent and recieved server-side but for my Android application I don't know how to constantly check for messages and update the UI. I'm using a BufferedReader for input and I want to display the messages on a TextView. Here's what I have so far:
package com.example.david.chatclient;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.ExecutionException;
/**
* After connecting to server, how can i recieive messages, append it, and then reloop through it
*/
public class MainActivity extends AppCompatActivity {
private String IP;
private int portNumber;
private Socket clientSocket;
private PrintWriter writer;
private BufferedReader reader;
private Button connectButton;
private Button sendButton;
private EditText userMessage;
private TextView chatHistory;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 10.0.2.2 = Android Emulator IP Address (Reaches development machine, not emulator itself)
IP = "10.0.2.2";
portNumber = 25565;
connectButton = (Button) findViewById(R.id.connect_button);
sendButton = (Button) findViewById(R.id.send_button);
userMessage = (EditText) findViewById(R.id.user_message);
chatHistory = (TextView) findViewById(R.id.chat_history);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void connectClient(View view) {
ConnectToServer task = new ConnectToServer();
task.execute();
} // end connectClient
public void sendMessage(View view) {
String message = userMessage.getText().toString() + "\n";
writer.write(message);
writer.flush();
chatHistory.append("CLIENT: " + message);
userMessage.setText("");
}
private class ConnectToServer extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... params) {
try{
clientSocket = new Socket(IP, portNumber);
reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
writer = new PrintWriter(clientSocket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
Toast.makeText(MainActivity.this, "Successfuly connected, streams are esablished", Toast.LENGTH_SHORT).show();
}
} // end ConnectToServer
} // end MainActivity
Here's what the UI looks like:
https://gyazo.com/dbf99c78ca7874939a404ef7d23d8ff8

There are two aproaches.
Checking periodically if new message awaits on server this method is called Fetch - this is very battery and data unfriendly.
Keeping open connection all time aka push messaging - that's the modern way to go. Google handles this on android and ios with GCM

Related

In wireshark, I cannot see the packet I sent from android multicast socket

I follow the step here to set up a multicast server, but for some reason, I am not able to see my packet in wireshark. I am monitoring my wifi interface. Here is the code I used
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener((e) -> {
try {
boom();
} catch (Exception e1) {
e1.printStackTrace();
}
});
}
private void boom() throws Exception
{
new AsyncServer().execute("");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
class AsyncServer extends AsyncTask<String, Void, Void> {
private Exception exception;
protected Void doInBackground(String... args)
{
String msg = "Hello";
InetAddress group = null;
try {
group = InetAddress.getByName("239.1.2.3");
MulticastSocket s = new MulticastSocket(4333);
// s.setInterface(InetAddress.getByName("192.168.232.2")); // To use wifi interface, but doesn't seem to be necessary. The message I will send at 75 and receive at 79 will have address 192.168.232.2
s.joinGroup(group);
DatagramPacket hi = new DatagramPacket(msg.getBytes(), msg.length(), group, 4333);
s.send(hi);
byte[] buf = new byte[1000];
DatagramPacket recv = new DatagramPacket(buf, buf.length);
s.receive(recv);
System.out.println("Received Message: " + recv.getData());
System.out.println("Send By: " + recv.getAddress());
// OK, I'm done talking - leave the group...
s.leaveGroup(group);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
}
I try something similar in a Java application and it work just fine, so I am assuming this is something wrong with android. Do you guy have any idea ?
Thank you

Android client socket is always null

I have made client server connection and it connects well but the socket always returns null, I don't know why.
The server is MATLAB and has no problem and it runs well. When I try to write the ip of the server in browser it give me the message that the client should receive.
Here is the server code
data = 'Hello World..\n'
tcpipServer = tcpip('0.0.0.0',80,'NetworkRole','Server');
set(tcpipServer,'OutputBufferSize',length(data)+1);
fopen(tcpipServer);
fwrite(tcpipServer,data);
fclose(tcpipServer);
And here is the client code
import android.os.AsyncTask;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class MainActivity extends ActionBarActivity {
Socket socket;
TextView txt1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt1 = (TextView) findViewById(R.id.txt1);
final byte[] data = new byte[1024];
new Thread(new Runnable() {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName("192.168.185.10");
socket = new Socket(serverAddr, 80);
socket.getInputStream().read(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
txt1.setText(new String(data));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Here is the problem the socket is always equal to null
socket = new Socket(serverAddr, 80);
Note: It connects to the server but does not receive any thing
and I even have the internet permission in the manifest.

getting text from EditText in android

I have written this code for searching a text file for a string. The problem is, it says that the string is not found even if it is present. Process is to receive the text from the EditText and then start the searching process. But it shows that string is found every time.
package com.example.demo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button;
final EditText obedittext;
button =(Button)findViewById(R.id.button1);
obedittext =(EditText)findViewById(R.id.editText1);
button.setOnClickListener(
new View.OnClickListener()
{
boolean textfound;
public void onClick(View view)
{
textfound = searchtext(obedittext.getText().toString());
if(textfound)
maketoast(obedittext.getText().toString());
else
maketoast("Unsuccessfull");
}
});
}
protected boolean searchtext(String string) {
// TODO Auto-generated method stub
BufferedReader br = null;
try {
String sCurrentLine;
br = new BufferedReader(new InputStreamReader(getAssets().open("mneumo.txt")));
while ((sCurrentLine = br.readLine()) != null) {
if(sCurrentLine.equals(string)) {
return true;
}
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
finally{
}
return false;
}
private void maketoast(String string) {
// TODO Auto-generated method stub
Context context = getApplicationContext();
Toast toast = Toast.makeText(context, string , Toast.LENGTH_SHORT);
toast.show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
So when i tried to give the string inside the code itself instead of getting it from the edittext,it works fine. Like this,
string = "SPINAL ANESTHESIA AGENTS";
The sample text file is,
SPINAL ANESTHESIA AGENTS
XYLOCAINE: WHERE NOT TO USE WITH EPINEPHRINE
GENERAL ANAESTHESIA: EQUIPMENT CHECK PRIOR TO INDUCING
So how can i rectify this problem? Can anyone say why i am getting this problem?
Should i any other method to compare the strings?
The text file is correctly placed in the assets folder. And i accessed it using the assetmanager. And i am a total newbie to android development.
May be your editText contain some white space already, To get text from your editText try this:
obedittext.getText().toString().trim();
and inside your searchtext() method, replace your if condition with:
if(sCurrentLine.equalsIgnoreCase(string))

list of images not showing up after search button is pressed

I am getting image urls using google image search apis. i use okhttp to connect to the url. this is done in my activity's oncreate method. in the oncreate() method of fragment i get all the image urls and store them in mSmallIMagesUrl, in the oncreateView() i try to display the images using a customized adapter. but when i run my app, hit the search button, it shows a blank page, when i go back and click the search button(there is always text in the search box) it shows images of the the previous search text. i dont know why it this,below is my code, please let me know what i am missing. thanks
package com.paveynganpi.allsearch;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Text;
import java.io.IOException;
import java.util.ArrayList;
public class ImageGrid extends ActionBarActivity {
private static final String TAG = ImageGrid.class.getSimpleName();
protected int start = 0;//variable to change pages from google Api
//contains extra images urls to supply to ... when need
protected static ArrayList<ArrayList<String>> mBigImagesUrls = new ArrayList<ArrayList<String>>();
//contains image urls to inject into gridview
protected static ArrayList<String> mSmalImagesUrls = new ArrayList<>();
protected static String mEditedString;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_grid);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
for (int start = 0; start < 2; start++) {
if (isNetworkAvailable()) {
//using okHttp library to connect to imagesUrl and retrieve JSON Data
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(getImagePage(start)).
build();
Call call = client.newCall(request);
//runs the below code asynchronously
call.enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
Log.v(TAG, "error from request");
}
#Override
public void onResponse(Response response) throws IOException {
try {
String jsonData = response.body().string();
//Log.v(TAG, jsonData);
if (!response.isSuccessful()) {
alertUserAboutError();
} else {
// mSmalImagesUrls = getCurrentDetails(jsonData);
mBigImagesUrls.add(getCurrentDetails(jsonData));
Log.d(TAG, mBigImagesUrls.size() + " big size");
Log.d(TAG, mSmalImagesUrls.size() + " small size");
}
} catch (IOException | JSONException e) {
Log.e(TAG, "Exception caught :", e);
}
}
});
} else {
Toast.makeText(this, "Network is unavailable", Toast.LENGTH_LONG).show();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_image_grid, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private String getImagePage(int start) {
return "https://ajax.googleapis.com/ajax/services/search/images?v=1.0&q="
+ mEditedString + "&rsz=8&start=" + start;
}
//get data
private ArrayList<String> getCurrentDetails(String jsonData) throws JSONException {
JSONObject jsonObject = new JSONObject(jsonData);
JSONObject responseData = jsonObject.getJSONObject("responseData");
ArrayList<String> localList = new ArrayList<String>();
JSONArray results = responseData.getJSONArray("results");
for (int i = 0; i < results.length(); i++) {
localList.add(results.getJSONObject(i).getString("url"));
}
return localList;
}
//An AlertDialog to display to user when an error occurs
private void alertUserAboutError() {
AlertDialogFragment dialog = new AlertDialogFragment();
dialog.show(getFragmentManager(), "error_dialog");
}
//checks if user is connected to a network
private boolean isNetworkAvailable() {
ConnectivityManager cm =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isAvailable = false;
if (activeNetwork != null && activeNetwork.isConnectedOrConnecting()) {
isAvailable = true;
}
return isAvailable;
}
#Override
public void onBackPressed() {
super.onBackPressed();
Log.d(TAG,"back was pressed");
mBigImagesUrls.clear();
mSmalImagesUrls.clear();
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
protected GridView mGridView;//reference to gridview in fragment_image_grid.xml
static String mEditedString;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, mBigImagesUrls.size() + " final big size");
Log.d(TAG, mSmalImagesUrls.size() + "final small size");
for(int i =0;i<mBigImagesUrls.size();i++){
for(int j =0;j<8;j++){
mSmalImagesUrls.add(mBigImagesUrls.get(i).get(j));
}
}
}
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_image_grid, container, false);
final ArrayList<String> testList = new ArrayList<String>();
//gets the edited string from MainActivity
Bundle args = getActivity().getIntent().getExtras();
mEditedString = args.getString("space");
mGridView = (GridView)rootView.findViewById(R.id.imagesGrid);//reference to gridview
ImagesGridAdapter adapter = new ImagesGridAdapter(getActivity(), mSmalImagesUrls);
mGridView.setAdapter(adapter);
return rootView;
}
}
}
Since you are making an asynchronous request, the response is not available immediately. You can display a ProgressBar while the list of images is being downloaded, and then display the list when it has completed downloading.
After that, notify your adapter that the dataset has changed.

threads to AsyncTask( android, Modbus/TCP)

I'm working a connection to a PLC via TCP / Modbus and Jamod library, therefore I use and work with threads. I'm using to handle AsyncTask thread function, but when running my code the application is not responding and closes automatically. Thanks for the help in advance =)
package com.JR.scada;
import java.net.InetAddress;
import net.wimpi.modbus.Modbus;
import net.wimpi.modbus.io.ModbusTCPTransaction;
import net.wimpi.modbus.msg.ReadInputDiscretesRequest;
import net.wimpi.modbus.msg.ReadInputDiscretesResponse;
import net.wimpi.modbus.net.TCPMasterConnection;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class Main extends Activity{
TextView text, depurar;
EditText IP;
Button boton;
TCPMasterConnection con = null; //the TCP connection
ModbusTCPTransaction trans = null; //the Modbus transaction
InetAddress addr = null; //direccion del esclavo
int port = Modbus.DEFAULT_PORT;//puerto por defecto 502
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.lblRegistro);
IP = (EditText) findViewById(R.id.txtIp);
depurar = (TextView) findViewById(R.id.txtdepurar);
boton = (Button)findViewById(R.id.btnVerRegistro);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
protected void onStop() {
super.onStop();
//Close the TCP connection
con.close();
}
public class conectar extends AsyncTask<String,String,Integer>{
protected Integer doInBackground(String... urls) {
try {
text.setText("Entro en el try");
//IP address;
addr = InetAddress.getByName("212.170.50.238");
// Open the connection
con = new TCPMasterConnection(addr);
con.setPort(port);
con.connect ();
} catch (Exception e) {
Log.d("MODBUS","connection error", e);
depurar.setText("no conecta");
return 1;
}
return 0;
}
protected void onPostExecute(Integer bytes) {
depurar.setText("conecta");
}
}
public void onClick(View v) {
conectar conectamos = new conectar();
conectamos.execute("hola");
}
see any errors?
We can't touch UI during onBackground()
depurar.setText("no conecta");
Use UI thread or put it on onPost().

Categories

Resources