I am syncing lat-longs from local database to the server and change the status of rows in local database table if the lat-longs are successfully synced with the server, when user presses the button.
Problem
When button is pressed I hit the API for syncing lat-long to the server.
Some long-long is missing if the internet is slow (I want to send all lat-longs in exact sequence. If miss any lat-long, I try again to send the missing).
If all lat-longs are successfully synced only then EndRide Api is called.
This is the code when the button is pressed.
try {
cursor = db.getUnsyncedLatLngs(engIdForDB);
if (cursor.moveToFirst()) {
do {
//calling the method to save the unsynced name to MySQL
saveLatLngs(cursor.getInt(cursor.getColumnIndex(NewDatabaseForInRideData.COLUMN_ID)), cursor.getDouble(cursor.getColumnIndex(NewDatabaseForInRideData.Latitude)), cursor.getDouble(cursor.getColumnIndex(NewDatabaseForInRideData.Longitude)), engIdForDB);
} while (cursor.moveToNext());
}
} catch (Exception e) {
e.printStackTrace();
}
//Problem driverEndRideAsync is called even if some LatLng skiped to upload.
driverEndRideAsync(activity, abc, abc, 0, abc);
And for uploading lat-long to the server
private void saveLatLngs(final int id, final double lati, final double longi, String engId) {
RestClient.getApiService().update_data(abc, abc, lati, longi, String.valueOf(123), String.valueOf(123), String.valueOf(123), new Callback<String>() {
#Override
public void success(String s, Response response) {
try {
JSONObject jObj;
jObj = new JSONObject(s);
int flag = jObj.getInt("flag");
if (ApiResponseFlags.SOMETHING_WENT_WRONG.getOrdinal() == flag) {
db.updateNameStatus(id, NAME_NOT_SYNCED_WITH_SERVER, engId);
} else {
db.updateNameStatus(id, NAME_SYNCED_WITH_SERVER, engId);
}
} catch (JSONException e) {
e.printStackTrace();
}
android.util.Log.i("update_in_ride_data", " Success =" + response);
}
#Override
public void failure(RetrofitError error) {
android.util.Log.i("update_in_ride_data", " Error =" + error);
}
});
}
You have several problems in your implementation.
You are saving your lat-long fetched from your database table by calling an external API to your server inside a while loop. This is quite a bad implementation as this is creating a lot of AsyncTask in the background when you are trying to save each lat-long with an API service call.
The cleaner implementation requires development in your backend server which should take the lat-long as a batch (i.e. a bunch of lat-long will be saved at a time). In this implementation you will be able to save your lat-long by calling the API service once, instead of having it called multiple times for each of your entries.
Move the driverEndRideAsync(activity, abc, abc, 0, abc); function call inside your try block, so that it will not execute if you get an exception from that block while you are sending the lat-long data to your server using the API service.
If you are keeping this exact implementation in your server side, then I would suggest you to have a background service which will check if there is any data available to be synced with server in your database table after a certain time. In that case, you will have your data synced even if you get an exception while you are syncing your data with your server, because eventually the background service will detect un-synced data and will sync them with the server application.
Hope that helps.
Related
I've been trying to build some functionality into my app too allow user-generated data (EEG recordings) to be sent to a central BigQuery database.
I've never done any networking code in Java before, so I shied away from doing the POST or REST-based strategies recommended here. The BigQuery Java client library seemed to be exactly what I needed, though I was completely confused why it wouldn't officially support Android.
Still, I came across this example Android app (from Google no less) that promised to do exactly what I wanted with the BigQuery Client library. I incorporated it into my app as follows:
// .... in an AsyncTask
#Override
protected String doInBackground(String... params) {
String CSV_CONTENT = params[0];
try {
AssetManager am = MainApplication.getInstance().getAssets();
InputStream isCredentialsFile = am.open(CREDENTIALS_FILE);
BigQuery bigquery = BigQueryOptions.builder()
.authCredentials(AuthCredentials.createForJson(isCredentialsFile))
.projectId( PROJECT_ID )
.build().service();
TableId tableId = TableId.of(DATASET,TABLE);
Table table = bigquery.getTable(tableId);
int num = 0;
Log.d("Main", "Sending CSV: ");
WriteChannelConfiguration configuration = WriteChannelConfiguration.builder(tableId)
.formatOptions(FormatOptions.csv())
.build();
try (WriteChannel channel = bigquery.writer(configuration)) {
num = channel.write(ByteBuffer.wrap(CSV_CONTENT.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
Log.d("Main", e.toString());
}
Log.d("Main", "Loading " + Integer.toString(num) + " bytes into table " + tableId);
} catch (Exception e) {
Log.d("Main", "Exception: " + e.toString());
}
return "Done";
}
This runs without any errors and fires off an API call that is detected by Google Cloud Storage. However, it returns error 200 (job was cancelled) every time. I don't understand how this could be since I'm not doing anything in the code to cancel the request and I don't see how the async task I put the call in could be cancelled.
Was this just a bad example app I copied and a bad usage of the BigQuery Client? If so, what's the best way to send data to BigQuery from Android?
I'm using Parse with Android in order to sync my data.
I'm trying to delete an object which is stored in the Parse cloud via
The callback returns and there's no exception, the Logcat message is "deleted".
But the object still exists in table when I check the Parse Data.
tastToEdit is an object from Task class (configured locally in my app).
ParseObject parse_task = new ParseObject("Task");
parse_task.put("Description",tastToEdit.getDescription());
parse_task.put("DueDate",tastToEdit.getDueDate());
parse_task.put("Priority",tastToEdit.getPriority().ordinal());
int com_state = (tastToEdit.getCompleted()) ? 1 : 0;
parse_task.put("IsCompleted",com_state);
parse_task.put("Location",0);
parse_task.put("Category",tastToEdit.getTask_catg().ordinal());
parse_task.put("Status", tastToEdit.getTask_sts().ordinal());
//parse_task.deleteInBackground();
parse_task.deleteInBackground(new DeleteCallback() {
public void done(ParseException e) {
if (e == null) {
Log.d("msg","deleted");
} else {
Log.d("msg", "not deleted");
e.printStackTrace();
}
}
});
What might be causing the callback to return as "deleted" but the object still remains?
Thanks in advance.
You are creating a new ParseObject and you try to delete it after but you don't provide an ObjectID.
A better way to do this will be to first do a ParseQuery for that task you are looking and the in the completion delete it.
I am in a project and using volley to parse data from internet. I have successfully cached the data and can retrieve the data from there and if cache is not available then parse from network by the following code:
Cache cache = GlobalData.getInstance().getRequestQueue().getCache();
Entry entry = cache
.get("http://10.10.10.22/emaildata/getcurrentuser.php");
if (entry != null) {
try {
String data = new String(entry.data, "UTF-8");
JSONArray array = new JSONArray(data);
setParsedValue(array);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
JsonArrayRequest jArrayRequest = new JsonArrayRequest(
"http://10.10.10.22/emaildata/getcurrentuser.php",
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray array) {
setParsedValue(array);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(),
error.getMessage(), Toast.LENGTH_LONG)
.show();
}
});
GlobalData.getInstance().addToRequestQueue(jArrayRequest);
}
now I want that the data will always load from the cache until new data is available on that network url, as far I did is the following on onPause();
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
GlobalData
.getInstance()
.getRequestQueue()
.getCache()
.invalidate("http://10.10.10.22/emaildata/getcurrentuser.php",
true);
}
sometimes it works but sometimes it doesnt work, most of the time I had to restart my device to get awared about the new data where I want instead, can anyone help how to instantly get the data changes to parse from the network or load from the cache otherwise?
I am in a project and using volley to parse data from internet. I have
successfully cached the data and can retrieve the data from there and
if cache is not available then parse from network by the following
code:
...
now I want that the data will always load from the cache until new
data is available on that network url
...
can anyone help how to instantly get the data changes to parse from the network or load from the cache otherwise?
Volley dose all of above task automatically as long as the server response allows it, for example dose not have any field like:
Cache-Control:no-cache|no-store
which cause Volley dose not store the response.
all you have to do is just making request. if it is in his cache and it is valid (max-age or ttl or... is ok) it returns that for you else if it is expired or it is not valid anymore it creates new request.
If you want to ensure that you always get fresh data from the server instead of locally cached you can append a current timestamp to your url call. This will ensure that Volley treats the url you pass it as unique and therefore it will make a request to the server.
e.g.
int time = (int) (System.currentTimeMillis());
JsonArrayRequest jArrayRequest = new JsonArrayRequest(
"http://10.10.10.22/emaildata/getcurrentuser.php?time"
I'm trying to indicate the authentication / sync status of an account using the AccountAuthenticator and SyncAdapter. I've been through the samples, and can get it working alright.
How can I set the indicator to red just like the GMail account?
I'd also like to add additional status indicators on the sync adapter page. See picture below:
Answering my own question for future team knowledge...
Getting the indicator to change color was fairly easy after some experimentation. Start by creating a project based on thecode supplied in the SDK sample projects, modify as follows:
1) Fake the initial login from the server during the AuthenticationActivity. Once past the initial check, the system will start it's periodic sync attempts.
/**
* Called when the authentication process completes (see attemptLogin()).
*/
public void onAuthenticationResult(boolean result) {
Log.i(TAG, "onAuthenticationResult(" + result + ")");
// Hide the progress dialog
hideProgress();
// Override the result, we don't care right now....
result = true;
if (result) {
if (!mConfirmCredentials) {
finishLogin();
} else {
finishConfirmCredentials(true);
}
} else {
Log.e(TAG, "onAuthenticationResult: failed to authenticate");
if (mRequestNewAccount) {
// "Please enter a valid username/password.
mMessage.setText(getText(R.string.login_activity_loginfail_text_both));
} else {
// "Please enter a valid password." (Used when the
// account is already in the database but the password
// doesn't work.)
mMessage.setText(getText(R.string.login_activity_loginfail_text_pwonly));
}
}
}
2) Modify the "onPerformSync()" method within the SyncAdapter. The key here are the "syncResult.stats" fields. While modifying them, I found that inserting multiple errors didn't get the effect I wanted. Also noting that the counts didn't seem to be recorded across sync attempts (i.e. the fails always come in as zero). The "lifetimeSyncs" is a static variable that keeps count across sync attempts. This modified code will continue to alternate between green and red...
#Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
List<User> users;
List<Status> statuses;
String authtoken = null;
try {
// use the account manager to request the credentials
authtoken = mAccountManager.blockingGetAuthToken(account, Constants.AUTHTOKEN_TYPE, true );
// fetch updates from the sample service over the cloud
//users = NetworkUtilities.fetchFriendUpdates(account, authtoken, mLastUpdated);
// update the last synced date.
mLastUpdated = new Date();
// update platform contacts.
Log.d(TAG, "Calling contactManager's sync contacts");
//ContactManager.syncContacts(mContext, account.name, users);
// fetch and update status messages for all the synced users.
//statuses = NetworkUtilities.fetchFriendStatuses(account, authtoken);
//ContactManager.insertStatuses(mContext, account.name, statuses);
if (SyncAdapter.lifetimeSyncs-- <= 0 ){
//mAccountManager.invalidateAuthToken(Constants.ACCOUNT_TYPE, authtoken);
syncResult.stats.numAuthExceptions++;
//syncResult.delayUntil = 60;
lifetimeSyncs = 5;
}
} catch (final AuthenticatorException e) {
syncResult.stats.numParseExceptions++;
Log.e(TAG, "AuthenticatorException", e);
} catch (final OperationCanceledException e) {
Log.e(TAG, "OperationCanceledExcetpion", e);
} catch (final IOException e) {
Log.e(TAG, "IOException", e);
Log.d(TAG, extras.toString());
syncResult.stats.numAuthExceptions++;
syncResult.delayUntil = 60;
//extras.putString(AccountManager.KEY_AUTH_FAILED_MESSAGE, "You're not registered");
} catch (final ParseException e) {
syncResult.stats.numParseExceptions++;
Log.e(TAG, "ParseException", e);
}
}
That's it, enjoy playing with the delays and other variables too...
I am working on an android application which is able to connect with an openerp server and retrive the userid and also the individual fields of the different contacts of that user.
below is the code on the things i have done so far
public int Search()
{
searchClient = new XMLRPCClient("http://"+lp.HOST+":"+lp.IN_PORT+lp.URL_XML+lp.URL_OBJECT);
try
{
record = (Array[]) searchClient.call("search",lp.DB_NAME, lp.uid1, lp.PASSWORD, "res.partnet.contact","execute", arguments);
}
catch(Exception e)
{
Log.i("------------------ CONNECTION FAILED Search", e.toString());
}
return 0;
}
i appreciate the help given
Thank you,
try to interchange the position of method search and execute.The method execute must be given before search.Also try searchClient.callEx instead call only like you do it above!
record = (Array[]) searchClient.callEx("execute",lp.DB_NAME, lp.uid1, lp.PASSWORD, "res.partnet.contact","search", arguments);