The client code for binding to a service, which is normally in the activity class; I'm trying to move it to the service class, so that the activity class would be as clean and small as possible.
i.e. basically trying to merge the code in the second box here into the first box = as much of it into the service class as possible
Single Line in Activity for Binding to Service
public class MyActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Bind to service with this line only:
AService.bindService(this);
}
}
Static bindService and ServiceConnection Moved to Service
public class AService extends Service {
public String test = "I want to see this";
public static AService aService;
private static boolean isBound;
private static Context context;
// ... IBinder, onBind etc also here on service side
public static void bindService(Context context) {
try {
Log.i(TAG, "bindService Start");
if (!isBound && context != null) {
Log.i(TAG, "Binding");
context.bindService(new Intent(context, AService.class),
serviceConnection, Context.BIND_AUTO_CREATE);
isBound = true;
Log.i(TAG, "Bound");
}
} catch (Exception e) {
Log.e(TAG, "bindService", e);
}
}
private static ServiceConnection serviceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
try {
Log.i(TAG, "onServiceConnected Start");
aService = ((AService.LocalBinder) service).getService();
if (aService != null)
Log.i(TAG, aService.test);
Log.i(TAG, "onServiceConnected Finish");
} catch (Exception e) {
Log.e(TAG, "onServiceConnected", e);
}
}
public void onServiceDisconnected(ComponentName className) {
try {
Log.i(TAG, "onServiceDisconnected");
aService = null;
} catch (Exception e) {
Log.e(TAG, "onServiceDisconnected", e);
}
}
};
public static void unbind() {
try {
Log.i(TAG, "unbind start");
if (isBound && context != null) {
Log.i(TAG, "Unbinding");
context.unbindService(serviceConnection);
isBound = false;
context = null;
Log.i(TAG, "Unbound");
}
} catch (Exception e) {
Log.e(TAG, "unbind", e);
}
}
}
But onServiceConnected is Never Called?
The log shows everything up to:
...
Bound
But NOT onServiceConnected Start or beyond
and no exceptions.
Note that when the same code was in the Activity, it works (when called with MyActivity.this)
What am I doing wrong?
Is this
AService.bindService(this);
much better than this?
bindService(new Intent(context, AService.class),
serviceConnection, Context.BIND_AUTO_CREATE);
And does ServiceConnection implementation sit in Activity really annoying your so much? I doubt that.
I don't see any point centralize everything into Service and then call a static method in the actual Service to start this Service from Activity. The best practice is to follow the standard way that Google's recommended to do things, by doing this in your way, you make your code obscure and confuse other people when reading your code (if you work in a team). It doesn't make any sense IMO.
Instead of put all your effort into isolate every single bit of service from activity, I would rather consider more on how to isolate business logic from activity and centralize them into service, and let Activity mostly focus on UI stuff.
Really hope that would help you.
Related
Ive been trying to get a class in my android app to be able to post snackbars. The class is a manager for a bluetooth connection, and ive needed to make it static in my main activity to achieve this. For this reason i cant send android context classes to it or store within in, making me unable to get the view needed to make a snackbar. All throughout the bluetooth service class i use the method runOnUiThread(() -> snackbarMsg to try to show snackbars. It used to work when i sent view as a parameter of the constructor, but only for the first time the main screen showed, if i switched activity and back it would stop working, and this also caused a memory leak. Any other way to solve this? Any help is appreciated.
Currently code looks like this in main activity:
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener{
//Initialise some static variables needed across the whole program
private static BluetoothService bluetoothService;
private static final String TAG = MainActivity.class.getSimpleName();
protected static ArrayList<LocationData> locations = new ArrayList<>();
protected static List<String> categories = new ArrayList<>();
Spinner spinner;
private static boolean doneFirstRun = false;
protected static LocationData selectedLocation = new LocationData();
MainActivity instance = this;
public MainActivity() {
}
/*
TODO: view in bluetooth service causes memory leak
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try{
if (!doneFirstRun){
//Getting storage
readFromFile(MainActivity.this);
//adding example location
if (locations.size()==0){
LocationData spaceRay = new LocationData();
spaceRay.setName("SpaceRay");
spaceRay.setLatitude(59.40384);
spaceRay.setLongitude(17.95228);
spaceRay.setInclination(-85);
spaceRay.setDirection(200);
spaceRay.setAltitude(99990);
locations.add(spaceRay);
}
//Checking and asking for relevant permissions
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
#SuppressLint("InlinedApi") String[] permissions = {Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN};
ActivityCompat.requestPermissions(instance, permissions, 1);
}
bluetoothService = new BluetoothService();
//starting bluetooth networking activity on new thread
startBluetoothService();
doneFirstRun = true;
}
} catch (Exception exception){
Log.e(TAG, "Failed to do first run through of code: ", exception);
}
...
protected void startBluetoothService(){
try {
Log.i(TAG, "New thread started");
bluetoothService.run(MainActivity.this);
} catch (Exception e) {
Log.e(TAG, "Bluetooth service failed: ", e);
snackbarMsg("Bluetooth service failed");
}
}
and like this is bluetooth_service class:
public class BluetoothService extends AppCompatActivity{
private static final String TAG = BluetoothService.class.getSimpleName();
private OutputStream outputStream;
private InputStream inputStream;
private BluetoothSocket socket;
private boolean writing = false;
public BluetoothService(){
}//constructor
...
//method to show snackbar message at the bottom of the screen
public Runnable snackbarMsg (String msg){
try {
View view = findViewById(R.id.btn_connect);
Snackbar snackbar = Snackbar.make(view, msg, BaseTransientBottomBar.LENGTH_SHORT);
snackbar.show();
} catch (Exception exception){
Log.e(TAG, "Could not show snackbar", exception);
}
return null;
}
Error message looks like this:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()' on a null object reference
at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:190)
at android.view.ContextThemeWrapper.getTheme(ContextThemeWrapper.java:174)
at android.content.Context.obtainStyledAttributes(Context.java:809)
at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:852)
at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:819)
at androidx.appcompat.app.AppCompatDelegateImpl.findViewById(AppCompatDelegateImpl.java:640)
at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:261)
at antennalocator.util.BluetoothService.snackbarMsg(BluetoothService.java:204)
at antennalocator.util.BluetoothService.lambda$write$4$antennalocator-util-BluetoothService(BluetoothService.java:159)
at antennalocator.util.BluetoothService$$ExternalSyntheticLambda5.run(Unknown Source:4)
at java.lang.Thread.run(Thread.java:1012)
Managed to get around this issue. The way i solved this was by sending the view as a parameter in each method that needed to post snackbars: for example the write method:
public void write(String s, View view) {
if (!writing){
new Thread(() -> {
try {
writing = true;
outputStream.write(s.getBytes());
runOnUiThread(snackbarMsg("Sent data", view));
lockout(3000);
writing = false;
} catch (Exception exception) {
writing = false;
Log.e(TAG, "Error occurred when sending data, restarting bluetooth service", exception);
runOnUiThread(() -> snackbarMsg("Could not send data, restarting bluetooth service", view));
disconnect();
}
}).start();
} else{
runOnUiThread(snackbarMsg("Please wait a bit before sending data", view));
}
}
in main:
bluetoothService.write(ConvertToString(selectedLocation), findViewById(R.id.btn_connect));
I Want to stop my service and stop get data to ma handler which I have in activity. And service I connect to USB and get data from this port.
I try did this:
usbService.stopSelf();
Intent intent = new Intent(MainMenu.this, UsbService.class);
usbService.stopService(intent);
but all the time I have a data from service.
I start my service just like this:
private void startService(Class<?> service, ServiceConnection serviceConnection, Bundle extras) {
if (!UsbService.SERVICE_CONNECTED) {
Intent startService = new Intent(this, service);
if (extras != null && !extras.isEmpty()) {
Set<String> keys = extras.keySet();
for (String key : keys) {
String extra = extras.getString(key);
startService.putExtra(key, extra);
}
}
startService(startService);
}
Intent bindingIntent = new Intent(this, service);
bindService(bindingIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
You need to unbind your service first, by calling unBindService.
As you can see in the Service documentation:
Note that if a stopped service still has ServiceConnection objects
bound to it with the BIND_AUTO_CREATE set, it will not be destroyed
until all of these bindings are removed. See the Service documentation
for more details on a service's lifecycle.
you need to unbind all objects bound to the service before stopping it in order to destroy the service.
EDIT: Answer to your question. Add a boolean variable mBound. Override these methods.
public void onServiceConnected(ComponentName className, IBinder service) {
mBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
In your activity's onStop method, add this:
#Override
public void onStop()
{
super.onStop();
if (mBound) {
try {
unbindService(mConnection);
} catch (java.lang.IllegalArgumentException e)
{
//handle exception here
}
}
mBound = false;
}
Whenever my application is minimized I start a service that is sending pull requests to my HTTP server to check for notifications, when the application is brought back up the service gets terminated (along with the scheduled runnable). All works well until I decided to kill the application (slide it off the screen from the running apps list). Then for some reason the properties of the service get reset (even the static ones) and onStartCommand gets called again with it's first parameter Intent as null which is weird for me.
Here are some parts of the code
public class DnActivity extends Activity {
protected String cookieString = "";
protected String userAgent = "";
protected WebView webview;
#Override
protected void onStop() {
super.onStop();
try {
Intent mServiceIntent = new Intent(this, PullService.class);
mServiceIntent.putExtra("cookieString", cookieString);
mServiceIntent.putExtra("userAgent", userAgent);
startService(mServiceIntent);
} catch (Exception e) {
Log.d("DNev", e.getMessage());
}
}
#Override
protected void onStart() {
super.onStart();
Intent mServiceIntent = new Intent(this, PullService.class);
stopService(mServiceIntent);
}
#Override
public void onCreate(Bundle savedInstanceState) {
...
webview.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
try {
cookieString = getCookieFromAppCookieManager(url);
} catch (Throwable e) {
Log.e("DNev", e.getMessage());
}
}
});
}
}
And the service
public class PullService extends Service {
protected static String cookieString;
protected static String userAgent = "Mobile APP for Android";
protected Service PullService = this;
protected ScheduledFuture interval;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
if (intent.hasExtra("cookieString")) {
cookieString = intent.getStringExtra("cookieString");
}
if (intent.hasExtra("userAgent")) {
userAgent = intent.getStringExtra("userAgent");
}
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
interval.cancel(true);
}
#Override
public void onCreate() {
super.onCreate();
Log.d("DNev", String.valueOf(cookieString));
Log.d("DNev", String.valueOf(userAgent));
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
interval = scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
public void run() {
Log.d("DNev", "1");
Log.d("DNev", String.valueOf(cookieString));
Log.d("DNev", String.valueOf(userAgent));
...
As I said, everything works fine until I destroy the activity, then the interval keeps running but cookieString and userAgent become their default values.
I need to be able to persist these values when the activity gets destroyed, how can I do that?
I'm not experienced in neither android nor java development, and I want to apologize if my code made anyone cry blood.
Here is the manifest entry for the service, it resides in <application
<service android:name=".PullService" android:exported="false"/>
All works well until I decided to kill the application (slide it off the screen from the running apps list).
When you kill the app (which I assume Force Stop from i.e. Settings -> Apps) then WHOLE app gets terminated, including its services. Everything stored in variables will go away with the process. If you want it to survive, you need to store it in persistent storage (i.e. in database or shared preferences).
Also I'd save this data once I received it, in onStartCommand() because if onDestroy() will not be called (which is not unlikely for abruptly killed process) then your data would be lost.
I start a service that is sending pull requests to my HTTP server to check for notifications
Don't. Use GCM to actually push notification to the app. Do not pull.
in the DnActivity.onDestroy() method, save the info somewhere, you could have the "shutting down" of the activity control the mServiceIntent and do alterations to it (like shutting it down as well)
For instance:
DnActivity.onDestroy(){
super.onDestroy();
stopService(mServiceIntent);
Intent mServiceIntent = new Intent(this, PullService.class);
mServiceIntent.putExtra("some_value", the_value);
mServiceIntent.putExtra("some_other_value", the_other_value);
startService(mServiceIntent);
}
I am starting to migrate some PC Java applications to Android environments being a complete newbie concerning Android platform.
I found a problem when I tried to use a Service reference as context for a Toast message.
This is the relevant part of my Service code:
public class ServicePFPE extends Service {
Timer messageSimulator;
TimerTask messagePoll;
private class MessageReceptionTask extends TimerTask
{
public MessageReceptionTask(Context c) {
context = c;
}
#Override
public void run() {
String shownText = "Message received!! on " + (new Date(System.currentTimeMillis())).toString();
//doToast(shownText, context); //THIS LINE MAKES THE APP CRASH!
System.out.println(shownText); //But I can do this
}
private Context context;
}
public ServicePFPE() {
super();
messageSimulator = new Timer();
messagePoll = new MessageReceptionTask(this);
}
#Override
public IBinder onBind(Intent intent)
{
doToast("Service: onBind");
return null;
}
...
...
...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
doToast("Service: onStartCommand");
messageSimulator.schedule(messagePoll, 5000, 5000);
return super.onStartCommand(intent, flags, startId);
}
...
...
...
private void doToast(String msg) { doToast(msg, this); }
private void doToast(String msg, Context con) {
Toast.makeText(con,msg,Toast.LENGTH_SHORT).show();
}
}
When the scheduled task runs reaching doToast call Android notifies that "Unfortunatelly, myAPP has stopped".
I think it has something to do with the fact I am using the service context in a different thread but I don't know for sure.
Could you confirm if that is the case? What is the right way to run a timer from a service and be able to use its context? If that is not possible, can I get a context for that thread so I can generate Toasts user messages.
It depends on what you really need, if you are planning to show simple notifications, maybe instead of toasts you can use Android notification bar (which is the standard way to show them). For example you can use:
/**
* Show a notification while this service is running.
*/
private void showNotification() {
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.local_service_started);
NotificationManager mNM;
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.stat_sample, text,
System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, LocalServiceActivities.Controller.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.local_service_label),
text, contentIntent);
// Send the notification.
mNM.notify(NOTIFICATION, notification);
}
however, if you just want toasts, you can show them from the service, your problem is that the timertask is being executed in a different thread that the UI thread (where the service is running). to "post" this code to the UI thread you can do it directly with something like this:
Handler handler;
#Override
public void onCreate() {
// Handler will get associated with the current thread,
// which is the main thread.
handler = new Handler();
super.onCreate();
}
private void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
Source
And finally if you want fully interaction between service and activities, you have several ways:
Use binders, for simple communications, this is moreless what you need.
Use a messenger, to more complicated communications.
If you only need dialogs you are always able to launch new activities in dialog mode.
AIDL...
Documentation about 1 & 2 here and here
Binders:
They let you bind different objects in your application letting them access directly to the object itself and its functions, example from android doc:
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
public class BindingActivity extends Activity {
LocalService mService;
boolean mBound = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute) */
public void onButtonClick(View v) {
if (mBound) {
// Call a method from the LocalService.
// However, if this call were something that might hang, then this request should
// occur in a separate thread to avoid slowing down the activity performance.
int num = mService.getRandomNumber();
Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
Messenger:
More advanced & complicated, in this way you can send messages from one object to another:
public class MessengerService extends Service {
/** Command to the service to display a message */
static final int MSG_SAY_HELLO = 1;
/**
* Handler of incoming messages from clients.
*/
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service.
*/
#Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();
return mMessenger.getBinder();
}
}
public class ActivityMessenger extends Activity {
/** Messenger for communicating with the service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mBound;
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mService = new Messenger(service);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mBound = false;
}
};
public void sayHello(View v) {
if (!mBound) return;
// Create and send a message to the service, using a supported 'what' value
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MessengerService.class), mConnection,
Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
}
In case you want to show activities as fancy dialogs to show the updates you can use a regular activity with this theme:
<activity android:theme="#android:style/Theme.Dialog" />
Any UI related code should be ran on the UI thread using RunOnUiThread method.
you should set a global context like this:
public static Activity currentActivity=null;
and after run your main activity or any activity that runs service set context like this:
MainActivity.currentActivity = this;
after that in toast use this context:
Toast.makeText(MainActivity.currentActivity," text", Toast.LENGTH_LONG);
hope use full
Here's the scaffolding code of my Dashclock extention. It receives messages from GCM and displays the information.
public class ComputerWidget extends DashClockExtension {
private MessageReceiver objMessageReceiver;
private class MessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context ctxContext, Intent ittIntent) {
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(ctxContext);
String strType = gcm.getMessageType(ittIntent);
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(strType)) {
showInformation(ittIntent.getExtras());
}
}
}
#Override
protected void onInitialize(boolean booReconnect) {
super.onInitialize(booReconnect);
if (objMessageReceiver != null) {
try {
unregisterReceiver(objMessageReceiver);
} catch (Exception e) {
e.printStackTrace();
}
}
IntentFilter intentFilter = new IntentFilter("com.google.android.c2dm.intent.RECEIVE");
intentFilter.addCategory("com.something.something");
objMessageReceiver = new MessageReceiver();
registerReceiver(objMessageReceiver, intentFilter);
}
public void onCreate() {
super.onCreate();
}
protected void showInformation(Bundle bndBundle) {
final ExtensionData edtInformation = new ExtensionData();
setUpdateWhenScreenOn(true);
try {
if (bndBundle.getString("event").equalsIgnoreCase("logon")) {
edtInformation.visible(true);
edtInformation.expandedTitle(bndBundle.getString("machine"));
edtInformation.expandedBody(getString(R.string.logon, bndBundle.getString("username")));
}
} catch (Exception e) {
edtInformation.visible(false);
}
edtInformation.icon(R.drawable.ic_dashclock);
publishUpdate(edtInformation);
}
public void onDestroy() {
super.onDestroy();
if (objMessageReceiver != null) {
try {
unregisterReceiver(objMessageReceiver);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
protected void onUpdateData(int arg0) {
setUpdateWhenScreenOn(true);
System.out.println("Update");
}
}
As you can see, I'm registering my GCM BroadcastReceiver when my extension is initialized and I'm unregistering it when the extension is destroyed.
This piece of code works just fine as long as the receiver is initialized but Dashclock, after a period of inactivity, destroys the extension and therefore I can't receive any GCM messages.
How can I keep the BroadcastReceiver alive so that I can receive GCM messages? Is there a way to accomplish this programatically and not through the manifest file?
I came to this solution after my last question regarding BroadcastRecievers — How do I publish an update to Dashclock when my application receives an Intent?
How can I keep the BroadcastReceiver alive so that I can receive GCM messages?
Register it in the manifest, the way the GCM samples show you.
Is there a way to accomplish this programatically and not through the manifest file?
No, but you can enable and disable the manifest-registered receiver via PackageManager and setComponentEnabledSetting().