I am working on a chat application. Currently i did like that when i open the ChatActvity, all sockets are registered and the chatting works... Now i want to change the coding structure.. I want to open the sockets in a class, not in Activity class and i need to add a listener to that class. How i implement this..?
private class Chatroom {
private static void initialise() {
// Initialising the sockets and registering listeners to each socket
}
}
I want to notify in my activity class when the socket listeners in the Chatroom class get called..
here is probably what you need :
public class RequestSender extends AsyncTask<String, Void, String> {
private final static String serverIP = "192.168.1.1";
private final static Integer serverPort = 1234;
private ServerResponseListener listener = null;
public void setServerResponseListener(ServerResponseListener listener){
this.listener=listener;
}
public interface ServerResponseListener {
public void onResponseReceive(String response);
}
#Override
protected String doInBackground(String... params) {
Socket socket = null;
try {
socket = new Socket(serverIP, serverPort);
} catch (IOException e) {
// return "server is unreachable" message or something
}
PrintWriter requestWriter = new PrintWriter(socket.getOutputStream());
BufferedReader resultReader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
String request = params[0] //for example
requestWriter.println(request);
requestWriter.flush();
String result = null;
while ((result = resultReader.readLine()) != null) {}
return result;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
listener.onResponseReceive(result);
}
}
here is example how to execute AsynchTask from Activity :
public class MainActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RequestSender requestSender = new RequestSender();
requestSender.setServerResponseListener(new RequestSender.ServerResponseListener(){
#override
public void onResponseReceive(String response){
//
}
});
requestSender.execute("message");
}
}
read this : http://developer.android.com/reference/android/os/AsyncTask.html
Related
I have declared a private field in the MainActivity Class with getter and setter method. Now I want to setText from another class in this field. But after running the device the app is crushing. I want to fetch some json data by using this code. I am not getting how to call this field from another class and how to set the value to run the app smoothly. My code looks like this.
public class MainActivity extends AppCompatActivity {
private TextView tvData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnHit=(Button)findViewById(R.id.btnHit);
tvData=(TextView)findViewById(R.id.tvJsonItem);
btnHit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
JSONTask jsonTask=new JSONTask("https://jsonparsingdemo-cec5b.firebaseapp.com/jsonData/moviesDemoItem.txt"); //error showing this cannot be applied
jsonTask.execute();
}
});
}
The another class is
public class JSONTask extends AsyncTask<String,String,String>{
private TextView tvData;
public JSONTask(TextView tvData) {
this.tvData =tvData;
}
#Override
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(params[0]);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
tvData.setText(result);
}
}
Make your AsyncTask like this:
class JSONTask extends AsyncTask<String ,String,String>{
private TextView textView;
public JSONTask(TextView textView) {
this.textView = textView;
}
#Override
protected String doInBackground(String... params) {
return null;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
textView.setText(s);
}
}
now call this class from MainActivity
JSONTask jsonTask = new JSONTask(yourTextView);
jsonTask.execute();
Hope it will work for you .
#override
protected void onPostExecute(String result){
super.onPostExecute(result);
new MainActivity().setTvData().setText(result);
Use setTvData().setText() to set the value if you only one data in your json string .
I would like to modify dynamically an ImageView (setImageResource) in ServerSocket
I used :
public class MainActivity extends AppCompatActivity {
private SocketServer server;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
server = new SocketServer(MainActivity.this);
}
}
public class SocketServer {
private final Context context;
public SocketServer(Context context) {
this.context = context;
new Thread(new SocketServerThread()).start();
}
private class SocketServerThread implements Runnable {
private String read;
private BufferedInputStream reader = null;
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress("192.168.1.1", 11000));
while (true) {
Socket socket;
socket = serverSocket.accept();
//On attend la demande du client
reader = new BufferedInputStream(socket.getInputStream());
read = Strings.getBuffered(reader);
((Activity) context).runOnUiThread(new Runnable() {
final ImageView ls_fp = (ImageView) ((Activity) context).findViewById(R.id.ls_fp);
#Override
public void run() {
if(read != "1")
ls_fp.setImageResource(R.mipmap.ls_fp_light);
else
ls_fp.setImageResource(R.mipmap.ls_fp);
}
});
}
} catch (IOException e) {
Log.e(Log.TAG.SOCKETSERVER, "SocketServerThread", e);
}
}
}
}
And this code work perfectly fine
But, when in change to another activity and i rerun activity base, the image source not change.
Could you help me ?
I'm trying to make a simple app that sends a message taken from an EditText,
using the Java Socket class. I'm trying with AsyncTask, but it works only once and I can't return the socket for reuse in another instance of the class.
Can you give me an example of a background service that opens a communication with a server and returns the Socket?
EDIT:
As required by nandsito; I intend to open a connection using a Button, so this button calls a beckground process that creates the connection with the server, finally returns the Socket. When I press another Button I want to start another task that reuses sockets, write data (for example Sring) receive a response from the server and updates the UI.
It looks simple but I think you have an interesting and challenging problem. If you want to keep the socket open after sending messages through it, you'll need to maintain one or more threads to use that socket because, you know, Android doesn't allow networking on main thread.
Multithread programming is seldom simple and often there is more than one way to do it. E.g. in Android you can use Handlers with Loopers from HandlerThreads, or the classic Java Thread. And also AsyncTask, but I think it doesn't fit this case.
How do you intend to manage the socket lifecycle (i.e. when is it opened or closed), and in which moments is data read/written from/into the socket? Please explain better the matter so I can suggest an implementation.
EDIT
Here's an example Activity with two buttons. One button runs an AsyncTask that creates a socket and its streams, and the other button runs another AsyncTask that writes data into the socket. It's an oversimplified solution, but it should work. Note that the code needs synchronization, for different threads access the socket.
public class MainActivity extends Activity {
private SocketContainer mSocketContainer;
private final Object mSocketContainerLock = new Object();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// onClick attribute of one button.
public void onClickPushMe(View view) {
String serverAddress;
int serverPort;
new CreateSocketAsyncTask(serverAddress, serverPort).execute();
}
// onClick attribute of other button.
public void onClickPushMeToo(View view) {
String text;
new WriteSocketAsyncTask(text).execute();
}
// Class that contains the socket and its streams,
// so they can be passed from one thread to another.
private class SocketContainer {
private Socket mSocket;
private InputStream mSocketInputStream;
private OutputStream mSocketOutputStream;
private SocketContainer(Socket socket, InputStream socketInputStream, OutputStream socketOutputStream) {
mSocket = socket;
mSocketInputStream = socketInputStream;
mSocketOutputStream = socketOutputStream;
}
private Socket getSocket() {
return mSocket;
}
private InputStream getSocketInputStream() {
return mSocketInputStream;
}
private OutputStream getSocketOutputStream() {
return mSocketOutputStream;
}
}
// AsyncTask that creates a SocketContainer and sets in into MainActivity.
private class CreateSocketAsyncTask extends AsyncTask<Void, Void, SocketContainer> {
private final String mServerAddress;
private final int mServerPort;
private CreateSocketAsyncTask(String serverAddress, int serverPort) {
mServerAddress = serverAddress;
mServerPort = serverPort;
}
protected SocketContainer doInBackground(Void... params) {
try {
Socket socket = new Socket(mServerAddress, mServerPort);
return new SocketContainer(socket, socket.getInputStream(), socket.getOutputStream());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#Override
protected void onPostExecute(SocketContainer socketContainer) {
super.onPostExecute(socketContainer);
synchronized (mSocketContainerLock) {
mSocketContainer = socketContainer;
}
}
}
private class WriteSocketAsyncTask extends AsyncTask<Void, Void, Void> {
private final String mText;
private WriteSocketAsyncTask(String text) {
mText = text;
}
#Override
protected Void doInBackground(Void... params) {
synchronized (mSocketContainerLock) {
try {
mSocketContainer.getSocketOutputStream().write(mText.getBytes(Charset.forName("UTF-8")));
mSocketContainer.getSocketOutputStream().flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return null;
}
}
}
With this code i connect to a chat, so you can use it similliary to connect with what you want
public class SocialConnectionManager extends AsyncTask<Void, Void, Void> {
public static final int SQL_STEP_LOGIN = 0;
public static final int SQL_STEP_LOGOUT = 1;
public static final int SQL_STEP_SEND = 2;
public static final int SQL_STEP_UPDATE = 3;
final int serverPort = 8080;
private String message, channel, userName, serverIp;
private int step;
private long uniqueId;
private Activity activity;
public SocialConnectionManager(String serverIp, long uniqueId, int step, String userName,
String channel, String message, Activity activity) {
this.message = message;
this.step = step;
this.uniqueId = uniqueId;
this.channel = channel;
this.userName = userName;
this.serverIp = serverIp;
this.activity = activity;
}
#Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
try {
socket = new Socket(serverIp, serverPort);
DataOutputStream dataOut = new DataOutputStream(socket.getOutputStream());
switch (step) {
case SQL_STEP_LOGIN:
dataOut.writeInt(step);
dataOut.writeLong(uniqueId);
dataOut.writeUTF(channel);
dataOut.writeUTF(userName);
break;
case SQL_STEP_LOGOUT:
dataOut.writeInt(step);
dataOut.writeLong(uniqueId);
dataOut.writeUTF(channel);
dataOut.writeUTF(userName);
break;
case SQL_STEP_SEND:
long messageId = createRandomId();
messageIds.add(messageId);
dataOut.writeInt(step);
dataOut.writeLong(uniqueId);
dataOut.writeUTF(channel);
dataOut.writeUTF(userName);
dataOut.writeUTF(message);
dataOut.writeLong(messageId);
break;
case SQL_STEP_UPDATE:
dataOut.writeInt(step);
dataOut.writeUTF(message);
break;
}
dataOut.flush();
} catch (UnknownHostException e) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
((MainActivity) activity).showNetworkAlertDialog(context.getString
(R.string.social_chat_connection_failed));
}
});
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
}
private class ReceiveTask extends AsyncTask {
final int clientPort = 5050;
#Override
protected Object doInBackground(Object[] params) {
try {
serverSocket = new ServerSocket(clientPort);
while (true) {
final Socket socket = serverSocket.accept();
DataInputStream dataIn = new DataInputStream(socket.getInputStream());
final int step = dataIn.readInt();
final int userCount = dataIn.readInt();
final String message = dataIn.readUTF();
final String userName = dataIn.readUTF();
switch (step) {
case SocialConnectionManager.SQL_STEP_LOGIN:
if (isLogging) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
showProgress(false);
}
});
isLogging = false;
isLoggedIn = true;
}
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
userCountView.setText(Integer.toString(userCount));
addMessage(message, userName, step);
}
});
break;
case SocialConnectionManager.SQL_STEP_LOGOUT:
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
addMessage(message, userName, step);
}
});
break;
case SocialConnectionManager.SQL_STEP_SEND:
messageId = dataIn.readLong();
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
addMessage(message, userName, step);
}
});
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
BroadcastReceiver networkStateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String ip = getIpAddress();
if (ip.equals("")) {
((MainActivity) activity).showNetworkAlertDialog(context.getString
(R.string.social_chat_connection_lost));
} else if (!deviceIp.equals(ip)) {
SocialConnectionManager socialConnectionManager =
new SocialConnectionManager(serverIp, 0,
SocialConnectionManager.SQL_STEP_UPDATE, null, null, deviceIp,
activity);
socialConnectionManager.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
};
}
Async task is not worthy for the real time chat.
Get into firebase to use the things easy.
This might help you-
https://www.firebase.com/docs/android/examples.html
I am currently trying to make an android app that basically downloads strings from a url. But I want to make it object oriented. My mainActivity gets string from webService which downloads string when button is clicked. But I am not good at interfaces and callbacks. What should I do to make this code run?
public class MainActivity extends Activity implements WebServiceInterface{
private TextView textView;
private Button readWebPage;
private WebService service;
private WebServiceInterface webServiceInterface;
private String response;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.TextView01);
readWebPage = (Button) findViewById(R.id.readWebpage);
service = new WebService();
readWebPage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
service.execute(new String[]{"http://google.com/"});
onSuccess(response);
}
});
}
#Override
public void onSuccess(String response) {
textView.setText(Html.fromHtml(response));
}
#Override
public void onFail(Exception ex) {
textView.setText(ex.getLocalizedMessage());
}
}
public class WebService extends AsyncTask<String, Void, String> {
private WebServiceInterface webServiceInterface;
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
webServiceInterface.onSuccess(response);
} catch (Exception e) {
e.printStackTrace();
webServiceInterface.onFail(e);
}
}
return response;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
public interface WebServiceInterface {
void onSuccess(String response);
void onFail(Exception ex);
}
you need to create one public method for set webServiceInterface in WebService class like
public setWebServiceInterface (WebServiceInterface listener)
{
this.webServiceInterface =listener;
}
in MainActivity activity call this method and pass argument this
service.setWebServiceInterface (this);
in WebService class in onPostExecute Method call
webServiceInterface.onSuccess(s);
Add WebService (WebServiceInterface webServiceInterface) in your AsyncTask as a constructor.
service = new WebService(new WebServiceInterface (){
void onSuccess(String response){
//do your stuff
}
void onFail(Exception ex){
//do your stuff
}
});
and in your asynctask
public class WebService extends AsyncTask<String, Void, String> {
public WebService (WebServiceInterface webServiceInterface){
this.webinterface= webServiceInterface;
}
private WebServiceInterface webinterface;
#Override
protected String doInBackground(String... urls) {
String response = "";
for (String url : urls) {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
webinterface.onSuccess(response);
} catch (Exception e) {
e.printStackTrace();
webinterface.onFail(e);
}
}
return response;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
}
I have found the problem, it is because of runOnUiThread is missing.
MainActivity.java
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Client client = new Client();
try {
client.connect("192.168.1.10",5555);
} catch (IOException e) {
e.printStackTrace();
}
}
public void displayServerAnswer(String answer){
TextView textView = (TextView)findViewById(R.id.mainTextView);
textView.setText(answer);
}
...
Client.java
import java.net.Socket;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Observable;
public class Client extends Observable implements Runnable {
private Socket socket;
private BufferedReader br;
private PrintWriter pw;
private boolean connected;
private int port=5555; //default port
private String hostName="localhost";//default host name
public Client() {
connected = false;
}
public void connect(String hostName, int port) throws IOException {
if(!connected)
{
this.hostName = hostName;
this.port = port;
socket = new Socket(hostName,port);
//get I/O from socket
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
pw = new PrintWriter(socket.getOutputStream(),true);
connected = true;
//initiate reading from server...
Thread t = new Thread(this);
t.start(); //will call run method of this class
}
}
public void sendMessage(String msg) throws IOException
{
if(connected) {
pw.println(msg);
} else throw new IOException("Not connected to server");
}
public void run() {
String msg = ""; //holds the msg recieved from server
try {
while(connected && (msg = br.readLine())!= null)
{
//In Here I want to call MainActivity.displayServerAnswer()
//notify observers//
this.setChanged();
//notify+send out recieved msg to Observers
this.notifyObservers(msg);
}
}
catch(IOException ioe) { }
finally { connected = false; }
}
...
}
In the place I specified, I want to be able to display the server answer.
How can I get access to MainActivity instance that created client object, in order to call its method?
#hopia answer is pretty good. you also can implement the Listener Design pattern
public class Client extends Observable implements Runnable {
public interface ClientListener {
public void onAction();
}
private ClientListener mListener;
public Client(ClientListener listener) {
mListener = listener;
}
public class MainActivity extends ActionBarActivity implements ClientListener {
#Override
public void onAction(){
....do whatever you need
}
...
}
You can pass an acvtivity reference to your client in either a constructor or a set accessor method.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Client client = new Client(this);
try {
client.connect("192.168.1.10",5555);
} catch (IOException e) {
e.printStackTrace();
}
}
And in your java object:
MainActivity activity;
public Client(MainActivity activity) {
connected = false;
this.activity = activity;
}
...
public void run() {
String msg = ""; //holds the msg recieved from server
try {
while(connected && (msg = br.readLine())!= null)
{
//In Here I want to call MainActivity.displayServerAnswer()
activity.displayServerAnswer();
//notify observers//
this.setChanged();
//notify+send out recieved msg to Observers
this.notifyObservers(msg);
}
}
catch(IOException ioe) { }
finally { connected = false; }
}
How about passing the activity instance as an argument to the Client's constructor?
// MainActivity
Client client = new Client(this);
// Client
public Client(Activity activity) {
this.activity = activity;
connected = false;
}