I have an application in which there is Google map, location overlays on Google map and a separate thread which send the current location of device to server after every 30 seconds. The problem is that when the thread sends the location to server the screen of device halted until the server respond. Here is the following code,
Global Object
private Handler handlerTimer = new Handler();
In onCreate Method
handlerTimer.removeCallbacks(taskUpdateStuffOnDialog );
handlerTimer.postDelayed(taskUpdateStuffOnDialog , 100);
And here is the taskUpdateStuffOnDialog
private Runnable taskUpdateStuffOnDialog = new Runnable()
{
public void run()
{
try
{
URL url3 = new URL("http://"+ appState.getURL()+"//iLocator/IDForClient.php?reg_no="+ Device_ID[0]);
HttpURLConnection conn = (HttpURLConnection) url3.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String quote = reader.readLine();
while (quote != null)
{
Device_ID = quote.split("\n");
quote = reader.readLine();
bCheckID = true;
}//End While
positionOverlay.setID(Device_ID[0]);
addEvent(Device_ID[0]);
}//End try
catch (Exception e)
{
e.printStackTrace();
Toast.makeText(MainMapActivity.this, "Communication Issue",Toast.LENGTH_LONG).show();
}//End catch
handlerTimer.postDelayed(this, 9000);
}
};
Please tell me what is wrong with my code.
The problem is that, although you're spawning a new Thread, you aren't spawning a new process. Everything you're doing is still in the user interface process, and that's blocking. You can find more information on the topic on developer.android.com.
The quickest and easiest way to get around this is using the IntentService class. It will only allow one HTTP request to be executed at a time, but will take care of all the problems for you.
Try using the AsyncTask for connecting to the Server. See an example here: http://developer.android.com/reference/android/os/AsyncTask.html
Related
I'm developing an Android application for in-house of a certain company, and it needs to log the working time of employees. Therefore, the work with system time is crucial. My application badly needs to know when the user changes the system time. Big deal, you say, see this: Is there a way to detect when the user has changed the clock time on their device?
The problem is that the user may circumvent that solution by doing Force Stop of the application prior to changing the time. The application then won't receive system notification, which is brilliantly described here: https://stackoverflow.com/a/19856367/1309803
I don't mind checking that upon the next launch of the application, but how can I possibly know if the user has changed the time? I'm aware about SystemClock.elapsedRealtime(). I could figure time shift based on delta of those values provided that the user hasn't reboot the device, but this is what I'm unsure of. My application is subscribed to BOOT_COMPLETED event, but that one won't be received either while the application is in stopped state.
And, to cap it all, employees of that company are supposed to work in condition of having no network access, so I can't rely on Web servers. So is there any other possible approach?
Getting the time from the third-party servers is not reliable most of the times and some of them are paid services.
If you want to get the exact time and check with the phone whether it is correct or not, irrespective of the proper way, you can use the following simple trick to get the actual time.
private class GetActualTime extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
try {
HttpURLConnection urlConnection = null;
StringBuilder result = new StringBuilder();
try {
URL url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
int code = urlConnection.getResponseCode();
if (code == 200) {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = bufferedReader.readLine()) != null)
result.append(line);
in.close();
}
else {
return "error on fetching";
}
return result.toString();
} catch (MalformedURLException e) {
return "malformed URL";
} catch (IOException e) {
return "io exception";
} finally {
if (urlConnection != null) {urlConnection.disconnect();
}
}
} catch (Exception e) { return "null"; }
}
#Override
protected void onPostExecute(String time) {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat mdformat = new SimpleDateFormat("h:mm");
String times = mdformat.format(calendar.getTime());
try {
String areatime = time.substring(time.indexOf(String.valueOf(times)), time.indexOf(String.valueOf(times)) + 5).trim();
Toast.makeText(this, "The actual time is " + areatime, Toast.LENGTH_SHORT).show();
}
catch(IndexOutOfBoundsException e){
Toast.makeText(this, "Mobile time is not same as Internet time", Toast.LENGTH_SHORT).show();
}
}
}
}
Call the class in the onCreate();
new GetActualTime().execute("https://www.google.com/search?q=time");
So this is actually getting the time from Google. This works pretty awesomely in my projects. In order to check whether the system time is wrong, you can use this trick. Instead of depending on the time servers, you can trust Google.
As it is more sensitive in checking, even a minute ahead or lag will catch the exception. You can customise the code if you want to handle that.
I'm porting some of my Windows Phone 7 apps to Android. When we call services in the WP7 world, the calls are async. We call the service and there is a delegate _completed event that triggers when when the result is returned. Meanwhile we go on about our way.
The java android code pasted below is how I am calling an HTTP service on my cloud server. I developed this code by going through Android tutorials teaching how to call a service in the android world. Apparently, service calls here are synchronus so the instruction starting with InputStream in... doesn't get executed until the result is returned.
Is this how it is supposed to work for Android? If the service does not respond, there is a wait of a couple minutes and then a timeout exception takes place. That's no good. Everything will hang.
What is the reccommended way to call services in android?
Thanks, Gary
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
HttpURLConnection urlConnection = null;
try
{
URL url = new URL("http://www.deanblakely.com/REST/api/products");
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
String myString = readStream(in);
String otherString = myString;
otherString = otherString + " ";
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
urlConnection.disconnect();
}
}
Is this how it is supposed to work for Android?
Yes. Do HTTP operations in a background thread, such as the one supplied by an AsyncTask.
If the service does not respond, there is a wait of a couple minutes and then a timeout exception takes place. That's no good. Everything will hang.
You can set a socket timeout to be something shorter than "a couple minutes". For example, you can call setReadTimeout() on your HttpURLConnection to specify a timeout period in milliseconds.
for simplicity purpose of demonstrating on how socket programming works in the Android platform, I want to develop a simple socket program without thread/asyntask and also (if possible) without exception caught. Is that possible? I've tried but it doesn't works (as pointed by many others that socket is better to be run at other thread).
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.TextView01);
tv.setText("Nothing from client yet");
}
public Void handleOnClick(View v) {
Socket s = null;
try {
ss = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
try {
s = ss.accept();
BufferedReader input = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String st = null;
st = input.readLine();
mClientMsg = st;
} catch (IOException e) {
e.printStackTrace();
}
}
You can develop anything without using AsyncTask, but I definitely don't recommend it as your application would block until the tasks completes (as I'm sure you already know)! In this case, your socket would need to response fast enough so that the OS doesn't kill your process (see discussions on ANR here).
You will have to handle the Exceptions at one point or another. The best you can do is have your methods throw the exceptions and handle them wherever the method gets called, but this doesn't mean you won't have to handle them; this will just delay them.
public Void handleOnClick(View v) throws IOException {
Socket s = null;
ss = new ServerSocket(SERVERPORT);
s = ss.accept();
BufferedReader input = new BufferedReader(
new InputStreamReader(s.getInputStream()));
String st = null;
st = input.readLine();
mClientMsg = st;
}
If this is meant to be an example or demonstration for others, it should be well structured so that people learn to do things correctly. I would strongly encourage you to consider handling the exceptions where they should be handled (or throw more meaningful exceptions up the chain). Further, if you're teaching a class or an individual these things, you should demonstrate, at one point or another, how to avoid getting slapped with an ANR.
After reading a few posts and reading on the developers page about ASYNCTASK, I came up with the following code, and assigned it to a button:
private class TalkToServerTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String response = "";
try {
InetAddress serverAddr = InetAddress.getByName(params[0]);
Socket s = new Socket(serverAddr, Integer.valueOf(params[1]));
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(s.getOutputStream())), true);
// WHERE YOU ISSUE THE COMMANDS
out.println(params[2]);
// BufferedReader input = new BufferedReader(
// new InputStreamReader(s.getInputStream()));
DataInputStream dataInputStream = null;
dataInputStream = new DataInputStream(s.getInputStream());
st = dataInputStream.readLine().toString();
// String st = s.readLine();
// st = input.readLine();
// read line(s)
s.close();
return st;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return response;
}
#Override
protected void onPostExecute(String result) {
serverresponse = result;
}
}
The idea being, that when a button is clicked, the ASyncTask sends the word "getDomains" to a console app running on my server, the server acts on this and sends back a string with the list of domains created on an email server.
I have verified that the server is receiving the command "getdomains", and it in turn replies with a pipe-delimited string of domains. The problem being however, that I've set a Toast to pop up with the results of the socket transaction, and the toast shows nothing. If I hit the button again, the Toast shows the list of domains. To me, it seems as if the socket is first returning an empty
Here is the button code:
case R.id.btnDomains:
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(this);
IpAddress = sp.getString("ipaddress", "0.0.0.0");
Serverport = sp.getString("tcpport", "12345");
buttonpressed = "domains";
// TalkToServerTask task = new TalkToServerTask();
new TalkToServerTask().execute(IpAddress, Serverport, "getDomains");
Intent buttonActivity = new Intent(MainActivity.this, Rules.class);
buttonActivity.putExtra(MainActivity.DOMAINLIST, serverresponse);
Toast.makeText(getApplicationContext(), serverresponse,
Toast.LENGTH_SHORT).show();
the variable "serverresponse" is what at first is showing empty, but then shows the list of servers.
As Thepoosh mentioned, AsyncTask is working on a separate thread.
Therefore the thread is being executed and didn't get result yet when you first time press the button.
What you should do is to show the data in onPostExecute method. Also you should pass the context to your AsyncTask.
public TalkToServerTask(Context context) {
this.context = context;
}
#Override
protected void onPostExecute(String result) {
Intent buttonActivity = new Intent(context, Rules.class);
buttonActivity.putExtra(MainActivity.DOMAINLIST, result);
Toast.makeText(context.getApplicationContext(), result, Toast.LENGTH_SHORT).show();
}
You just need to change your code a little,
You need to move this 3 lines,
Intent buttonActivity = new Intent(MainActivity.this, Rules.class);
buttonActivity.putExtra(MainActivity.DOMAINLIST, serverresponse);
// and also the line to startActivity() as well.
Toast.makeText(getApplicationContext(), serverresponse,
Toast.LENGTH_SHORT).show();
from your Switch..case to onPostExecute of the AsyncTask where you have written serverresponse = result
That's because the AsyncTask run in a different thread, while you have executed in Swtich...case it's not like that the next line of code will not get executed untill the AsyncTask finishes, So all dependent code should be written in onPostExecute of the Task.
AsynTask is run on a separate thread from the UI thread. So there are 2 threads running parallel. While you are trying to display the list in a toast on main UI thread, the AsynTask is still preparing to fetch the list, or probably creating sockets in its own thread. Hence the list data is still empty.
The postexecute method of Asynctask is run on the main UI thread, so its safe and correct to update the UI in it.
Im having some trouble reading/writing to a tcp server for which im building an app. In a recent thread I was suggested to use a service instead but this is a project for school which suggested asyncTask so I might aswell go for that.
So the classes ive got are my activity class and async, nothing interesting is going on in activity but sending a string which is working so ill get on with the async one.
class ServerTask extends AsyncTask<Void, Void, Void>{
public static String ip = "10.0.2.2";
public static int port = 2002;
Socket socket;
public DataInputStream dis;
public DataOutputStream dos;
public String message;
#Override
protected Void doInBackground(Void... params) {
try {
socket = new Socket(ip, port);
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
} catch (Exception e) {
Log.i("AsyncTank", "Cannot create Socket");
}
while(socket.isConnected()){
read();
}
}
}
return null;
}
public void write(String message) {
try {
if (socket.isConnected()){
dos.writeUTF(message);
dos.flush();
} else {
Log.i("AsynkTask", "Socket appears to be closed");
}
} catch (Exception e) {
Log.i("AsynkTask", "Writing failed");
}
}
public String read() {
try {
if (socket.isConnected()) {
message = dis.readLine();
} else {
Log.i("AsyncTask", "Cannot read");
}
} catch (Exception e) {
Log.i("AsyncTask", "Cannot read from stream");
}
return message;
}
}
Things I do know, the server DOES get the messages but it doesnt update until I restart the server which leads me to believe that im not pushing a new line or something which makes it all appear as one line after its closed. This however might aswell be the server for which im not reponsible so ill have to read up in that.
The read part however does not want to work, im not sure on how to call the method to have it constantly listen and react to the servers sockt? I tried make a thread just before the return in doInBackGround but then the application starts works for a couple of seconds the force closes due to lack of memory? Do I need a thread to keep constantly listen?
The whole point of this as you might guess is to make a chat so the read method is eventually supposed to update a textView in my activity class. The send method is "working" but not as it should though this might be as I said earlier the server doing some funky buisness.
Another one, is it even possible to have the read as a method like I have or does something have to react when the server sends data and then call the method?
Edit
I have now moved the read part, or atleast some of it to doInBackGround so its now
dis = new BufferedReader(new InputStreamReader(socket.getInputStream()));
message = dis.readLine();
Log.i("AsynkTask", "Read : "+message+" this is doInBackGround!");
This along with a change to simply hardcode a printline in the server made me read that line in the client so im guessing its working realtively good for now.
How is it looking? Is it utter crap this code and should be done some other way? Got my functionality but never bad to learn to do it better so to speak :).
You should do both your writing and reading to the Socket in an AsyncTask's doInBackground() method, as both take time and could block the main (UI) thread. I don't know how you are calling your write() method above but you might also want to take a look at this question that might be related.