Problems accesing database in FirebaseMessagingService - java

I had an app with PushBots and it was working fine. The client asked to migrate to FCM, so i did. And its mostly working perfectly. Im receiving notifications and, when the app is in the foreground, the notifications get saved. With the app in the background the notifications are still arriving without any trouble but in this case its not saving into database.
So i started with this:
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Timber.d("RECIEVED");
RemoteMessage.Notification n = remoteMessage.getNotification();
if (n != null) {
Notification notification = new Notification();
notification.setTitle(n.getTitle());
notification.setMessage(n.getBody());
notification.setDate(System.currentTimeMillis());
NotificationDAO dao = new NotificationDAO(MyApp.getInstance());
dao.create(notification);
showNotification(n.getTitle(), n.getBody());
}
}
So i thought the problem could be on the context, so i tried replacing MyApp.getInstance() with getApplicationContext(). That wasnt working, so then i changed getApplicationContext() with this. As it wasnt working neither i tried to do this access inside another thread, but none its working.
What am i doing wrong? The dao's method create is working in the rest of the application.
Regards.

If you want to use "context" in your FirebaseMesaagingService, you can use 'this'
The hierarchy of classes is as below
FirebaseMessagingService extends Service which (Service) extends ContextWrapper
which inturn (ContextWrapper) extends Context
Hence you can directly use,
'MyFirebaseMessagingService.this' or simply 'this'

Related

Android Best way to keep and share data through the app

I am making a small Android app that run a Foreground Service which listen and notify the user whenever a new SMS message arrived. When the Service start it register the BroadcastReceiver with action android.provider.Telephony.SMS_RECEIVED in IntentFilter, and unregister it when stop. The application also get the user data along with a list of selected number from a JSON file in internal storage so that the Receiver can filter out which number to notify the user. My MainActivity has 3 buttons, Start and Stop Service, along with a Setting button that move to SettingActivity that display some user info as well as the list of selected number and allow the user to change it. My question is that: What is the best way to share the user data throughout the app so that all Activity as well as Service and Receiver can access it? I have thought of and tried a few ways:
Getting the user data from file in MainActivity where the application start up and pass it through Intent to others: this worked well when passing data from Activity to Activity as well as Service, but does not seem to work with BroadcastReceiver since it is registered to listen to SMS_RECEIVED and not other Broadcast even if I create a new Intent and broadcast it with startBroadcast
Making the user object static: I tried with making the User public static so that it can be called by other class when the MainActivity is done getting the data from the file, basically putting a public static User user in MainActivity and calling it by MainActivity.user in other class, this worked even with BroadcastReceiver but I am not sure if this the right way to share data throughout the application
Lastly is to get the data from the file when each Activity or Service is called, this mean when each Activity or Service is called, it get data again from the JSON file. I have not tried it yet but I think it might impact the performance as well as data consistency throughout the app.
So what is the right way to implement this? Please give me some suggestion. Thank you guys in advance.
There are a few suggestions for this:
1 - You could store the data you need in shared preferences, though if this is personal data, that you'd want to keep private (eg passwords, personally identifiable information) you probably don't want to do this.
2 - Similarly to what you are doing in your activity, you could create a service which is responsible for getting the user data from the file and keeps hold of it until the app is killed, for example -
public class UserDataStore()
This way you can create an instance of a UserDataStore on startup and then, through dependency injection, pass it around your app. So wherever you create your service that handles the broadcast events, you can just add a UserDataStore as a parameter, assuming you create your UserDataStore first. eg -
public class BroadcastReceiverService(UserDataStore store)
This way also means that your BroadcastReceiverService is more testable as you can mock the UserDataStore.
Example -
public class MainActivity() {
UserDataStore store = new UserDataStore()
BroadcastReceiverService broadcastService = new BroadcastReceiverService(store)
}
Then in your UserDataStore -
public class UserDataStore() {
// in here you want to get all your info about the user eg username, email etc
String name = ""
init {
User user = getUserInfo()
name = user.name
}
public String getUserName() {
return name
}
}
Then finally in your broadcast receiver
public class BroadcastReceiverService(UserDataStore store) {
public void receiveMessage(Message msg) {
if(msg.username == store.name) // continue
}
}

How to use a intent in android?

I have a sony smart watch and i'm trying to invoke a vibration intent by using the following:
Intent intentImplicit = new Intent(Control.Intents.CONTROL_VIBRATE_INTENT);
startActivity(intentImplicit);
it says startActivity its not declared in the control extension. How can I fix this?
I found this online "You can get a Context object from the Constructor for the Control and save it to a member variable then just call context.startActivity()." but i'm unsure on how to do this
The Sony SDK documentation says you should use sendBroadcast()
See: http://developer.sonymobile.com/reference/sony-addon-sdk/com/sonyericsson/extras/liveware/aef/control/Control.Intents#CONTROL_VIBRATE_INTENT
So this should work:
context.sendBroadcast(intentImplicit, Registration.HOSTAPP_PERMISSION);
If you used a sample application from Sony as base, the context is already saved as a field of your class. If not, you can get a reference in the constructor of the Extension and save it to a field like this:
public class TestExtension extends ControlExtension
{
private Context context;
TestExtension(final String hostAppPackageName, final Context context, Handler handler)
{
super(context, hostAppPackageName);
this.context = context;
}
}
What is the purpose of trying to send that Intent? If you are just trying to activate the Vibration, there is already a method built into the utilities class to do this. Take a look at the ControlExtension.startVibrator() method in the SmartExtensionUtils project.

Update TextView from GCMIntentService in Methods onRegistered and onUnregistered

I want to set the text of a TextView in my MainActivity with the onRegistered and onUnregistered methods in the GCMIntentService class I've implemented. I can't set it directly because it's in a different class. What would be the best way to handle this?
A little background. I"m using the TextView to update the status on whether the device is registered or not and to display messages to the user. The reason I want to set it in the GCMIntentService is because once those methods are deplyed the device has completed the tasks. Right now when the user hits the register button it switches the status to registered, but the device isn't fully registered yet. I don't want to cause confusion or errors because they think the device is registered.
Have a look at the GCM sample app. The way to do this is:
In the GCMIntentService you extended from GCMBaseIntentService, in onRegistered/onUnregistered, you can send a broadcast message (in the example, it's DISPLAY_MESSAGE_ACTION). You just need to put the registration state in the intent, say 'REGISTRATION_STATE'. In your MainActivity, you then need to register a BroadcastReceiver and look for this message, e.g.:
private final BroadcastReceiver mHandleMessageReceiver =
new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
mTextView.setText("Registration state is: " + intent.getExtras().getString("REGISTRATION_STATE");
}
};

How to make a callback from a Service to an Activity

Sorry for bugging you again, but I still can't find a way to make a callback from my activity to a service...
Found a similar question - How to Define Callbacks in Android?
// The callback interface
interface MyCallback {
void callbackCall();
}
// The class that takes the callback
class Worker {
MyCallback callback;
void onEvent() {
callback.callbackCall();
}
}
// Option 1:
class Callback implements MyCallback {
void callback() {
// callback code goes here
}
}
worker.callback = new Callback();
yet not sure how to integrate that sample into my project.
Any suggestions or links to clear tutorials would be great!
That kind of callbacks (Observer pattern) that you are showing in your example won't work between a service and an activity. Use observer patter when, from class A, you created the instance of class B and want to send callbacks from B to A.
With regards to the services and activities, things are completely different. AFAICT, if you want to callback your Activity from a Service, the best method to achieve this is to use ResultReceiver. There are a lot of interesting things about ResultReceiver:
Its constructor receives a Handler (that you must create inside the activity), which will allow you to change UI from the service.
It implements Parcelable thus you can put a reference of your ResultReceiver in the Intent extras that you used to start the service.
Its onReceive method has a result code integer which allows you to generate different kind of callbacks (this is like if your callback interface had many methods). Also, it receives a Bundle which you can use to put all result data.
On the other hand, if you want to do a callback (not sure if that is correct term in this case), from your Activity to your Service, I guess you will have to send a Broadcast message or something like that.

Android: Passing a Service a Handler

So, I've read the android AIDL documentation and have a general idea of how RPC works between an Activity and a Service. However, for my application it seems overboard to implement such features: basically, I want to pass a Service a nice handler so its thread can pass data to my Activity. Currently I'm getting around this by using a static public member (a hack) but I would prefer just passing a Handler object in the Service's starting Intent. E.g. I can easily pass ints to my service upon creation:
int x = 0;
Intent svc = new Intent(this, MyService.class);
svc.putExtra("x",x);
startService(svc);
However since a Handler isn't serialize-able , I haven't found a way to pass it to the service without a simple static member hack. Any insight? Or, am I just going to have to suck it up and do a formal RPC to the service?
If your Service and Activity are in the same process, you can pass a Binder from your Service without doing the complicated RPC stuff:
public class MyEasyButNotGoodPracticesBinder {
public void gimmeHandler(Handler handler) {
// you got it!
}
}
IBinder mBinder = new MyEasyButNotGoodPracticesBinder();
public IBinder onBind(Intent intent) {
return mBinder;
}
Then in your Activity when you get the IBinder object just cast it to a MyEasyButNotGoodPracticesBinder and call the gimmeHandler(Handler) method. Now, I think this is bad practices because if you ever want to put your Service in a separate process so that it doesn't crash the whole process if it crashes, this would break. I don't think it's that future-proof either. But it does work.
An AIDL interface is not that hard - you may just want to do that instead.
Android documentation suggests to work with a messenger as client interface in their Remote Messenger Service Sample:
Remote Messenger Service Sample
Code example can be found in the link above, no need to repost here I guess...
Regards,
Michael

Categories