I'm working in an application which must send a GPS location every 5 seconds to the server when I choose (auto send button on). I'm new with android so I don't know how I can make an on/off button and how can I invoke the method that sends the data every 5 seconds when the button is on.
The method which it must invoke every 5 seconds:
public void postData() throws ClientProtocolException, IOException, Exception {
String longitude="UK";
String latitude="UK";
String altitiude="UK";
String time="";
String speed="";
getCurrentLocation(); // gets the current location and update mobileLocation variables
if (mobileLocation != null) {
locManager.removeUpdates(locListener); // This needs to stop getting the location data and save the battery power.
longitude = ""+mobileLocation.getLongitude();
latitude = "" + mobileLocation.getLatitude();
altitiude = "" + mobileLocation.getAltitude();
String accuracy = "Accuracy" + mobileLocation.getAccuracy();
time = "" + mobileLocation.getTime();
speed =""+ (int)(4*mobileLocation.getSpeed());
editTextShowLocation.setText(longitude + "\n" + latitude + "\n"
+ altitiude + "\n" + accuracy + "\n" + time+ "\n" + speed);
} else {
editTextShowLocation.setText("Sorry, location is not determined");
}
String url = "http://www.itrack.somee.com/post.aspx?id="+"f1"+"&long="+longitude+"&lat="+latitude+"&alt="+altitiude+"&speed="+speed;
// Create a new HttpClient and Post Header
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
try {
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
}
I have faced exactly the same problem, sending location periodically. I've used a handler and its postDelayed method.
The periodic call part of my code looks like this:
private final int FIVE_SECONDS = 5000;
public void scheduleSendLocation() {
handler.postDelayed(new Runnable() {
public void run() {
sendLocation(); // this method will contain your almost-finished HTTP calls
handler.postDelayed(this, FIVE_SECONDS);
}
}, FIVE_SECONDS);
}
Then you just need to call scheduleSendLocation when you want to start your period calls.
Ridcully is right, there is probably no reason to send the current location every 5 seconds. Here is the rational behind that:
You really only care about 2 things about the users location:
Where are they right now?
Have they moved since I got their first location?
So once you get a satisfactory initial location, you can just register to get callbacks whenever the users moves like this:
private LocationListener mLocationListener;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocationListener = new LocationListener() {
#Override
public void onLocationChanged(final Location location) {
updateLocation(location);
}
#Override
public void onStatusChanged(final String provider,
final int status, final Bundle extras) {
}
#Override
public void onProviderEnabled(final String provider) {
}
#Override
public void onProviderDisabled(final String provider) {
}
};
}
That being said, you could obviously do what these others have said and run the timer every 5 seconds. The thing is, most good locations take 10-20 seconds to run, so you might only want to run it in that interval. Also FYI, this WILL kill battery
Look at the AlarmManager class http://developer.android.com/reference/android/app/AlarmManager.html and particularly the setRepeating function. Its going to be a bit more complicated than you'd like though.
You can use a Timer. But I think it would be better if you only send the position of it has changed a certain distance from the last one you sent. This way you'd send way less data without losing any information.
Related
I am building a simple Android app to check if active internet connection is available on my phone. For checking this I am using a service which is running into background every 30 seconds and "pings" the Google's DNS server to check if there is a response.
This is my class used for checking internet status:
public class NetworkStatus {
private static final String GOOGLE_DNS_SERVER = "8.8.8.8";
private static final String CLOUDFLARE_DNS_SERVER = "1.1.1.1";
private static final String TAG = "OUTGOING-NET-STATUS";
private static final String RETRY_TAG = "DNS-CHECK";
boolean pingDnsServerSuccessful() {
boolean success = false;
int count = 0;
final int MAX_TRIES = 15;
while (!success && count++ < MAX_TRIES) {
Log.d(RETRY_TAG, "Retry value: " + count + " out of " + MAX_TRIES);
success = isDnsServerReachable(CLOUDFLARE_DNS_SERVER) || isDnsServerReachable(GOOGLE_DNS_SERVER);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (success) {
Log.d(TAG, "Outgoing Internet Traffic is Enabled");
} else {
Log.d(TAG, "Error reaching Outgoing Traffic");
}
return success;
}
private boolean isDnsServerReachable(String dnsServer) {
int connectionTimeout = 250;
try {
return InetAddress.getByName(dnsServer).isReachable(connectionTimeout);
} catch (Exception e) {
Log.d(TAG, "Exception: Error while pinging " + dnsServer + " DNS server: " + e);
}
return false;
}
}
and this is the code which triggers the background timer within the service:
public void startTimer() {
//set a new Timer
timer = new Timer();
networkStatus = new NetworkStatus();
notificationManager = new NotificationManager();
//initialize the TimerTask's job
initializeTimerTask();
//schedule the timer, to wake up every 30 seconds
timer.schedule(timerTask, 1000, 30000); //
}
/**
* it sets the timer to print the counter every x seconds
*/
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
Log.i("in timer", "in timer ++++ " + (counter++));
if (networkStatus.pingDnsServerSuccessful()) {
Log.i(PING_TAG, "Active Internet Connection");
if (!notificationManager.getLastSentNotificationType().equals(NotificationType.INTERNET_UP)) {
Log.i(NOTIFICATION_TAG, "Internet ON");
notificationManager.sendNotification(getApplicationContext(), NotificationType.INTERNET_UP);
}
} else {
Log.i(PING_TAG, "No Internet Connection");
if (!notificationManager.getLastSentNotificationType().equals(NotificationType.INTERNET_DOWN)) {
Log.i(NOTIFICATION_TAG, "Internet OFF");
notificationManager.sendNotification(getApplicationContext(), NotificationType.INTERNET_DOWN);
}
}
}
};
}
Everything works fine for a random amount of time (minutes/hours) when suddenly the DNS server can't be reached anymore when app is running in background and phone is locked. Activating the phone's screen is immediately resulting into a success while pinging the server.
Here are some logs reflecting the behaviour:
Logs
Does anybody have a clue why is this happening? I highly doubt that Google or Cloudflare DNS server becomes unresponsive...
Many Thanks!
This is Doze mode. To save power, background requests are limited to a small window every 15 minutes or so for requests. In addition, background processes can be killed at any time.
I'm not sure what you're actually trying to do, but there are 100% better ways to do it. For example, JobScheduler allows you to schedule a job to go off only if the internet is connected. No need to ping a server manually, and no need to do all the work to avoid Doze.
I'm working on MapBox off line. The code was OK, able to download map but after adding some peice of code which have nothing to do with the map, the download stop to work and the give an HTTP401 Error.
I've noticed that depending on where you call MapboxAccountManager.start sometimes it fails.
Here's the code:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
DB_Handler db_ansb = new DB_Handler(Init_Carte.this,null,null,1);
// Get data from DB, about the map
HashMap<String, String> data_mapbox = db_ansb.do_get_mapbox(0);
the_mapbox_token = data_mapbox.get("tmapbox_token");
the_mapbox_style = data_mapbox.get("tmapbox_style");
the_mapbox_zoom_min = Integer.parseInt(data_mapbox.get("tmapbox_zoom_min"));
the_mapbox_zoom_max = Integer.parseInt(data_mapbox.get("tmapbox_zoom_max"));
the_mapbox_inter = Double.parseDouble(data_mapbox.get("tmapbox_inter"));
OfflineManager offlineManager = OfflineManager.getInstance(this);
MapboxAccountManager.start(this,the_mapbox_token);
setContentView(R.layout.activity_init_carte);
// Menu with APP compat
// https://developer.android.com/training/appbar/setting-up.html
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
// Find our truck GPS position for road map
HashMap<String, String> my_truck = db_ansb.do_get_my_truck();
String str_truck_lagps = my_truck.get("frota_lagps");
String str_truck_logps = my_truck.get("frota_logps");
the_lagps_truck = Double.parseDouble(str_truck_lagps);
the_logps_truck = Double.parseDouble(str_truck_logps);
// Find accident location for road map
HashMap<String, String> my_inter = db_ansb.do_get_inter_resume();
String str_inter_lagps = my_inter.get("inter_lagps");
String str_inter_logps = my_inter.get("inter_logps");
the_lagps_inter = Double.parseDouble(str_inter_lagps);
the_logps_inter = Double.parseDouble(str_inter_logps);
// Compute area to get
HashMap<String, Double> data_gps_inter = db_ansb.do_get_bounds_inter(the_lagps_inter,the_logps_inter,the_mapbox_inter);
final double inter_lagps_ne = data_gps_inter.get("inter_max_lagps"); // Nord Est
final double inter_logps_ne = data_gps_inter.get("inter_max_logps");
final double inter_lagps_so = data_gps_inter.get("inter_min_lagps"); // Sud Ouest
final double inter_logps_so = data_gps_inter.get("inter_min_logps");
// Display what we're doing
tmp_id_msg = (TextView) findViewById(R.id.txt_action);
tmp_id_msg.setText(R.string.str_telechargement_carte);
// Create zone
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(new LatLng(inter_lagps_ne, inter_logps_ne)) // Northeast
.include(new LatLng(inter_lagps_so, inter_logps_so)) // Southwest
.build();
OfflineTilePyramidRegionDefinition definition = new OfflineTilePyramidRegionDefinition(
the_mapbox_style,
latLngBounds,
the_mapbox_zoom_min,
the_mapbox_zoom_max,
(Init_Carte.this).getResources().getDisplayMetrics().density);
byte[] metadata;
try
{
JSONObject jsonObject = new JSONObject();
jsonObject.put(JSON_FIELD_REGION_NAME, "Carte");
String json = jsonObject.toString();
metadata = json.getBytes(JSON_CHARSET);
} catch (Exception e)
{
Log.e("TAG", "Failed to encode metadata: " + e.getMessage());
metadata = null;
}
// Get data
offlineManager.createOfflineRegion(definition, metadata, new OfflineManager.CreateOfflineRegionCallback()
{
#Override
public void onCreate(OfflineRegion offlineRegion)
{
offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE);
// Monitor the download progress using setObserver
offlineRegion.setObserver(new OfflineRegion.OfflineRegionObserver()
{
#Override
public void onStatusChanged(OfflineRegionStatus status)
{
Log.i("DBUG","onStatusChanged");
// Calculate the download percentage and update the progress bar
double percentage = status.getRequiredResourceCount() >= 0 ?
(100.0 * status.getCompletedResourceCount() / status.getRequiredResourceCount()) :
0.0;
long long_pourcentage = Math.round(percentage);
String str_pourcentage = Long.toString(long_pourcentage)+" %";
// Display on screen
tmp_id_valeur = (TextView) findViewById(R.id.val_action);
tmp_id_valeur.setText(str_pourcentage);
Log.i("DBUG",str_pourcentage+"%");
if (status.isComplete())
{
// OK so now, ask the road
do_get_trajet();
}
}
#Override
public void onError(OfflineRegionError error)
{
// If an error occurs, print to logcat
Log.i("DBUG", "onError reason: " + error.getReason());
Log.e("DBUG", "onError message: " + error.getMessage());
}
#Override
public void mapboxTileCountLimitExceeded(long limit)
{
// Notify if offline region exceeds maximum tile count
Log.i("DBUG", "Mapbox tile count limit exceeded: " + limit);
}
});
}
#Override
public void onError(String error)
{
Log.e("TAG", "Error: " + error);
}
});
}
I enter the Aysnc part, get 3 or 4 times
Log.i("DBUG",str_pourcentage+"%");
with a value of 0% then get I get:
I/System.out: [CDS]rx timeout:10000
D/NativeCrypto: ssl=0x619629c8 sslWrite buf=0x41e60068 len=222 write_timeout_millis=0
D/NativeCrypto: ssl=0x619629c8 sslRead buf=0x41e60068 len=8192,timeo=10000
I/DBUG: onError reason: REASON_OTHER
E/DBUG: onError message: HTTP status code 401
D/com.mapbox.mapboxsdk.http.HTTPRequest: [HTTP] Request with response code = 401: Unauthorized
I've noticed same strange behaviour on another page: depending on the fact you perform or not, action before of after MapboxAccountManager.start(this,the_mapbox_token); it works or not.
Notice the token is correct.
Any idea?
After changing the token in our DB, it was OK but only for a short time: I was able to download 26% of the map and then, I get again the HTTP 401 message...
Found. In fact there is a small mistake in the code that help me understand: how can this code work sometimes, as I call
OfflineManager offlineManager = OfflineManager.getInstance(this);
MapboxAccountManager.start(this,the_mapbox_token);
so as I call the init after the use of the Lib? In fact all example at Mapbox are made with one activity performing all the jobs. So when you have more than one activity using Mapbox, you quickly believe you need to put a MapboxAccountManager.start in each ones. Which is wrong. In that case (more than one activity), you must call MapboxAccountManager.start at App level. Like that:
public class App_Start extends Application
{
#Override
public void onCreate()
{
super.onCreate();
String the_mapbox_token = "pk.eyJ1IjoiYW5.....";
MapboxAccountManager.start(this,the_mapbox_token);
}
public void customAppMethod()
{
// Custom application method
}
}
and add this class at application level on your Manifest:
<application android:icon="#drawable/ic_launcher" android:label="#string/app_name" android:theme="#style/AppTheme" android:name="net.ansb_brasil.xxxx.App_Start">
Concerning the fact the second activity was performing two times the download, it came from the fact the if (status.isComplete()) part of the onStatusChanged() is always called two times. Seems to be a bug in the Lib. On some example at Mapbox, they use a boolean flag in order to avoid taking two times this call in account.
As my first activity was downloading one map and then call a second activity for a second map, this "double call" had as result two call for the second activity and so many troubles.
Hope this will avoid headaches to others
First of all sorry to repost the question as I didn't post my code earlier just written some lines now I am failing to explain.So posting the question again with codes.
I have written a code that will log the acceleromter data and save the data in a csv file. What I need to do is I have to run the acceleromter in background as a service. So,I m done with writing the codes for
1.running the accelerometer,
2.shown the data in textbox,
3.write the data in a csv file.
Things that are left is making it a service. I m giving the code below(Howfar I have done)
#SuppressWarnings("deprecation")
public class AccelerometerVaue extends Activity implements SensorListener {
SensorManager sm = null;
TextView xacc= null;
TextView yacc = null;
TextView zacc = null;
TextView xorient = null;
TextView yorient = null;
TextView zorient = null;
TextView text = null;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sm = (SensorManager) getSystemService(SENSOR_SERVICE);
setContentView(R.layout.activity_main);
xacc = (TextView) findViewById(R.id.xvalue);
yacc = (TextView) findViewById(R.id.yvalue);
zacc = (TextView) findViewById(R.id.zvalue);
xorient = (TextView) findViewById(R.id.xvalues);
yorient = (TextView) findViewById(R.id.yvalues);
zorient = (TextView) findViewById(R.id.zvalues);
}
#SuppressLint("SdCardPath")
public void onSensorChanged(int sensor, float[] values) {
synchronized (this) {
if (sensor == SensorManager.SENSOR_ORIENTATION) {
xorient.setText("Orientation X: " + values[0]);
yorient.setText("Orientation Y: " + values[1]);
zorient.setText("Orientation Z: " + values[2]);
}
if (sensor == SensorManager.SENSOR_ACCELEROMETER) {
// Time now = new Time();
// now.setToNow();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
String currentDateandTime = sdf.format(new Date());
Log.d("Time",currentDateandTime);
xacc.setText("Accel X: " + values[0]);
yacc.setText("Accel Y: " + values[1]);
zacc.setText("Accel Z: " + values[2]);
String res=String.valueOf(currentDateandTime+"#"+values[0])+"#"+String.valueOf(values[1])+"#"+String.valueOf(values[2]);
Log.d("test", res);
CSVWriter writer = null;
try
{
//Log.d("check","pasla");
//Environment.getExternalStorageDirectory().getPath();
writer = new CSVWriter(new FileWriter("/sdcard/AccelData.csv",true), ',');
String[] entries = res.split("#"); // array of your values
writer.writeNext(entries);
//FileWriter
writer.close();
}
catch (IOException e)
{
//error
}
}
}
}
public void onAccuracyChanged(int sensor, int accuracy) {
String tag = null;
Log.e(tag,"onAccuracyChanged: " + sensor + ", accuracy: " + accuracy);
}
#Override
protected void onResume() {
super.onResume();
sm.registerListener(this,
SensorManager.SENSOR_ORIENTATION |
SensorManager.SENSOR_ACCELEROMETER,
SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onStop() {
sm.unregisterListener(this);
super.onStop();
}
}
So, now I need to run a background service which will keep taking accelerometer data in background and also keep saving into that csv file. How can I do this? One more I like to ask is it possible to take the acc data after a certain period of time? Suppose here I m logging all the data continuously which is huge and thew battery drain will be huge. So, I need to implemented the service in such a way so that it will run in background for 15mins and log the data for 10 seconds at the beginning of each minute.
I have just replied to a similar question.
You can use Android's scheduling mechanism, called AlarmManager, to schedule your services.
There is a problem inerent to this approach, though: when the system is in battery-saving sleep state, your service has to acquire a wake lock in order to execute properly, then when finished release the wake lock for the system to go back to sleep state. Implementing this wake lock acquisition/release mechanism is not a trivial task.
I recommend using Commonsware's WakefulIntentService in order to avoid writing your own wake lock acquisition/release mechanism for your service. It's very easy to use. You will basically declare a class that extends the WakefulIntentService class and override its doWakefulWork() method. In that method you will poll for accelerometer data and write it to a file. I'll just let you down in the part of displaying the data in the screen, I don't know how to do that (I suppose you will have to perform a bind to the service though). <:)
I am making an app in which I want to get the current time from internet.
I know how to get the time from the device using System.currentTimeMillis, and even after searching a lot, I did not get any clue about how to get it from internet.
You can get time from internet time servers using the below program
import java.io.IOException;
import org.apache.commons.net.time.TimeTCPClient;
public final class GetTime {
public static final void main(String[] args) {
try {
TimeTCPClient client = new TimeTCPClient();
try {
// Set timeout of 60 seconds
client.setDefaultTimeout(60000);
// Connecting to time server
// Other time servers can be found at : http://tf.nist.gov/tf-cgi/servers.cgi#
// Make sure that your program NEVER queries a server more frequently than once every 4 seconds
client.connect("time.nist.gov");
System.out.println(client.getDate());
} finally {
client.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.You would need Apache Commons Net library for this to work. Download the library and add to your project build path.
(Or you can also use the trimmed Apache Commons Net Library here : https://www-us.apache.org/dist//commons/net/binaries/commons-net-3.6-bin.tar.gz This is enough to get time from internet )
2.Run the program. You will get the time printed on your console.
Here is a method that i have created for you
you can use this in your code
public String getTime() {
try{
//Make the Http connection so we can retrieve the time
HttpClient httpclient = new DefaultHttpClient();
// I am using yahoos api to get the time
HttpResponse response = httpclient.execute(new
HttpGet("http://developer.yahooapis.com/TimeService/V1/getTime?appid=YahooDemo"));
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpStatus.SC_OK){
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
out.close();
// The response is an xml file and i have stored it in a string
String responseString = out.toString();
Log.d("Response", responseString);
//We have to parse the xml file using any parser, but since i have to
//take just one value i have deviced a shortcut to retrieve it
int x = responseString.indexOf("<Timestamp>");
int y = responseString.indexOf("</Timestamp>");
//I am using the x + "<Timestamp>" because x alone gives only the start value
Log.d("Response", responseString.substring(x + "<Timestamp>".length(),y) );
String timestamp = responseString.substring(x + "<Timestamp>".length(),y);
// The time returned is in UNIX format so i need to multiply it by 1000 to use it
Date d = new Date(Long.parseLong(timestamp) * 1000);
Log.d("Response", d.toString() );
return d.toString() ;
} else{
//Closes the connection.
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
}catch (ClientProtocolException e) {
Log.d("Response", e.getMessage());
}catch (IOException e) {
Log.d("Response", e.getMessage());
}
return null;
}
If you don't care for millisecond accuracy, and if you are already using google firebase or don't mind using it (they provide a free tier), check this out: https://firebase.google.com/docs/database/android/offline-capabilities#clock-skew
Basically, firebase database has a field that provides offset value between the device time and the firebase server time. You can use this offset to get the current time.
DatabaseReference offsetRef = FirebaseDatabase.getInstance().getReference(".info/serverTimeOffset");
offsetRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
double offset = snapshot.getValue(Double.class);
double estimatedServerTimeMs = System.currentTimeMillis() + offset;
}
#Override
public void onCancelled(DatabaseError error) {
System.err.println("Listener was cancelled");
}
});
As I said, it will be inaccurate based on network latency.
I think the best solution is to use SNTP, in particular the SNTP client code from Android itself, e.g.:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.1.1_r1/android/net/SntpClient.java/
I believe Android uses SNTP for automatic date/time updates when a cell network is not available (e.g. wifi tablets).
I think it is better then the other solutions because it uses SNTP/NTP rather then the Time protocol (RFC 868) used by the Apache TimeTCPClient. I don't know anything bad about RFC 868, but NTP is newer and seems to have superceeded it and is more widely used. I believe that Android devices that don't have cellular uses NTP.
Also, because it uses sockets. Some of the solutions proposed use HTTP so they will lose something in their accuracy.
You will need to have access to a webservice that provides current time in XML or JSON format.
If you don't find such type of service, you could parse the time from a web page, like http://www.timeanddate.com/worldclock/, or host your own time service on a server using a simple PHP page for example.
Check out JSoup for the parsing of HTML pages.
Nothing from the above worked from me. This is what I ended up with (with Volley);
This example also converts to another timezone.
Long time = null;
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.timeapi.org/utc/now";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = simpleDateFormat.parse(response);
TimeZone tz = TimeZone.getTimeZone("Israel");
SimpleDateFormat destFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
destFormat.setTimeZone(tz);
String result = destFormat.format(date);
Log.d(TAG, "onResponse: " + result.toString());
} catch (ParseException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.w(TAG, "onErrorResponse: "+ error.getMessage());
}
});
queue.add(stringRequest);
return time;
Import Volley in gradle:
compile 'com.android.volley:volley:1.0.0'
There is a clear answer available already in Stackoverflow
https://stackoverflow.com/a/71274296/11789675
Call this url or use as GET API
http://worldtimeapi.org/api/timezone/Asia/Kolkata
the response will be like
{
"abbreviation": "IST",
"client_ip": "45.125.117.46",
"datetime": "2022-02-26T10:50:43.406519+05:30",
}
This thing works best for my apps. I use jsoup to search the google time and gets current time and then I compare the phone time with google time. So if these time are different you can stop user using a dialogbox or alertbox to tell them the times have changed. You can implement in MainActivity to check this condition. Here is a snippet so you get the idea more clearly.
public class HomeActivity extends AppCompatActivity {
//phoneDate and phoneTime to get current phone date and time
String phoneDate = new SimpleDateFormat("dd MMM yyyy ").format(clnd.getTime()).trim();
String phoneTime = new SimpleDateFormat("hh:mm a").format(clnd.getTime()).trim();
String googleDate;
String googleTime ;
#Override
protected void onCreate(Bundle _savedInstanceState) {
super.onCreate(_savedInstanceState);
setContentView(R.layout.home);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
//URL to search time
String url = "https://www.google.co.in/search?q=time";
Document document = Jsoup.connect(url).get();
org.jsoup.select.Elements time = document.getElementsByClass("gsrt vk_bk FzvWSb YwPhnf");
org.jsoup.select.Elements date = document.getElementsByClass("KfQeJ");
Log.d("HTML", "google date" + String.format(date.text()));
Log.d("HTML", "google time" + time.text());
googleDate = date.text().trim();
googleTime = time.text().trim();
//'0'is not present when hour is single digit
char second = googleTime.charAt(1);
if(second == ':'){
googleTime = "0" + googleTime;
}
Log.d("Proper format", "google time" + googleTime);
Log.d("Date", "your current url when webpage loading.." + phoneDate);
Log.d("Time", "your current url when webpage loading.." + phoneTime);
if(googleDate.contains(phoneDate) && googleTime.equals(phoneTime)){
Log.d("Time", "your current url when webpage loading.." + " true");
}else{
Log.d("Time", "your current url when webpage loading.." + " false");
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
I'm using using AsyncTask to download data over internet and I have a little problem. I need to be able to start one AsyncTask a few times, that's why I'm creating a new instance everytime,but the thing that I notice is that it's working without any problem the first three or four times,but after that my AsyncTask is stuck on onPreExecute() and doing nothing after that. Am I doing something wrong ? (Actually I am using two AsyncTasks one after another just for testing purposes). Here is the sample code which I'm using :
this is how I start the AsyncTasks :
if (index == 1) {
//Login - first way
new FirstSync().execute(Synchronization.this);
} else if (index == 2) {
//SyncWithHash - second way
SyncWithHash syncHash = new SyncWithHash();
syncHash.execute(Synchronization.this);
} else if (index == 3) {
//Deactivate Collection - third way
deactivateColl = new DeactivateCollection();
deactivateColl.execute(Synchronization.this);
}
I did try with three different ways to start the asyncTask,but no change. Here is my AsyncTask :
// Sync With Hash
public class SyncWithHash extends AsyncTask <Context, Integer, Void> {
#Override
protected Void doInBackground(Context... arrContext) {
try {
String charset = "UTF-8";
hash = getAuthHash();
SharedPreferences lastUser = PreferenceManager.getDefaultSharedPreferences(Synchronization.this);
int userId = lastUser.getInt("lastUser", 1);
systemDbHelper = new SystemDatabaseHelper(Synchronization.this, null, 1);
systemDbHelper.initialize(Synchronization.this);
String sql = "SELECT dbTimestamp FROM users WHERE objectId=" + userId;
Cursor cursor = systemDbHelper.executeSQLQuery(sql);
if (cursor.getCount() < 0) {
cursor.close();
} else if (cursor.getCount() > 0) {
cursor.moveToFirst();
timeStamp = cursor.getString(cursor.getColumnIndex("dbTimestamp"));
Log.d("", "timeStamp : " + timeStamp);
}
String query = String.format("debug_data=%s&"
+ "client_auth_hash=%s&" + "timestamp=%s&"
+ "client_api_ver=%s&"
+ "set_locale=%s&" + "device_os_type=%s&"
+ "device_sync_type=%s&"
+ "device_identification_string=%s&"
+ "device_identificator=%s&" + "device_resolution=%s",
URLEncoder.encode("1", charset),
URLEncoder.encode(hash, charset),
URLEncoder.encode(timeStamp, charset),
URLEncoder.encode(clientApiVersion, charset),
URLEncoder.encode(locale, charset),
URLEncoder.encode(version, charset),
URLEncoder.encode("14", charset),
URLEncoder.encode(version, charset),
URLEncoder.encode(deviceId, charset),
URLEncoder.encode(resolution, charset));
SharedPreferences useSSLConnection = PreferenceManager
.getDefaultSharedPreferences(Synchronization.this);
boolean useSSl = useSSLConnection.getBoolean("UseSSl", true);
if (useSSl) {
UseHttpsConnection(url, charset, query);
} else {
UseHttpConnection(url, charset, query);
}
} catch (Exception e2) {
e2.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Integer... progress) {
//cancelDialog.setProgress(progress[0]);
}
#Override
protected void onCancelled() {
Log.d("","ON CANCELLED");
}
#Override
protected void onPreExecute()
{
Log.d("","ON PRE EXECUTE");
// myProgress = 0;
}
#Override
protected void onPostExecute(Void v) {
Log.d("","ON POST EXECUTE");
}
}
So any ideas why it's happening and which is the best way to be able to use an AsyncTask a few times without any exceptions and bugs like the one that I get.
And another question : Is there anything in AsyncTask which can cause my connection to be Reset by peer , because I'm getting this error too (not every time).
Thanks a lot!
I think your doInBackground() is hanging. Make log statement when its entered and when its exited and check.
In the old days AsyncTask had a pool of threads, so if a doInBackground() hung, then it didnt affect the other AsyncTasks. That changed AFAIK with Android 2.2 or 2.3 to that a single thread took care of all AyncTasks, one at a time. Therefore, if your doInBackground() is hanging it might affect the next AsyncTasks being started and the will hang right after onPreExecute().
Edit: It was changed from a single thread, to multiple, and then back to a single thread:
http://developer.android.com/reference/android/os/AsyncTask.html#execute%28Params...%29 "When first introduced, AsyncTasks were executed serially on a single background thread. Starting with DONUT, this was changed to a pool of threads allowing multiple tasks to operate in parallel. After HONEYCOMB, it is planned to change this back to a single thread to avoid common application errors caused by parallel execution."
If you really want an indefinite lot of stuff to 'hang' in parralel, then don't use AsyncTask. Use good old threads, which, when they need to update the GUI, fire off a Runnable to be runned on the GUI thread:
Button knap1, knap2, knap3;
...
Runnable r=new Runnable() {
public void run() {
// Do some stuff than hangs
try { Thread.sleep(10000); } catch (InterruptedException ex) {}
System.out.println("færdig!");
// Update GUI thread
Runnable r2=new Runnable() {
public void run() {
knap3.setText("færdig!");
}
};
runOnUiThread(r2);
}
};
new Thread(r).start();
(example from http://code.google.com/p/android-eksempler/source/browse/trunk/AndroidElementer/src/eks/asynkron/Asynkron1Thread.java?spec=svn109&r=109)
It might be happening because you are synchronizing on an object "Synchronization.this'.
Also noticed you are not closing the cursor which you opened.