Search code examples
androidgoogle-cloud-messagingandroid-build

Google Cloud Messaging Example Main Thread


I'm having a problem with the Google Cloud to Device messaging example. I'm following the instructions here(https://github.com/GoogleCloudPlatform/gradle-appengine-templates/tree/master/GcmEndpoints) as this was the instructions given by Android Build when I created the project. As per the instructions I've created the required classes to register and receive messages. The register was created as an AsyncTask and called from the OnCreate method of my Main App. The problem I have is every time it runs I get an IOException: MAIN THREAD. I tried changing the code to a Runnable to no luck I just get the same error. Everything I've read in the Documentation, says that what I've done should work, so I can't understand why its not.

Below is a Logcat dump showing the error and stack trace

10-19 13:04:21.637    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ java.io.IOException: MAIN_THREAD
10-19 13:04:21.637    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at com.google.android.gms.gcm.GoogleCloudMessaging.register(Unknown Source)
10-19 13:04:21.647    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at com.hillbilly.kidslauncher.GcmRegistrationAsyncTask.doInBackground(GcmRegistrationAsyncTask.java:75)
10-19 13:04:21.647    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at com.hillbilly.kidslauncher.MainActivity.onCreate(MainActivity.java:43)
10-19 13:04:21.657    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at android.app.Activity.performCreate(Activity.java:5008)
10-19 13:04:21.657    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
10-19 13:04:21.667    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
10-19 13:04:21.667    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
10-19 13:04:21.677    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at android.app.ActivityThread.access$600(ActivityThread.java:130)
10-19 13:04:21.677    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
10-19 13:04:21.677    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at android.os.Handler.dispatchMessage(Handler.java:99)
10-19 13:04:21.687    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at android.os.Looper.loop(Looper.java:137)
10-19 13:04:21.687    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at android.app.ActivityThread.main(ActivityThread.java:4745)
10-19 13:04:21.697    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at java.lang.reflect.Method.invokeNative(Native Method)
10-19 13:04:21.697    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at java.lang.reflect.Method.invoke(Method.java:511)
10-19 13:04:21.707    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
10-19 13:04:21.707    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
10-19 13:04:21.717    1291-1291/com.hillbilly.kidslauncher W/System.err﹕ at dalvik.system.NativeStart.main(Native Method)

Any help great fully received.

As requested here is the relevant code:

the onCreate Method from the main Activity:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.setContentView(R.layout.activity_main);
    new GcmRegistrationAsyncTask().doInBackground(this);
}

The Registration Class

package com.hillbilly.kidslauncher;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;
import com.appspot.kidslauncherparent.registration.Registration;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import com.google.api.client.extensions.android.http.AndroidHttp;
import com.google.api.client.extensions.android.json.AndroidJsonFactory;
import com.google.api.client.googleapis.services.AbstractGoogleClientRequest;
import com.google.api.client.googleapis.services.GoogleClientRequestInitializer;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 * Created by craighillbeck on 19/10/2014.
 */
public class GcmRegistrationAsyncTask extends AsyncTask<Context, Void, String> {
private GoogleCloudMessaging gcm;
    private Context context;
    private Registration regService = null;

    // TODO: change to your own sender ID to Google Developers Console project number, as per instructions above
    private static final String SENDER_ID = "978823093525";

    /**
     * Override this method to perform a computation on a background thread. The
     * specified parameters are the parameters passed to {@link #execute}
     * by the caller of this task.
     * <p/>
     * This method can call {@link #publishProgress} to publish updates
     * on the UI thread.
     *
     * @param params The parameters of the task.
     *
     * @return A result, defined by the subclass of this task.
     *
     * @see #onPreExecute()
     * @see #onPostExecute
     * @see #publishProgress
     */
    @Override
    protected String doInBackground(Context... params) {
        context = params[0];
        if (regService == null) {
            Registration.Builder builder = new Registration.Builder(
                    AndroidHttp.newCompatibleTransport(),
                    new AndroidJsonFactory(), null)
                    // Need setRootUrl and setGoogleClientRequestInitializer only for local testing,
                    // otherwise they can be skipped
                    .setRootUrl("http://10.0.2.2:8080/_ah/api/")
                    .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
                        @Override
                        public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest)
                                throws IOException {
                            abstractGoogleClientRequest.setDisableGZipContent(true);
                        }
                    });
            // end of optional local run code
            builder.setApplicationName(context.getString(R.string.app_name));
            regService = builder.build();
        }



        String msg = "";
        try {
            if (gcm == null) {
                gcm = GoogleCloudMessaging.getInstance(context);
            }
            String 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.
            // The request to your server should be authenticated if your app
            // is using accounts.
            regService.register(regId).execute();

        } catch (IOException ex) {
            ex.printStackTrace();
            msg = "Error: " + ex.getMessage();
        }
        return msg;
    }


    /**
     * <p>Runs on the UI thread after {@link #doInBackground}. The
     * specified result is the value returned by {@link #doInBackground}.</p>
     * <p/>
     * <p>This method won't be invoked if the task was cancelled.</p>
     *
     * @param msg The result of the operation computed by {@link #doInBackground}.
     *
     * @see #onPreExecute
     * @see #doInBackground
     * @see #onCancelled(Object)
     */
    @Override
    protected void onPostExecute(String msg) {
        Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
        Logger.getLogger("REGISTRATION").log(Level.INFO, msg);
    }
}

Solution

  • That's not how you execute a background task in the background. Simply calling the doInBackGround() method executes this method in the same (main) thread, which causes your execption.

    new GcmRegistrationAsyncTask().doInBackground(this);
    

    The right way is :

    new GcmRegistrationAsyncTask().execute(null,null,null);
    

    Here's an example from the official GCM demo :

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