Регистр GCM блокирует AsyncTask до тех пор, пока не произойдет тайм-аут

Я пытаюсь получить идентификатор регистрации устройства с помощью GCM. Мой код для этого содержится в AsyncTask, который вызывается из моего основного потока.

Основной код

try { String deviceId = new Gcm().execute(this.activity).get(5, TimeUnit.SECONDS); Log.i("Login", "User device id returned as " + deviceId); return deviceId; } catch (Exception e) { Log.e("Login", "Exception", e); } 

Класс GCM

 public class Gcm extends AsyncTask<Activity,Void,String> { @Override protected String doInBackground(Activity... params) { Log.i("GCM", "Attempting to get device id"); Activity activity = params[0]; try { Log.i("GCM", "Getting GCM instance"); GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(activity.getApplicationContext()); Log.i("GCM", "Registering with GCM"); String regId = gcm.register(PROJECT_NUMBER); Log.i("GCM", "Device registered, registration ID=" + regId); return regId; } catch (IOException e) { throw new IllegalStateException(e); } } } 

И вот мой свалка

 07-28 13:07:39.093 I/GCM﹕ Attempting to get device id 07-28 13:07:39.093 I/GCM﹕ Getting GCM instance 07-28 13:07:39.093 I/GCM﹕ Registering with GCM 07-28 13:07:44.103 E/Login﹕ Exception java.util.concurrent.TimeoutException at java.util.concurrent.FutureTask.get(FutureTask.java:176) at android.os.AsyncTask.get(AsyncTask.java:507) I/GCM﹕ Device registered, registration ID=XXXXXX 

Поэтому по какой-то причине вызов gcm.register () блокируется до тех пор, пока не будет удалено мое исключение таймаута. Кто-нибудь знает, почему это может произойти?

Причина в том, что вы выполняете gcm с

 .get(5, TimeUnit.SECONDS); 

Этот вызов блокирует поток в течение 5 секунд, однако из-за разных причин, таких как нестабильное сетевое соединение, процесс регистрации может занять более 5 секунд. Это не лучший подход к тому, что вы хотите.

Взгляните на этот пример, взятый из официальной демонстрации GCM :

 private void registerInBackground() { new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... params) { String msg = ""; try { if (gcm == null) { gcm = GoogleCloudMessaging.getInstance(context); } regid = gcm.register(SENDER_ID); msg = "Device registered, registration ID=" + regid; // You should send the registration ID to your server over HTTP, so it // can use GCM/HTTP or CCS to send messages to your app. sendRegistrationIdToBackend(); // For this demo: we don't need to send it because the device will send // upstream messages to a server that echo back the message using the // 'from' address in the message. // Persist the regID - no need to register again. storeRegistrationId(context, regid); } catch (IOException ex) { msg = "Error :" + ex.getMessage(); // If there is an error, don't just keep trying to register. // Require the user to click a button again, or perform // exponential back-off. } return msg; } @Override protected void onPostExecute(String msg) { mDisplay.append(msg + "\n"); } }.execute(null, null, null); 

Включите этот пример, и все должно работать.

Использование AsyncTask, как это, не имеет смысла. AsyncTasks используются, чтобы избежать блокировки потока, но, используя вызов блокировки get (), вы все равно блокируете поток. Вы можете также вызвать register () непосредственно в этом случае.

Вы получаете тайм-аут, потому что вы блокируете 5 секунд, но GCM занимает больше 5 секунд для регистрации. Это может быть связано с плохими сетевыми условиями, так как для сетевого запроса может потребоваться некоторое время. Или, возможно, для получения идентификатора регистрации требуется всего 5 секунд.