How to cancel Places SDK for Android find autocomplete predictions task? - android

I'm trying figure out how to cancel the task which was created to fetch autocomplete predictions using the new Places SDK for Android.
The task was created using this code -
Places.initialize(applicationContext, ApiClient.GOOGLE_API_KEY)
placesClient = Places.createClient(this)
placesClient.findAutocompletePredictions(request).addOnSuccessListener { response ->
for (prediction in response.autocompletePredictions) {
Log.i(TAG, prediction.placeId)
Log.i(TAG, prediction.getPrimaryText(null).toString())
}
}.addOnFailureListener { exception ->
if (exception is ApiException) {
val apiException = exception as ApiException
Log.e(TAG, "Place not found: " + apiException.statusCode)
}
}
The task has a addOnCancelledListener but no way to cancel it!
How do I cancel this task?

Here is the complete code to cancel an autocomplete search request following the links shared by #Riyasa
/*
Create a new CancellationTokenSource object each time you execute a new query
because the cancellation token received from this will work only for this request
and not afterwards
*/
val cancellationTokenSource = CancellationTokenSource()
val requestBuilder = FindAutocompletePredictionsRequest.builder()
.setQuery(newText) //NewText is your query text
.setCancellationToken(cancellationTokenSource.token)
//Setting the cancellation token from the object created above
placesClient.findAutocompletePredictions(requestBuilder.build()).addOnSuccessListener { response ->
//Do what you need to with the result
}
//and finally call this to cancel the request using the object created for this request
cancellationTokenSource.cancel()

You can use getCancellationToken () method to cancel any yet-to-be-executed requests.
You can follow official places sdk document from the following link.
https://developers.google.com/places/android-sdk/reference/com/google/android/libraries/places/api/net/FindAutocompletePredictionsRequest#getCancellationToken()
An example on how to use the cancellation token:
https://developers.google.com/android/reference/com/google/android/gms/tasks/CancellationToken

Related

I am using Jsoup to perform some actions on a website But I am having troubles getting the url right

I use this website I already logged in with these credentials
email:teacher#gmail.com
password:tttt
I got the cookies and saved it to my App ..but whenever I try to add new exam type I got error fetching url exception I use Jsoup
here's the code
private fun addExam() {
Log.d(TAG, "addExam: -----------------------")
try{
val addExamResponse=Jsoup.connect(getString(R.string.addExamUrl))
.method(Connection.Method.GET)
.userAgent("Mozilla")
.cookies(Common.sessionCookies)
.execute()
val document=addExamResponse.parse()
Log.d(TAG, "addExam: ------------------------------------------")
val authToken:String=document.select("input[name=__RequestVerificationToken]").first().attr("value")
Log.d(TAG, "addExam: ************************** ${addExamResponse.url()}")
val formData: HashMap<String, String> = HashMap()
formData["utf8"] = "e2 9c 93"
formData["ExamTypeName"]=examType.text.toString()
formData["Description"]=examDesc.text.toString()
formData["__RequestVerificationToken"] = authToken
//Log.d(TAG, "addExam: ----------------------------${Common.sessionCookies}--------------------")
val examListPage = Jsoup.connect(getString(R.string.addExamUrl))
.data(formData)
.method(Connection.Method.POST)
.userAgent("Mozilla")
.cookies(Common.sessionCookies)
.execute()
Log.d(TAG, "getData: --------------------------------${examListPage.url()}")
if (examListPage.url().toString().toLowerCase(Locale.ROOT).contains("teacher")){
runOnUiThread {
progressBar.hide()
}
startActivity(Intent(this,HomeActivity::class.java))
finish()
}
else{
runOnUiThread {
Toast.makeText(this,"Something went wrong!!",Toast.LENGTH_LONG).show()
}
}
}
catch (e:IOException){
Log.d(TAG, "addExam: -------------------------IO EXCEPTION---------------------${e.message}")
}
}
Without try and catch the app crashes with this exception .Stack trace::
E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.example.e_learninghub, PID: 10508
org.jsoup.HttpStatusException: HTTP error fetching URL. Status=500, URL=http://elearninghub.somee.com/Exam/AddExamType
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:682)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:629)
at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:261)
at com.example.e_learninghub.NewExamActivity.addExam(NewExamActivity.kt:65)
at com.example.e_learninghub.NewExamActivity.access$addExam(NewExamActivity.kt:19)
at com.example.e_learninghub.NewExamActivity$addExamType$1.invokeSuspend(NewExamActivity.kt:35)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask$DefaultImpls.run(Dispatched.kt:235)
at kotlinx.coroutines.DispatchedContinuation.run(Dispatched.kt:81)
at kotlinx.coroutines.scheduling.Task.run(Tasks.kt:94)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:586)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:732)
Error 500 suggests there was something wrong on server side. Your code looks OK, so probably there was something wrong with your parameters. Are you sure ExamTypeName and Description are not empty?
Try displaying parameters before you send them:
Log.d(TAG, "formData: --------------------------------${formData}")

httpClient.PostAsync crashes app in Xamarin Android JobService

I have an Android Xamarin app that handles notifications. When a notification is displayed, there are buttons that ask for a response. The app needs to send this response back to a server via an httpClient.PostAsync call. I am using the same http client wrapper in other parts of the code and it is working correctly. However, when I call it from the JobService code, the app crashes. I have enclosed the http call in a try/catch and no exception occurs. There are also no errors in the device log. i would like to know how to debug this. Here is my flow:
I have a class that derives from FirebaseMessagingService with an OnMessageReceived method. That gets called when a notification arrives. I build a local notification via the notification manager and call .Notify. The notification appears with the buttons. I have a BroadcastReceiver with an OnReceive method. That method schedules a job to do the post back of the button click. The job gets started and runs until the point I call the PostAsync. From there it crashes with no exception. Here is the relevant part of the JobWorker:
public override bool OnStartJob(JobParameters jobParams)
{
_backgroundWorker = Task.Run(() => { DoWork(jobParams); });
return true;
}
private void DoWork(JobParameters jobParams)
{
var logger = App.ResolveDependency<ILogger>() as ILogger;
var callActions = App.ResolveDependency<ICallActionsHandler>() as ICallActionsHandler;
var callToken = jobParams.Extras.GetString(JobParameterCallToken);
var subsciberPhoneNumber = jobParams.Extras.GetString(JobParameterSubscriberPhoneNumber);
var action = jobParams.Extras.GetString(JobParametersCallAction);
logger.TraceInfo($"starting {nameof(CallActionService)}: starting job {jobParams.JobId}");
callActions.SendAction(
callToken,
subsciberPhoneNumber,
(CallActions)Enum.Parse(typeof(CallActions), action));
}
The SendAction code calls the http client wrapper. The http client wrapper code looks like this:
public async Task<int> PostAsync(string api, object message)
{
var apiUrl = Constants.DefaultAppApi + api;
var contentText = JsonConvert.SerializeObject(message);
var content = new StringContent(contentText, Encoding.UTF8, "application/json");
var backOff = 10;
var retryCount = 5;
HttpResponseMessage response = null;
for (var attempt = 1; attempt <= retryCount; attempt++)
{
_logger.TraceInfo($"DataServerClient Post message: {message.GetType().Name}, attempt = {attempt}");
try
{
response = await _client.PostAsync(apiUrl, content);
}
catch (Exception ex)
{
if (attempt == retryCount)
_logger.TraceException($"DataServerClient Post failed", ex);
}
if (response != null && response.IsSuccessStatusCode)
{
_logger.TraceInfo($"DataServerClient post was successful at retry count: {attempt}");
break;
}
backOff *= 2;
await Task.Delay(backOff);
}
return (int)response.StatusCode;
}
Can anyone provide clues for why this is failing or how I can gather diagnostics to find out what is happening? As I mentioned, the exception is not caught, the task that I create gets marked as completed, and no message gets posted.

Using Retrofit 2 in Intent Service class

I am trying to fetch data from server and sync it on the background of app. I did it using AsyncTask in an Intent Service class, but now I want to make network call using Retrofit. So, I fetched data from server using retrofit but while I am saving them on the local database the main thread freezes, only after completion of the process I can do something on the Main thread. Why is this happening?
I tried both synchronus and Asynchronus request of retrofit but the problem remains. This is what I have tried so far..
//calling company api in synchronus way
try {
val responseCompany = apiService.company(page, headers, bodyModel).execute()
Log.e("onResponse", "Company Response Code: ${responseCompany.code()}")
Log.e("onResponse", "Company Response Body: ${Gson().toJson(responseCompany.body())}")
if (responseCompany.isSuccessful) {
val response = responseCompany.body()
//delete company data
if (response?.delete?.data?.size!! > 0) {
for (i in response.delete.data.indices) {
val delete = response.delete.data[i]
Log.e(tag, "Delete Company data $i: ${delete.company_id}")
dbAdapter.open()
dbAdapter.Delete_COMPANY_NAME(delete.company_id)
dbAdapter.close()
}
}
//insert company data
if (response.insert.data.isNotEmpty()) {
for (i in response.insert.data.indices) {
val insert = response.insert.data[i]
Log.e(tag, "Insert company data $i: ${insert.company_id}")
dbAdapter.open()
dbAdapter.Insert_COMPANY_NAME(insert.company_id.toString(), insert.company_name)
dbAdapter.close()
}
}
//update company data
if (response.update.data.isNotEmpty()) {
for (i in response.update.data.indices) {
val update = response.update.data[i]
Log.e(tag, "Update Company data $i: ${update.company_id}")
dbAdapter.open()
dbAdapter.Update_COMPANY_NAME(update.company_id.toString(), update.company_name)
dbAdapter.close()
}
}
val totalPage = largest(response.delete.meta.pagination.total_pages, response.insert.meta.pagination.total_pages, response.update.meta.pagination.total_pages)
if (page < totalPage) {
prefManager.pageNumber = page + 1
bodyModel.date = lastAdUpdate2
bodyModel.limit = 500
companyData(bodyModel)
} else {
prefManager.T_COMPANY_NAME = currentTime
prefManager.PAGE_NUMBER = 1
prefManager.TOTAL_PAGE = 1
prefManager.pageNumber = 1
prefManager.FIRST = "1"
pagenumber = prefManager.PAGE_NUMBER
Handler().postDelayed({
bodyModel.limit = 100
bodyModel.date = lastAdUpdate3
generics(bodyModel)
}, 1000)
}
} else {
prefManager.dbUpdateStatus = false
Log.i("dataNotInsert", "data Not Insert")
}
} catch (e: Exception) {
Log.e("Exception", "Company: ${e.localizedMessage}")
e.printStackTrace()
}
N.B: I made network call (Retrofit request) in an Intent Service class..
Any Kind of help is highly appreciated. Thank you
This problem was actually solved by replacing Intent Service with Work Manager. And Using Kotlin Coroutine
And if you want to persist with Intent Service rather than using WorkManager. Just wrapping your network call with AsyncTask will solve the problem

PlaceAutocompleteAdapter with Places SDK compat Library

I am working on google maps and search.
The only option to search on the map is the Google Places API.
https://developers.google.com/places/android-sdk/intro
Which also states that you play service version of SDK is deprecated.
So I was trying to implement it with the new SDK.
Now what I want is instead of Autocomplete to Open a new Activity I want it to be displayed as a list on my autocomplete.
So I tried to implement this : https://github.com/googlesamples/android-play-places/blob/master/PlaceCompleteAdapter/Application/src/main/java/com/example/google/playservices/placecomplete/PlaceAutocompleteAdapter.java
But the issue is it works with Play service version but not with Compat version because the classes and imports are different.
This is the part of the code that I am having trouble with :
// Submit the query to the autocomplete API and retrieve a PendingResult that will
// contain the results when the query completes.
PendingResult<AutocompletePredictionBuffer> results =
Places.GeoDataApi
.getAutocompletePredictions(mGoogleApiClient, constraint.toString(),
mBounds, mPlaceFilter);
// This method should have been called off the main UI thread. Block and wait for at most 60s
// for a result from the API.
AutocompletePredictionBuffer autocompletePredictions = results
.await(60, TimeUnit.SECONDS);
// Confirm that the query completed successfully, otherwise return null
final Status status = autocompletePredictions.getStatus();
if (!status.isSuccess()) {
Toast.makeText(getContext(), "Error contacting API: " + status.toString(),
Toast.LENGTH_SHORT).show();
Log.e(TAG, "Error getting autocomplete prediction API call: " + status.toString());
autocompletePredictions.release();
return null;
}
If anyone has implemented PlacesAutoCompleteAdapter with New Places API library. Please guide me with changing the above code.
Thank you.
Reference link:
https://developers.google.com/places/android-sdk/autocomplete#get_place_predictions_programmatically
Step 1. Intialize new PlaceClient
// Initialize Places.
Places.initialize(getApplicationContext(), apiKey);
// Create a new Places client instance.
PlacesClient placesClient = Places.createClient(this);
Step 2. Create request
// contain the results when the query completes.
FindAutocompletePredictionsRequest request = FindAutocompletePredictionsRequest.builder()
// similar to previous mBounds
// but you have to use Rectangular bounds (Check reference link)
.setLocationRestriction(mBounds)
.setQuery(constraint.toString()) // similar to previous constraint
.setTypeFilter(TypeFilter.ADDRESS) // similar to mPlaceFilter
.build();
Step 3. Send request object to response method
Task<FindAutocompletePredictionsResponse> task =
placeClient.findAutocompletePredictions(request);
Step 4. Handle OnSuccess code here
task.addOnSuccessListener(
(response) -> {
for (AutocompletePrediction prediction : response.getAutocompletePredictions()) {
Timber.d("prediction result: " + prediction);
// add result to your arraylist
}
// return your arraylist outside foreach loop
});
Step 5. Handle OnFailure code here
task.addOnFailureListener((exception) -> {
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
// places not found exception code
Timber.i("error message %s", apiException.getMessage());
}
});
Step 6. Handle OnComplete code here
task.addOnCompleteListener((response) -> {
Exception e = task.getException();
if (e instanceof ApiException) {
ApiException apiException = (ApiException) e;
if (!task.isSuccessful()) {
// your code
}
}
});
}

PendingResult.setResultCallback() always returns the statusCode success

if i connect my google watch with a mobile device successfully, and then disable the bluetooth connection (for test reasons) and make a google api client call to my mobile device, the pending result always returns the status code success, even if its not successfull because there is no more connection
async task for the request
class DataTask extends AsyncTask<Node, Void, Void> {
#Override
protected Void doInBackground(Node... nodes) {
Gson gson = new Gson();
Request requestObject = new Request();
requestObject.setType(Constants.REQUEST_TYPE);
String jsonString = gson.toJson(requestObject);
PutDataMapRequest dataMap = PutDataMapRequest.create(Constants.PATH_REQUEST);
dataMap.setUrgent();
dataMap.getDataMap().putString(Constants.KEY_REQUEST, jsonString);
PutDataRequest request = dataMap.asPutDataRequest();
DataApi.DataItemResult dataItemResult = Wearable.DataApi
.putDataItem(googleApiClient, request).await();
boolean connected = googleApiClient.isConnected();
PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi.putDataItem(googleApiClient, request);
pendingResult.setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(#NonNull DataApi.DataItemResult dataItemResult) {
com.google.android.gms.common.api.Status status = dataItemResult.getStatus();
DataItem dataItem = dataItemResult.getDataItem();
boolean dataValid = dataItemResult.getDataItem().isDataValid();
boolean canceled = status.isCanceled();
boolean interrupted = status.isInterrupted();
float statusCode = status.getStatusCode();
if(status.isSuccess()){ // expected to be false because there is no bluetooth connection anymore
Log.d(TAG, "Success");
}else{
Log.d(TAG, "Failure");
}
}
});
return null;
}
}
why do i not get a false for status.isSuccess?
the only solution i found is to write following code inside the AsyncTask:
Wearable.NodeApi.getConnectedNodes(googleApiClient).await().getNodes();
if(connectedNodes.size() == 0){
// no connection
}
is it not possible to check if the request was successfully inside the ResultCallback?
I believe that the getStatus() call for DataItemResult is only indicating whether the call was successfully passed off to the Data API, not whether it was successfully relayed to another node. The Data API is asynchronous - it's a "store and forward" architecture - so it's not reasonable to expect it to notify you immediately of successful delivery.
In fact, I don't think that there is a way to determine from the Data API when your DataItem has been delivered at all. Your getConnectedNodes technique is only telling you that the watch is connected, not that the data has been delivered. If you need proof of delivery, you'll probably have to implement that yourself, perhaps using the Message API.
One other note: given you've wrapped your code in an AsyncTask, there's no need to use PendingResult.setResultCallback. You can simply await the result inline: http://developer.android.com/training/wearables/data-layer/events.html#sync-waiting

Categories

Resources