Android Best way to keep and share data through the app - java

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

Related

Problems accesing database in FirebaseMessagingService

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'

Create object from a class. Save the object. Call the object from a third class

For this project, I'm using Android Studio.
I've tried a bunch of things.
Goal:
I would like to create an application which asks the user to input data. The data needs to be saved and later be called on another screen as a log history which the user can see.
What I've done:
I have three classes: "InputScreen" "Logs" "LogHistoryScreen"
I've tried to create Logs object at InputScreen which works perfectly fine such as: Logs log1 = new Logs(); But I have no idea how to call the object log1 made in InputScreen from the LogHistoryScreen. Anyone who have any suggestions?
Thanks in advance.
Create a list of logs in InputScreen class:
List<Log> logs = new ArrayList();
logs.add(log1);
// same for next logs.
then create a method in InputScreen which will return the list of logs. Something like this:
public List<Log> getAllLogs() {
return logs;
}
Call this method from LogHistoryScreen like:
InputScreen inputScreen = new InputScreen();
List<Log> logs = inputScreen.getAllLogs();
There are various options you could use here. I will mention a few here.
1) Passing through Intent.
Pass the Object as a parameter while you open the LogHistoryScreen from the InputScreen.
Please follow the below code to do so.
Intent intent = new Intent(this, LogHistoryScreen.class);
intent.putExtra("Key", yourObject);
startActivity(intent);
Receive the Object in the onCreate() of the LogHistoryScreen activity
Log log = (Log)getIntent().getSerializableExtra("Key");
The Log.class must implement Serializable.
public class Log implements Serializable
{
}
2) Store the Object in the Database and retrieve it from the other activity. This is particularly helpful if you need the data to persist across app sessions.
I think the first option will be more helpful for you.

updating UI with a volley request from a different class

I am having trouble with volley (again). I want to run a volley request in a class, so more than one activity can feed off its results and update their UI's accordingly. I have got it return data and call the request from the UI but now im struggling to update the UI with the new data. I have looked at answers but I'm trying to understand the structure and I am at a loss, can some please advise/ talk me through it
assuming I understand what you mean as being:
A Volley request returns, updates some data set through some activity
In this case, assuming the calling activity contains everything, and reminding that this is a very general example, what you should usually do (usually, since there are exceptions to the case), is just insert the data into the data set contained in your UI holder (e.g. your recycler adapter) and update it, an example would be your adapter holding a method similar to this:
public void updateDataSet(List<Item> items)
{
//mItemList is the adapters member list
if (null != mItemList)
{
mItemList.clear();
mItemList.addAll(items);
}
else
mItemList = items;
notifyDataSetChanged();
}
you call this inside the request callback you fired earlier, just make sure to initialize everything BEFORE you fire the request, e.g.
#Override
public void onResponse(JSONObject response)
{
Log.d(TAG + ": ", "somePostRequest Response : " + response.toString());
// here you need to parse to JSON to a list and then call...
List<Item> items = parseResponse(response);
myAdapter.updateDataSet(items);
}
Now, if what you meant was
A Volley request returns in some Activity, I want it to update stuff in another place
there are a couple of options:
As someone said in the comments - you could go for EventBus.
You could hold a DataManager class, which would be a global singleton, in which case you can either hold the data and update it there, and then every activity (in it's onResume or other relevant lifecycle method) knows to pull that data.
You could do the same as option 2, with the exception of that DataManager holding a reference to other UI parts (e.g. Fragments), and triggering member methods in them that pass the data and trigger the updates.
Personally I find option 3 cumbersome and somewhat bad practice, but if all else fails, (and it shouldn't, but if it does) then you can try.
There are more options out there, it depends and varies according to the data, your app architecture, coding style and other stuff you apply.
Hope this helps!
You can use EventBus. To use EventBus you need to register class where you will receive update and when you publish event for those event all classes will receive it.
Here is an example using greenrobot's EventBus :
Event Model :
public class MessageEvent {
/* Additional fields if needed */
}
Subscribe :
EventBus.getDefault().register(this); // In Activity onCreate method
#subscribe
public void onMessageEvent(MessageEvent event){
// this is the method to receive event
}
Publish event :
EventBus.getDefault().post(new MessageEvent());
Now every class subscribed for this event model will be updated.
Note : subscribed classes have to alive, If anyone destroyed they won't receive update.

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

Register in android a session like value shared by all activity

How can I register data (like integer or poco objects) shared by all activity like the id of the user ? Have I to use a simple singleton or is there a special Android way ?
Note : I don't need to make that data persistant (no need of SharedPreferences or sqlite)
Thank you
You can create your own class that implements Application and specify this in your manifest file. In that case, every time you call getApplicationContext you will get a reference of your application that can hold any kind of information.
How to declare global variables in Android?
Sample code:
class MyApplication extends Application {
public void setMethod() {
//
}
}
((MyApplication)getApplicationContext()).setMethod()
The android way is to create a custom Application for your project. Then in onCreate of that application you initialize whatever you need, and for example from an Activity do something like:
((MyApplication) getApplication()).getMyData()
If using roboguice you can use a #Singleton injection which basically does the boilerplate of a singleton for you - that's much nicer.

Categories