I'm a just diving head first into Android Studio and am working on my first app which is a sort of surfing log application. Basically it is to keep track of various weather conditions each time the user goes out surfing.
I have created a Java class "Session" with the following fields:
Date (Date)
Location (String)
Tide height (float)
Surf size (float)
more to come, keeping it simple for now.
My application will flow as follows:
There will be a Main home screen activity, with buttons, and also a small tableview that displays your 3 most recent sessions.
Buttons including:
New Session: this takes you to a new activity with various text inputs for each of the above fields, a date selector... and a save button.
My Sessions: this will take you to a tableview where you can view all of your past sessions. You can organize them by location, date, surf size...
Thus my question:
What is the best practice to pass all this data between the various activities?
To me the most obvious way to go about this is to have a central ArrayList that gets loaded in the main activity and then this gets somehow passed around to all of the subsequent activities. It contains all the sessions that you have ever created.
So lets say I tap the "new session" button on the main screen. This takes me to the new Session activity. I enter all the fields and hit save. I would like to take this data, create a new session object and then add this to the array back in Main Activity. So far my research tells me to pass all this data back using a bundle and the intent.putextra() technique. However it seems cumbersome. Is there not a better approach where I could just create a new object of my Session class and then append it to the central array?
Again let's say I tap the 'my sessions' button from the main activity. I would like this to load up a new activity which is a tableview that allows the user to scroll through all of their previously created sessions and tap on one to view the details.
I've done a bit of research and it seems there are various ways of going about this, I've read up a bit on Singletons, I've looked into creating some sort of static class that I could then reference from multiple activities, I've read about parcelable and serializable...
Perhaps though someone with some android experience could shed some light on the most efficient and standard way of accomplishing what I would like to do.
Again I want to reiterate that this Array or collection of "Sessions" is going to be the center of the app. Pretty much every activity I implement down the road is going to be using this data in someway or another. Whether it's displaying it a tableview which can be sorted in different ways, to running statistical analysis on it, to displaying pins on a map of each location...
I think you want to keep your data in a database and use a pub/sub workflow to keep track of it.
For example, you can use Firebase. Everytime a part of your application does an update (even a different user on a different device) any other part of your code can listen to that change and capture it.
Firebase is just an example, RethinkDB, MongoDB all have this option.
It is not a good option to use a data structure that is on your app: it will become really messy if it needs to be shared between different parts of your app, and impossible if you need other users to be aware of the change.
I think you should go for an event-based library like RxJava2. you can easily subscribe to a bus (subject) which emits all data created up till now.to keep other app's components up-to-date.
for you specefic use case. there is sth great in RXjava2 is called Replay Subject
Replay Subject:
It emits all the items of the source Observable, regardless of when the subscriber subscribes
a simple implementation would look like
public class RxReplayBus {
private static ReplaySubject<Object> subject = ReplaySubject.create();
private RxReplayBus() {
// hidden constructor
}
public static Disposable subscribe(#NonNull Consumer<Object> action) {
return subject.subscribe(action);
}
public static void publish(#NonNull Object message) {
subject.onNext(message);
}
}
from your component subscribe :
disposable = RxReplayBus.subscribe(new Consumer<Object>() {
#Override
public void accept(Object o) throws Exception {
}
});
and unsubscribe using :
disposable.dispose();
Related
Imagine we have a chat application and conversation page has been opened. If one of messages edited by other user or message's state changed from sent to deliver, Action update Store with new messages metadata. For example,after these actions we have a list of messagesState or messagesText or simply messages with modified data in our Store . So in this scenario we don't know which row has been edited and we render all the data in view again. Is this behavior one of Flux principles? Isn't better to update and send event about updated object only?
( I developing Android application and so I don't use reactJS or other library like this)
Also I going to think it's good if we mix MVP with Flux! because if one view want to change itself we have to put logic in view.for example view directly get store data and check it belongs to which element! I think a presentation layout is good for this type of situation. Has anyone tried this?
So in this scenario we don't know which row has been edited and we render all the data in view again. Is this behavior one of Flux principles?
Yes, it is! One of Flux principles is immutability of data, in order to avoid doing incremental change handling on every object in a parent data structure. This also immediately answers your second question:
Isn't better to update and send event about updated object only?
There are plenty of helper libraries for your Android project out there to establish immutable datastructures. To name just a few:
https://github.com/immutables/immutables
https://github.com/konmik/solid
In comparison, ReactJS is able to only perform updates on the "UI-Layer", the DOM, by comparing the current DOM tree to the to-be-updated DOM tree and therefore can perform incremental updates.
You could mimic such a behaviour in your Android views, by implementing something analog to the shouldComponentUpdate() function of ReactJS for your views.
If I have a class that contains a static variable, say x:
class MyClass {
static boolean x = false;
// Other methods
}
Now let us say that, hypothetically, I set x = true; from my first activity. Is there any point through the rest of my app's life cycle (including various activities and threads) where this value will simple be 'reset' back to false due to how the 'Google JVM' or the android environment works? I have heard that static variables have a 'lifetime', that dies when the program dies. Do Activities count as separate 'programs'? What about services? Or even Widgets?
I am asking this because it is often difficult to share complex data structures that rely on other complex processing (like syncing data from an online database) in android due to how 'separated' activities are, and static variables are often a very quick and dirty solution to the problem. Other things I have tried include serialisation, but that doesn't really seem like a practical solution either (constantly serialising and decoding objects when the user navigates from one activity to the next seems like it would be very resource intensive).
If I am an evil person for doing this, please tell me what I am doing wrong, or even better, give me some links or examples of better ways to solve this problem.
Yes. There are times where that will reset. Primarily if the user leaves the app and starts fiddling around with other apps or if the user lets the phone go to sleep for a long period of time. The Android process could kill the actual app. Then the "state" of the app will be restored when the user comes back, however static variables will be at their defaults because the actual process was rebuilt.
Generally passing small objects between Activities and Services is done by overriding the Parcelable interface. This will allow you to save and restore objects using setOnInstanceState methods of both Activities, Views, and some adapters. They will likewise, have a restore method in which you can rebuild the object. Parcelable is preferable over Serializable.
Larger data may require a shared file or database depending on the data that you want to have synced. There is a 1 MB size limit for parcelables being passed between Activities. One common tactic is to save the information to a file and send a URI to the location of where the information can be retrieved.
Answering your question - yes, there is a situation when you set x = true and value will be 'reset' back to false. Well, not exactly reset but consider this scenario: you have an activity and a service. Service is using separate process (you can define that in AndroidManifest when you declare your service). Then those two processes (main app and service) won't share memory and setting x to true in your activity won't affect the value of MyClass.x in your service. In all other cases changing value in one place will be visible everywhere else. Hope it helps!
No, a static variable will not be changed unless you change it or the app ends, it is safe (but generally unclean) to use it. Closing the activity the variable lives in won't hurt it.
You suggest you just need to keep track of a value as you move around activities. In that case you can add the value in your Intents as what is called an 'extra'. If you need to also pass back the value after, android also has the startActivityForResult feature
Intent extras example:
x below could be any type of value including any object which implements Parcelable
Intent intent = new Intent(...);
intent.putExtra("myKey", x);
startActivity(intent);
in receiving class:
x = getIntent().getBooleanExtra("myKey");
Edit:
Given your additional comment - "lists of objects that contain yet more lists of objects" you may get a Parcel too large exception when trying to use extras, but this is an indication you have a bigger architectural problem and that there may be a better approach
Use Gson.
Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.
You have two options. Convert to string , then put data in an intent then pass to activity. Or Convert to string with gson, save to a preference, then in the other activity, check if the preference is alive and read from it.
If you wish to be bold, you can persist to database preferably using Realm for Android or ObjectBox is a new mobile object database optimized for performance. With ObjectBox, we are bringing technology from NoSQL server databases to mobile.
I'm more used to procedural programming and what I've done basically works but when I look at it I think it can't be very efficient and there must be a much better way of doing the same thing. Could someone show me what it is? At the root of this is how to load different views from main.java and dispose of them based on the contents of a database.
I am building a database application with a Java Interface, using JDBC. I want to be able to load 3 different GUIs for 3 different users, depending on which one logs on. My initial stab at this is to build a java bean class for each table in the database and corresponding Manager classes to deal with interacting with the database. At the user end of things, I load a login window for them to attempt to access the database. When the user enters their correct login details, these are saved to a Singleton class named Session.java for reference while they're using the program, so that I don't have to go back and forth to the database to check for their information. The Singleton class is then used to determine the appropriate interface to load for them. I was doing this from Main.java like this:
LoginScreen login = new LoginScreen();
JohnsView john = new JohnsView();
MarysView mary = new MarysView();
PaulsView paul = new PaulsView();
login.setVisible(true);
login.setLocationRelativeTo(null);
//while the user has not completed login hide their database interface screen
while (!Session.isLoginSucessful()) {
john.setVisible(false);
mary.setVisible(false);
paul.setVisible(false);
}
when the user enters their login details via the GUI I check if their user name and password matches an entry in the database. If it does I set the variables in the Singleton class named Session.java like
this:
Session.setTheUserID(user.getIduser());
Session.setTheUserName(user.getUserName());
Session.setTheUserPassword(user.getPassword());
Session.setTheUserLevel(user.getUserLevel());
Session.setTheUserStaffID(user.getStaffID());
Session.setLoginSucessful(true);
then back in main.java I use a switch statement to .dispose() of the unneeded views and make the appropriate one visible like this:
//dispose of login once it's finished with
login.dispose();
//get the user 'level (1,2 or 3) from the singleton class...
int usrLev = Session.getTheUserLevel();
//check their level with the switch statement for the appropriate view to load
switch(usrLev) {
case 1:
john.setVisible(true);
mary.dispose();
peter.dispose();
break;
case 2:
mary.setVisible(true);
john.dispose();
peter.dispose();
break;
case 3:
peter.setVisible(true);
mary.dispose();
peter.dispose();
break;
default:
break;
}
I know I could approach this problem differently and put the login box into a bigger Jframe and manipulate the contents of the Jframe based on who logs on. I've looked at some examples of this in answer to other questions on here, but this wouldn't achieve what I want it to. I want to be able to load different views from Main depending on variables derived from the database. Do I need some kind of view manager class that's called from main? I've tried this a few times but end up deleting it because it doesn't make sense when I try it. I can't seem to figure this out in java. Any help with understanding this and answering it is appreciated.
OK. I solved this. Though rather than delete the post, I thought I'd leave it here for anyone else who is more used to procedural programming than OOP.
Basically nothing happens in Main apart from launching the first window of the application. In my case a login screen. Many people delete main, but I found it useful to keep it as I may want to do some multi-threading to handle communications with the database in the future, if I push the database onto a server rather than have it on my local machine.
Basically the code in the 3rd block above goes in the GUI code, inside the button action method that handles button presses for logging on. In that method you listen for input from the user, check if it matches what's in your database. If It doesn't tell them so through some visual feedback. If it does allow the code to progress to block three above, whereupon you load the view you want and call this.dispose() on the current view.
I'll leave this for a bit. if its not a useful contribution, I'll delete it.
I am currently making an android app for a friend who is a photographer where he will display his images in a RecyclerView. We would like to have sort of like a "like" feature where they can like his pictures. My question is, how would I keep track of the "likes"? What I mean is, how can I make it so that if someone already liked it, they cannot exit the app, come back and like it again? I thought about adding a +1 every time there was a like to the image properties in a database, but how can I keep them from exiting the app, coming back, and liking it again? TIA!
your problem is just a matter of identity. To achieve your goal, you should have a way to identify every piece of the pictures and each of the person who will give up-votes to these pictures.
If you can identify different pictures and different users, you can achieve your goal by either of the following ways:
For each of the pictures store all the users that have liked it. And every time a user want to like a picture, you should check whether he is in this collection or not. Only add the identity of the user to this collection if he is not in this set which means he did not like this picture before
Or you can store all the pictures that are liked by the user.
Which way is better depends on your other use cases.
To identify your pictures you can just assign a distinct name for each of the picture.
So you can see the key problem it how to identify your users.
Since you do not provide a detailed use case of the like action, I will describe some general ideas.
If you have a server
If the user must login, you can identify your users by their login id
If your user do not need to login, you can use some other information to identify your user for example their device id, MAC address or other device-specific indentity.
If you do not have a server, then how can you identify all the users that use the same device? The only way I can come up with is that, you must implement a local user system and ask the user to log in before they want to like a photo.
If you have so signing in users my guess is that you can't. You could save on a hidden file on the device the ids of the photos the device "liked" but this can be easily deleted if the user deletes the apps cache files or uninstall/reinstall.
Not an android expert here, just mho
With login:
In your Database there are "User", "Image" and "User_like_image"
You just have to check if this user didnt already upvoted the image
without login:
You locally store the ID of every images he upvoted
A rough idea: with each item that can be liked store a list of ids that liked it on the server. Your like count is equals to the list length.
On each device generate a random device id token (UUID.randomUUID() is always a good candidate), persist it locally on the device (e.g. in SharedPreferences - wiping the app data will kill it but that can't be solved reliably) and send it to the server with each request.
The server can now
tell you whether you already liked an image which is nice to see on the device and
reject multiple likes from the same device
A simpler approach: store locally in e.g. SharedPreferences that you liked the item. Then behave nicely and don't send another like request to your server backend when you see that you already did. Can be abused because it relies no the client software to be nice but I doubt a small photographer app needs to care too much about that.
A more elaborate approach: require user accounts. That works accross devices and persists through app uninstalls. People that go far enough to create multiple accounts to vote multiple times can't be stopped anyways. The big downside is that people will most likely not want to have another account just to like some photos. Would not recommend if avoidable.
What I did to avoid having people like the same item twice was:
Have 2 states with the same button. If you clicked on "like" the button state changes to "Remove Like" Save the state of the button in shared prefs and check the state before a click is given.
Example:
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
String ButtonText = button.getText().toString();
if(ButtonText.equals("Like"){
//code for Like
button.setText("Remove Like");
}
else{
//code for remove Like
button.setText("Like");
}
}
});
I have something of an abstract question regarding managing live feeds/polling on web sites.
I am creating a web app (built on Java/Spring/Hibernate) and on the user's home page I want a live feed of the latest activity from all the members of there team, and I am trying to work out the best way to handle this query on the server side.
The brute force way would be to load the current users list of team mates, and then iterate through each of his team mates, loading their latest conversations/file uploads/etc, and then merging all this activity in to a single list sorted by timestamp and returning that (lets say for sake of example that we just return the top 10 latest activity for the feed).
However, that seems very un-performant, especially as this operation would need to be done regularly (depending on the polling interval).
I have also considered making all the potential activities (conversations/status updates/uploads) as extending an Activity class and then just having a direct SQL/JPQL query in a DAO that selects all the latest activity from a set of users to be returned, but concerned that might bypass the caching and continued access to the DB would also reduce performance.
Has anyone handled this type of problem before? any one know what a good approach is?
Thanks!
This is an old one now, but here is what i did for this:
All tasks that should appear on a live wall extend Activity (this was already the case)
Created a new Notification object, the Notification had a link to the underlying Activity and a link to a user (who was being notified).
Created a pre-persist hook for Activity that created a Notification object for the Activity being persisted - it did this for every user that was interested (all users following the user that was persisting the Activity)
For the moment, Notifications are persisted/retrieved to the DB - possibly not scalable to very high volumes, but the approach I think supports moving to a Queue based system (such as LinkedIn's Kafka queue library which is designed exactly for this purpose). As it is per-user, it also provides the option to have a read/unread notification flag for significant notifications.