Problem with repeating requests in Android application - android

We have a problem with repeating requests. Our application (for Android) makes very simple requests to API (Ubuntu + Nginx). We have recently noticed in our logs and the Nginx server logs that very often (even 10% of users which means thousands in ou case) a single call (but not only, because it can also be a group of requests) is often called by the application even tens of thousands of times, it looks e.g. yes:
/api/v1/endpoint1 10:00:00
/api/v1/endpoint1 10:00:00
/api/v1/endpoint1 10:00:01
/api/v1/endpoint1 10:00:01
/api/v1/endpoint1 10:00:02
/api/v1/endpoint1 10:00:02
/api/v1/endpoint1 10:00:02
/api/v1/endpoint1 10:00:00
(20,000 requests)
We also noticed several groups of requests
/api/v1/endpoint1 10:00:00
/api/v1/endpoint2 10:00:00
/api/v1/endpoint3 10:00:01
/api/v1/endpoint1 10:00:01
/api/v1/endpoint2 10:00:02
/api/v1/endpoint3 10:00:02
/api/v1/endpoint1 10:00:02
/api/v1/endpoint2 10:00:00
/api/v1/endpoint3 10:00:00
It happens tens of thousands of times in a row or only 50 (but also in a row). It affects normal requests made by URLConnection.
In most cases, everything works fine - we make, for example, one request to display the results list so only one request is made. Also, on our test devices we were not able to reproduce it, everything works correctly (so one request). We would be very grateful for any suggestions and ideas how to sort it out because we seem to be at a dead end.
The problem occurs on various devices of different manufacturers, from Adnroid 4 to 9.
Code from activity (cleaned of unnecessary things):
private final ExecutorService executor = Executors.newSingleThreadExecutor();
...
public void onCreate(Bundle savedInstanceState) {
...
changeButton = (Button) findInLayout(R.id.changeButton);
changeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String data1 = data1edit.getText().toString();
final String data2 = data2edit.getText().toString();
executor.execute(new Runnable() {
#Override
public void run() {
boolean isSuccess = false;
HttpURLConnection conn;
try {
conn = (HttpURLConnection) new URL(MY_API_URL).openConnection();
conn.setRequestMethod("POST");
// setup headers, timeouts etc...
conn.setDoOutput(true);
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
writer.write(... some post data ...);
writer.close();
conn.connect();
isSuccess = conn.getResponseCode() == 200;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
}
if (isSuccess) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// show toast with success message + update ui
}
});
} else {
runOnUiThread(new Runnable() {
#Override
public void run() {
// show toast with error message + update ui
}
});
}
}
});
}
});
...
}
Request log screen:

Related

Firebase: Allow access depending on time difference (server-side-time)

So I have a database that looks like this:
Posts
|
|
|----post_id_1
|
|---post_title = "...."
|---post_body = "...."
|---post_time = "ServerValue.TIME_STAMP"
|
|----post_id_2
|.......
|.......
What I want to do:
I want to prevent a user to read a post that is greater than or equal a month from the day that it was posted?
What I tried:
I tried to use this method by android:
//current time of device
long current_time = System.currentTimeMillis();
//month in millisecond
long month = .....;
if(curent_time - post_time >= month){
//this post was there for a month from the time that it was posted.
}
Problem:
If I use the above method then if a user was smart enough he/she will change the time of the device to enter a post (when they shouldn't).
Question:
Any stable way of doing this?
Thanks.
NOTE: WITHOUT GETTING THE TIME STAMP FROM THE SERVER.
I have been through the same issue, how I solved that was pinging Google for the time, and then just store that time in Firebase, that way I can compare the last time the user did something and that time will be server time and can't be changed.
So, in my case I upload that server time each time my app enters in the onStop or onDestroy method, but you can use it anywhere you need to save to your database.
Here is the snippet to get server time, I use an asyncTask in order to fetch the server time and then just post it in my reference. Just call the asyncTask where you want to update something with server time.
public class getGoogleTime extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
try {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = httpclient.execute(new HttpGet("https://google.com/"));
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
DateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z", Locale.ENGLISH);
dateStr = response.getFirstHeader("Date").getValue();
Date startDate = df.parse(dateStr);
dateStr = String.valueOf(startDate.getTime() / 1000);
long actualTime = java.lang.Long.parseLong(dateStr);
//Here I do something with the Date String
} else {
//Closes the connection.
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
} catch (IOException e) {
Log.d("SAF_GTG_Response", e.getMessage());
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
// can use UI thread here
protected void onPostExecute(final Void unused) {
mDatabase.child("Posts").child(post_id_1).child("currentTime").setValue(dateStr, new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
Log.d("SAF_GTG_TAG", "Success");
}
});
}
}
To work with Firebase you can do this:
ref = FirebaseDatabase.getInstance().getReference();
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
Long timestamp = (Long) snapshot.getValue();
System.out.println(timestamp);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
ref.setValue(ServerValue.TIMESTAMP);
NOTE: this method just returns UTC time, you can convert it the way you want to display it to each user.
If you are worried about network usage, just ping Google and see how many bytes and packages are being used.
Pinging google.com [172.217.162.14] with 32 bytes of data:
Reply from 172.217.162.14: bytes=32 time=17ms TTL=53
Reply from 172.217.162.14: bytes=32 time=17ms TTL=53
Reply from 172.217.162.14: bytes=32 time=17ms TTL=53
Reply from 172.217.162.14: bytes=32 time=16ms TTL=53
Ping statistics for 172.217.162.14:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 16ms, Maximum = 17ms, Average = 16ms
From the docs:
The bandwidth consumption of a simple ping command, being run one time
per second, is relatively small. The smallest ping packet possible
(including the Ethernet frame header and the IP + ICMP headers, plus
the minimum 32 bytes of the ICMP payload) takes 74 bytes
around 0,074 kilobytes.
I would store the TIME_STAMP as UTC and get the time from the server, not use the time from the device.
In that case the user cannot change the time on the device to modify the output from the database.
I would recommend to always store all dates as UTC and just convert them to the user timezone when the user views them.

Volley Increasing ThreadPool Size Android

I have this code below which makes 300 http requests and each request returns 10000 rows from database. Total size of 10000 is approximately 0.4mb. So 300*0.4 = 120mb.
Questions:
How increasing the ThreadPool size for handing requests in Volley, can affect the perfomance in app? I change it to 12, but the execution time and size of data was the same as with 4. Is there any difference at all?
When in creasing the number of Volley threads, does the resulted data increase as well? If had 1 thread the maximum returned data each time would be 0.4mb. But if we had 4, the maximum would be 1.6mb.
Emulator: 4 Cores MultiThread
ExecutorService service = Executors.newFixedThreadPool(4);
RequestQueue queue;
AtomicInteger counter = new AtomicInteger(0);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
File cacheDir = new File(this.getCacheDir(), "Volley");
queue = new RequestQueue(new DiskBasedCache(cacheDir), new BasicNetwork(new HurlStack()), 4);
queue.start();
start();
}
public void start(){
String url ="...";
for(int i =0 ; i<300; i++) {
counter.incrementAndGet();
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
method(response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("VolleyError", error.toString());
}
});
stringRequest.setTag("a");
queue.add(stringRequest);
}
}
public synchronized void decreased(){
if(counter.decrementAndGet()==0)
start();
}
public void method( String response){
Runnable task = new Runnable() {
#Override
public void run() {
List<Customer> customers= new ArrayList<>();
ObjectMapper objectMapper = new ObjectMapper();
TypeFactory typeFactory = objectMapper.getTypeFactory();
try {
customers= objectMapper.readValue(response, new TypeReference<List<Customer>>() {});
//Simulate database insertion delay
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
decreased();
} catch (IOException e1) {
e1.printStackTrace();
}
}
};
logHeap("");
service.execute(task);
}
Regarding Question 1:
Thread pool with size 4 will be better when compared to 12.
Thread pool size should be in conjunction with number of processors available.
Since the number of processors are limited, app should not spawn unnecessary threads as this may lead to performance problem. As android OS has to manage resource between more threads which will lead to increased wait and actual time for each thread.
Ideally assuming your threads do not have locking such that they do not block each other (independent of each other) and you can assume that the work load (processing) is same, then it turns out that, have a pool size of Runtime.getRuntime().availableProcessors() or availableProcessors() + 1 gives the best results.
Please refer link Setting Ideal size of Thread Pool for more info.
Regarding question 2: If I have understood your question correctly, there should be no change on returned data as thread pool size has no effect on network payload, only wait time and actual time will be changed, when thread pool size value is changed.

AsyncTask only executing when stepping through in debugger

First off, let me say that I'm just starting my Android adventure and am learning on the code posted below.
So i have a Zebra barcode scanner and an Android device, which is supposed to handle the scanned barcodes. The two devices communicate with each other via BT connection (I got it working). Scanned barcodes are being handled by JsonObjectRequest (also working). Depending on the response (or lack of) from external service, scanner has to react in a certain way:
green/red LED on - beeper - green/red LED off
And here is where I am struggling:
If I have only beeper - everything works. If I have a LED on/off - only LED on works. If I have all 3 actions - none gets executed.
Now, strange thing is, that debugger shows those actions received and executed
D/MainActivity: Barcode Received
I/ViewRootImpl: CPU Rendering VSync enable = false
I/BluetoothScanner: executeCommand started. opcode = DCSSDK_SET_ACTION inXML = <inArgs><scannerID>5</scannerID><cmdArgs><arg-int>45</arg-int></cmdArgs></inArgs>
I/BluetoothScanner: 7 SSI bytes sent: 0x05 0xE7 0x04 0x00 0x04 0xFF 0x0C
I/BluetoothScanner: executeCommand returningDCSSDK_RESULT_SUCCESS
I/ViewRootImpl: CPU Rendering VSync enable = false
I/BluetoothScanner: executeCommand started. opcode = DCSSDK_SET_ACTION inXML = <inArgs><scannerID>5</scannerID><cmdArgs><arg-int>17</arg-int></cmdArgs></inArgs>
I/BluetoothScanner: 7 SSI bytes sent: 0x05 0xE6 0x04 0x00 0x11 0xFF 0x00
I/BluetoothScanner: soundBeeper command write successful. Wait for Status.
executeCommand returningDCSSDK_RESULT_SUCCESS
I/ViewRootImpl: CPU Rendering VSync enable = false
I/BluetoothScanner: executeCommand started. opcode = DCSSDK_SET_ACTION inXML = <inArgs><scannerID>5</scannerID><cmdArgs><arg-int>46</arg-int></cmdArgs></inArgs>
I/BluetoothScanner: 7 SSI bytes sent: 0x05 0xE8 0x04 0x00 0x04 0xFF 0x0B
executeCommand returningDCSSDK_RESULT_SUCCESS
Code, that I am using to construct those requests is based on an example app and documentation provided by Zebra see here the Zebra Android SDK and this is how I am calling those actions:
private class MyAsyncTask extends AsyncTask<String,Integer,Boolean> {
int scannerId;
StringBuilder outXML;
DCSSDKDefs.DCSSDK_COMMAND_OPCODE opcode;
private CustomProgressDialog progressDialog;
public MyAsyncTask(int scannerId, DCSSDKDefs.DCSSDK_COMMAND_OPCODE opcode){
this.scannerId=scannerId;
this.opcode=opcode;
this.outXML = outXML;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new CustomProgressDialog(MainActivity.this, "Execute Command...");
progressDialog.show();
}
#Override
protected Boolean doInBackground(String... strings) {
return executeCommand(opcode,strings[0],null,scannerId);
}
#Override
protected void onPostExecute(Boolean b) {
super.onPostExecute(b);
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
if(!b){
Toast.makeText(MainActivity.this, "Cannot perform the Action", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public boolean executeCommand(DCSSDKDefs.DCSSDK_COMMAND_OPCODE opCode, String inXML, StringBuilder outXML, int scannerID) {
if (Application.sdkHandler != null)
{
if(outXML == null){
outXML = new StringBuilder();
}
DCSSDKDefs.DCSSDK_RESULT result=Application.sdkHandler.dcssdkExecuteCommandOpCodeInXMLForScanner(opCode,inXML,outXML,scannerID);
if(result== DCSSDKDefs.DCSSDK_RESULT.DCSSDK_RESULT_SUCCESS)
return true;
else if(result==DCSSDKDefs.DCSSDK_RESULT.DCSSDK_RESULT_FAILURE)
return false;
}
return false;
}
private final Handler dataHandler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
switch(msg.what){
case Constants.BARCODE_RECEIVED:
Barcode barcode = (Barcode) msg.obj;
sendApiHttpRequest(new String(barcode.getBarcodeData()));
break;
}
return false;
}
});
private void sendApiHttpRequest(String ticketId){
String url = "https://#################################/" + ticketId;
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null, myJsonListener(), myJsonErrorListener());
// tag the request for ease of debugging
jsonObjectRequest.setTag(TAG);
// Access the RequestQueue through your singleton class.
MySingleton.getInstance(this).addToRequestQueue(jsonObjectRequest);
}
private Response.Listener<JSONObject> myJsonListener() {
return new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
boolean status;
try {
status = response.getBoolean("status");
if (status){
setScanResultOK();
}else{
setScanResultERR();
}
}catch(JSONException e){
setScanResultERR();
Log.e(TAG, "Failure", e);
}
}
};
}
private Response.ErrorListener myJsonErrorListener() {
return new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
setScanResultERR();
Log.i(TAG, "Error : " + error.getLocalizedMessage());
}
};
}
private void setScanResultOK(){
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_ON);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_FAST_WARBLE_BEEP);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_OFF);
TextView textViewScanResult = findViewById(R.id.txt_scan_result);
textViewScanResult.setText(R.string.scan_res_ok);
textViewScanResult.setTextAppearance(getApplicationContext(), R.style.roboto_medium_96dp_green);
}
private void setScanResultERR(){
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_RED_ON);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LOW_LONG_BEEP_3);
prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_RED_OFF);
TextView textViewScanResult = findViewById(R.id.txt_scan_result);
textViewScanResult.setText(R.string.scan_res_err);
textViewScanResult.setTextAppearance(getApplicationContext(), R.style.roboto_medium_96dp_red);
}
private void performOpcodeAction(String inXML) {
if (scannerID != -1) {
new MyAsyncTask(scannerID, DCSSDKDefs.DCSSDK_COMMAND_OPCODE.DCSSDK_SET_ACTION).execute(new String[]{inXML});
} else {
Toast.makeText(this, "Invalid scanner ID", Toast.LENGTH_SHORT).show();
}
}
private void prepareInXML(int value){
String inXML = "<inArgs><scannerID>" + scannerID + "</scannerID><cmdArgs><arg-int>" +
value + "</arg-int></cmdArgs></inArgs>";
performOpcodeAction(inXML);
}
When I set up breakpoints and step through the code, all actions are executed and as soon as I run the app, I get those issues.
Can anyone please help me?
Here's what I understood from your code. Your are sending an HTTP request to a server and based on the response, your are going to perform a sequence of events such as LED and sound state toggling.
As a background, Asynctask is used to execute a piece of code on a background thread. In your case, you want to perform the commands. As from the name, they are asynchronous and will run in parallel with your main thread (at least the doInBackground).
In setScanResultOK and setScanResultERR, you are potentially instantiating 3 asynctasks. Only one of them will run as by default, asynctasks run on a single execution thread. If you want to run them altogether, execute them in a thread pool executor.
Now, you mentioned that you want to run them in sequence. I propose to refactor your code as such.
Create 2 asynctasks, 1 for success and 1 for error.
Perform the multiple prepareInXML calls in doInBackground
Instantiate an asynctask based on the response, and execute.
As an example:
#Override
protected Boolean doInBackground(String... strings) {
if (!prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_ON)) {
return false;
}
if (!prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_FAST_WARBLE_BEEP)) {
return false;
}
return prepareInXML(RMDAttributes.RMD_ATTR_VALUE_ACTION_LED_GREEN_OFF);
}
Of course this will require you to change some function signature to accommodate. Then process all UI changes in onPostExecute.
#Override
protected void onPostExecute(Boolean b) {
super.onPostExecute(b);
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
if(!b){
Toast.makeText(MainActivity.this, "Cannot perform the Action", Toast.LENGTH_SHORT).show();
}
/* perform UI changes particular to the type of task (success/fail) */
}
UPDATE:
Try adding a delay in between commands. The no op might be something that is actually a on-sound-off sequence happening real fast for us to notice.

How to get current time from internet in android

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();
}
}

Android Async Task stop running after run it a few times

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.

Categories

Resources