AdvertisingIdClient getAdvertisingIdInfo blocked by main thread - java

I'm trying to wait the response of AdvertisingIdClient.getAdvertisingIdInfo(activity) without success. This method never response until the main thread has finished.
import android.app.Activity;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesUtil;
import java.io.IOException;
public class MyActivity extends Activity {
private Activity m_activity = null;
private AdvertisingIdClient.Info m_info = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// start the thread with the getAdvertisingIdInfo()
startGoogleAdvertisingIdRequest(this);
// simulate a waiting loop, others app init, ...
for (int i=0; i<20; i++) {
SystemClock.sleep(100);
}
// get the uuid
String uuid = getGoogleAdvertisingId();
// call a method who need the uuid
Log.i("UUID", "receive uuid: " + uuid);
}
public String getGoogleAdvertisingId() {
String uuid = null;
if (m_info != null) {
if (!m_info.isLimitAdTrackingEnabled()) {
uuid = m_info.getId();
} else {
uuid = "another uuid";
}
} else {
uuid = "another uuid";
}
return uuid;
}
public void startGoogleAdvertisingIdRequest(final Activity activity) {
m_activity = activity;
if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(activity) == ConnectionResult.SUCCESS) {
new Thread(new Runnable() {
#Override
public void run() {
AdvertisingIdClient.Info adInfo = null;
try {
Log.i("UUID", "before google request");
adInfo = AdvertisingIdClient.getAdvertisingIdInfo(activity);
Log.i("UUID", "after google request");
} catch (IOException e) {
Log.w("UUID", "getAdvertisingIdInfo IOException: " + e.getMessage());
} catch (GooglePlayServicesNotAvailableException e) {
Log.w("UUID", "GooglePlayServicesNotAvailableException: " + e.getMessage());
} catch (Exception e) {
Log.w("UUID", "GooglePlayServicesException: " + e.getMessage());
} finally {
finished(adInfo);
}
}
}).start();
}
}
private void finished(final AdvertisingIdClient.Info adInfo){
if(adInfo != null){
m_activity.runOnUiThread(new Runnable() {
#Override
public void run() {
m_info = adInfo;
Log.i("UUID", "runOnUiThread id: " + adInfo.getId());
}
});
}
}
}
Logcat of this code
11:29:52.103 30810-30828/com.example.testuuid I/UUID﹕ before google request
11:29:54.107 30810-30810/com.example.testuuid I/UUID﹕ receive uuid: another uuid
11:29:54.127 30810-30828/com.example.testuuid I/UUID﹕ after google request
11:29:54.151 30810-30810/com.example.testuuid I/UUID﹕ runOnUiThread id: d5dc3bfb-4756-490c-8f8e-2bedfb5e827a
Same logcat with more waiting time (5s)
11:36:14.215 31413-31436/com.example.testuuid I/UUID﹕ before google request
11:36:19.225 31413-31413/com.example.testuuid I/UUID﹕ receive uuid: another uuid
11:36:19.293 31413-31436/com.example.testuuid I/UUID﹕ after google request
11:36:19.315 31413-31413/com.example.testuuid I/UUID﹕ runOnUiThread id: d5dc3bfb-4756-490c-8f8e-2bedfb5e827a
Each time the getAdvertisingIdInfo(), who is in another thread, is blocked by the main thread.
What is the reason ? and how to do this ?

To get the google ad ID you need not to run the method getAdvertisingIdInfo on the main thread.
I use Async Task to manage the extraction of the google ad ID.
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
import com.google.android.gms.common.GooglePlayServicesRepairableException;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
String GAID; // this is the String of the Google Ad ID that you'll receive upon onPostExecute
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new GetGAIDTask().execute();
}
private class GetGAIDTask extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... strings) {
AdvertisingIdClient.Info adInfo;
adInfo = null;
try {
adInfo = AdvertisingIdClient.getAdvertisingIdInfo(MainActivity.this.getApplicationContext());
if (adInfo.isLimitAdTrackingEnabled()) // check if user has opted out of tracking
return "did not found GAID... sorry";
} catch (IOException e) {
e.printStackTrace();
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
} catch (GooglePlayServicesRepairableException e) {
e.printStackTrace();
}
return adInfo.getId();
}
#Override
protected void onPostExecute(String s) {
GAID = s;
}
}
You also need to add to the app build.gradle on the dependencies the line
compile 'com.google.android.gms:play-services-ads:7.8.0'
And be sure you have on the Android SDK manager the "EXTRAS Google Repository" updated

In the literature about AdvertisingIdClient it says to not use on main thread. It will throw an exception. So if you put it into it's own thread you will be fine, most likely.
AdvertisingIdClient reference

The issue you are seeing, where no amount of time seems long enough for the getAdvertisingIdInfo call to complete, is caused by how you are waiting and how runOnUiThread works. The key is that runOnUiThread will queue the code to be run after what is currently running on the ui thread, in this case the onCreate. The sleep calls used to "simulate waiting" will let your background thread run and do its work, but the final operation to set m_info will always be queued and executed after onCreate completes.
One solution would be to ensure that m_info is safe to access from multiple threads and simply assign it on the background thread. There would be no need for runOnUiThread. This would remove queuing, and allow your code to work with minimal changes.
A better solution would be to keep the use of runOnUiThread and remove the sleep used to wait. You would need to keep in mind that m_info will always be null in onCreate, but other events can check if the value is non null and use it as needed.
https://developer.android.com/reference/android/app/Activity#runOnUiThread(java.lang.Runnable)
Runs the specified action on the UI thread. If the current thread is the UI thread, then the action is executed immediately. If the current thread is not the UI thread, the action is posted to the event queue of the UI thread.

According to the docs (here) :
Unfortunately, in these cases using the com.google.android.gms.iid
InstanceID API or system functions to create an app-scoped ID are not
appropriate solutions because the ID may need to be shared across
apps. An alternative solution is to use the Advertising Identifier
available from the AdvertisingIdClient.Info class via the getId()
method. You can create an AdvertisingIdClient.Info object using the
getAdvertisingIdInfo(Context) method and call the getId() method to
use the identifier. Note that this method is blocking, so you should
not call it from the main thread; a detailed explanation of this
method is available here.
Also here:
public static AdvertisingIdClient.Info getAdvertisingIdInfo (Context
context)
Retrieves the user's advertising ID and limit ad tracking preference.
This method cannot be called in the main thread as it may block
leading to ANRs. An IllegalStateException will be thrown if this is
called on the main thread.
So they say it's blocking...
You need to put this code in a background thread.

Related

How can i store pushy tokens to database

am using pushy for push notifications but am not able to store the device token in the database.
private class RegisterForPushNotificationsAsync extends AsyncTask<Void, Void, Exception> {
protected Exception doInBackground(Void... params) {
try {
// Assign a unique token to this device
String deviceToken = Pushy.register(getApplicationContext());
// Log it for debugging purposes
Log.d("MyApp", "Pushy device token: " + deviceToken);
// Send the token to your backend server via an HTTP GET request
new URL("https://key}/register/device?token=" + deviceToken).openConnection();
} catch (Exception exc) {
// Return exc to onPostExecute
return exc;
}
// Success
return null;
}
#Override
protected void onPostExecute(Exception exc) {
// Failed?
if (exc != null) {
// Show error as toast message
Toast.makeText(getApplicationContext(), exc.toString(), Toast.LENGTH_LONG).show();
return;
}
// Succeeded, optionally do something to alert the user
}
}
I am using retrofit for the http requests and am not using any kind of backend system
What you're doing is well enough to get you a Device Token from Pushy service.
If you want to capture the returned device token and make it accessible to the AsyncTask class and the enclosing class in general (as you stated in the comments), then you can declare a global/instance String variable, say pushy_device_token, in the enclosing class.
Then in doInBackground() method of the AsyncTask, go ahead and assign the global variable as follows:
pushy_device_token = Pushy.register(getApplicationContext());
Complete code:
public class EnclosingClass {
String pushy_device_token;
// Additional class code
private class RegisterForPushNotificationsAsync extends AsyncTask<Void, Void, Exception> {
#Override
protected Exception doInBackground(Void... params) {
try {
// Assign a unique token to this device
pushy_device_token = Pushy.register(getApplicationContext());
// Log it for debugging purposes
Log.d("MyApp", "Pushy device token: " + deviceToken);
// Send the token to your backend server via an HTTP GET request
new URL("https://key}/register/device?token=" + deviceToken).openConnection();
} catch (Exception exc) {
// Return exc to onPostExecute
return exc;
}
// Success
return null;
}
#Override
protected void onPostExecute(Exception exc) {
// Failed?
if (exc != null) {
// Show error as toast message
Toast.makeText(getApplicationContext(), exc.toString(), Toast.LENGTH_LONG).show();
return;
}
// Succeeded, optionally do something to alert the user
}
}
}
Best practice recommendation:
It's best to have the result of processing in doInBackground(), returned in the onPostExecute() method, especially if you're going to do some UI work. So from onPostExecute(), you can do anything you want with the result, e.g. display to the user, report an error, etc.
To do this, you'll have to modify your doInBackground() method to return something as generic as Object. And so onPostExecute() will take in an Object as a parameter variable.
You'll modify by:
private class RegisterForPushNotificationsAsync extends AsyncTask<Void, Void, Object> { . . .
From this, you can check if the Object taken in by onPostExecute() is of type Exception, in which case, you'll display an error notification, or check if it's of type String, in which case you'll have the device token which you can then proceed to save in your DB (Firebase, SQLite, etc.).

Fail whe i try to connect my app to webServices

Actully i working in a app, but i have problems to connect my Web services, i have this code:
try{
HttpServices post = new HttpServices ("http://sotem.com.mx/WebServices/controller.php");
post.add("funcion", "test");
System.out.println("Si lo mande///////////////////Jhgfdsa");
String respuesta = post.getRespueta();
System.out.println(respuesta);
Toast.makeText(getApplicationContext(),"Cool: "+respuesta, Toast.LENGTH_SHORT).show();
}catch (Exception ex) {
Toast.makeText(getApplicationContext(),"error: "+ex.toString(), Toast.LENGTH_SHORT).show();
}
but i can make connection, i try to make other thinks, but i can make the thread, i'am new in this part, the app launcher this error:
android os network on main thread exception
It is not okay to do the Network Operation on main thread.. You can use AsyncTask to perform such operations and handle the result in onPostExecute method.
class YourNetworkingTasks extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
try{
HttpServices post = new HttpServices ("http://sotem.com.mx/WebServices/controller.php");
post.add("funcion", "test");
String respuesta = post.getRespueta();
Log.d("Output", respuesta);
// DON'T DO ANY UI CHANGES LIKE TOAST FROM BACKGROUND THREAD.. Toast.makeText(getApplicationContext(),"Cool: "+respuesta, Toast.LENGTH_SHORT).show();
}catch (Exception ex) {
// DON'T DO ANY UI CHANGES LIKE TOAST FROM BACKGROUND THREAD.. Toast.makeText(getApplicationContext(),"error: "+ex.toString(), Toast.LENGTH_SHORT).show();
}
return null;
}
protected void onPostExecute(RSSFeed feed) {
// TODO: YOU CAN MAKE U.I. Changes Like Display text in TextView, TOAST HERE.
// TODO: do something with the result
}
}
And write new YourNetworkingTasks().execute(); to run that code in background thread.
Please also not that since you are using http and not https you may get Network Security Exception and may not get any output due to recent security change in android.

How to use mediaPlayer correctlty?

I'm trying to play music in my app and while the media player is loading I want to allow the user to keep on using the app, but the app gets stuck for few seconds every time I start loading the media player, and when the media player is finished loading, only then the app returns to normal and starts working again, sometimes it's not just freezing, it also shows popup menu from the OS that prompts the user to quit the app.
I couldn't find any solution in Google or YouTube, anyone knows what's wrong with my code?
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
try {
String STREAM_URL = #####; // here i put the URL of the song
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(STREAM_URL);
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
} catch (NullPointerException e) {
Log.d(TAG, "run: NullPointerException = " + e.getMessage());
FirebaseCrash.log("Tag = " + TAG + "run: NullPointerException = " + e.getMessage());
}
}
}
};
handler.post(runnable);
Even though you are creating a Handler, the creation of the MediaPlayer still happens on the main UI thread. You should call prepareAsync or use an AsyncTask or some other means to avoid calling prepare on the main thread.
From the documentation for Handler:
When you create a new Handler, it is bound to the thread / message
queue of the thread that is creating it
If you are streaming music from the network, preparing the media for playback is especially going to take a while. One option may be to call prepareAsync instead of calling prepare. In that case, you should set the OnPreparedListener, and in that callback call start.

Async task completed abruptly. Debug View shows thread is stopped at Threadpoolexecutor.runWorker(ThreadpoolExecuter$Worker) line:1094

I'm trying to fetch Oauth token using GoogleAuthUtil.getToken and running the task as a separate thread using Async Task.
LogCat ouput shows me that the arguments required by the Async Task has been passed to it.(in this case the context, email and scope).
Here's the code of Async Task:
public class GetUsernameTask extends AsyncTask<Void, Void, Void>{
Activity mActivity;
String mScope;
String mEmail;
GetUsernameTask(Activity activity, String Email, String Scope){
Log.i(TAG,"Local variables are set from received arguments");
this.mActivity = activity;
this.mScope = Scope;
this.mEmail = Email;
}
#Override
protected Void doInBackground(Void... arg0) {
try {
Log.i(TAG,"fetchToken is called");
String token = fetchToken();
mToken = token;
//Stuff to do with the token comes here - (Consider sending it to the backend;
} catch(IOException e){
}
return null;
}
LogCat also tells me that fetchToken() method is called. Here's the code for fetchToken()
private String fetchToken() throws IOException {
try {
Log.i(TAG,"attempts to getToken");
return GoogleAuthUtil.getToken(mActivity, mEmail, mScope);
} catch (UserRecoverableAuthException userRecoverableException){
Log.i(TAG,"recoverable Exception Found");
//((MainActivity) mActivity).handleException(userRecoverableException);
} catch (GoogleAuthException fatalException){
Log.i(TAG,"fataException found");
}
return null;
}
The last logcat message before the debug mode opens up, is from Log.i(TAG,"attempts to getToken"); .
I have no idea how to proceed from here or how to do debugging in this particular case. Any direction on where to go next will be great.
There was a meta-data tag missing in the android manifest file. I added the followin code in the manifest file
<meta-data
android:name = "com.google.android.gms.version"
android:value="#integer/google_play_services_version"
/>
The error was pointed out after I had added RuntimeException which printed the suggestion. Here's the code I added for RuntimeException
catch (RuntimeException e){
Log.i(TAG, "RuntimeException caught");
e.printStackTrace();
}

Java - SWT - New runnable upon clicking submit button

I'm getting the dreaded...
Exception in thread "Controller Thread" org.eclipse.swt.SWTException: Invalid thread access
Quick overview of what I am trying to accomplish:
I have a listener on the Submit button, I would like to start a new thread due to the amount of processing the app will do with various url's.
This is part of my code in the Submit button listener...
submitButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent arg0) {
try {
// Check to see if http field is valid
httpValid = checkHttp(http);
if (httpValid) {
Thread t = new Thread(new UIMain(), "Controller Thread");
t.start();
} else {
System.out.println("Not a Valid http");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Here is my run method...
public void run() {
options = new Options();
setOptions(options);
Controller run = new Controller(options);
}
The error points to line "setOptions(options)"
options is a object, holding some data from the SWF fields that the user will input. setOptions is fairly straight forward, in that function, I gather the data from the SWF fields, and set them in the object.
Let me know if I need to post any more code...
Example of some code I'm doing in setOptions(options)...
String url = http.getText();
options.addUrl(url);
Thanks,
You can not access the SWT UI straightly from a separate thread. What you should rather do is perform an async invocation from that separate thread using the Display API.
Example:
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
// access the SWT UI
}
});

Categories