I am working on an app that fetch the data from Blogger using Google Blogger API. but the problem is every time user open the app it will fetch the data and show it. I want that the data must be stored on the first time the app is opened and have a option of refresh button, when clicked on that button it will refresh the data and again save it offline.
Here is the code for my getData method in main activity:
private void getData(){
Call<PostList> postList = BloggerAPI.getService().getPostList();
postList.enqueue(new Callback<PostList>() {
#Override
public void onResponse(Call<PostList> call, Response<PostList> response) {
PostList list = response.body();
recyclerView.setAdapter(new PostAdapter(MainActivity.this, list.getItems()));
Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<PostList> call, Throwable t) {
Toast.makeText(MainActivity.this, "Failure", Toast.LENGTH_SHORT).show();
}
});
}
PS: I want to create a tutorial type app with this. Is it a good approach for creating tutorial apps. I find everywhere but did not find the exact solution, So thought to create it by blogger.
You can save data locally in SQLite and use a DAO to make things easier, or investigate SqlDelight and SqlBrite if you want some Rx solutions. There are also storage solutions like Couchbase which are nosql. Finally, you could store the data in shared preferences or even use the file system directly, although I wouldn't advocate for either of those in this case
Related
I'm creating an app on Android Studio with Java and Firestore that lets users make publications and show them on a Fragment with a RecyclerView. The users create a profile (name, avatar) that gets saved in a document named after the user UID inside a collection named "Users". The publications are saved into another collection named "Posts" (title, content, picture, avatar, name).
I wrote two queries, one to get the title and content from the posts from the "Posts" collection, as well as the UID, to then do the other query that gets the name and picture from the poster and then all of those fields go inside a "Post" object and sent to the ArrayList that fills the RecyclerView.
Problem: The posts load perfectly on the RecyclerView but the user picture (the one I'm getting from a different collection) is giving me lots of problems. Sometimes it loads, sometimes it doesn't, and sometimes it loads only for the first post or even the first three posts. I don't understand what could be wrong. I'm posting the code:
private void loadPosts() {
Query postQuery = collectionReferencePosts.orderBy("timestamp", Query.Direction.DESCENDING);
postQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
for (QueryDocumentSnapshot document : task.getResult()) {
Post post = new Post();
post.setTitle(document.getString("title"));
post.setContent(document.getString("content"));
post.setImage(document.getString("image"));
String posterUid = document.getString("useruid");
DocumentReference docRef = collectionReferenceUsers.document(posterUid);
docRef.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
post.setName(documentSnapshot.getString("name").toString());
post.setAvatar(documentSnapshot.getString("image").toString());
}
});
postList.add(post);
postAdapter.notifyDataSetChanged();
}
}
});
}
If you want to display post details, along with user details at the same time, then you have to notify the adapter about the changes when the second request for getting the name and the image is complete. So you have to move the following two lines of code:
postList.add(post);
postAdapter.notifyDataSetChanged();
Right after:
post.setAvatar(documentSnapshot.getString("image").toString());
Besides that, there is another option that you should consider using, which is called denomalization. This means that you can add the name and the image of the user inside the post document. In this way, there is no need to perform the second query, since all the data already exists inside the post document. If you're new to NoSQL databases, this might sound some kind of weird, but I assure you it's quite common practice.
Please also note, that neither solution is better than the other. According to the number of changes that can occur in your app, regarding the update of name and user image, you have to check which solution is better to be used inside your project.
You can also take a look at the following post to have a better understanding of the asynchronous nature of Firebase API:
How to return a DocumentSnapShot as a result of a method?
I have an application at the Google Play and there are already a few hundred of users.
Now, I'm working on an update that will allow users to share user-to-user content via Firebase Dynamic Links.
In order to do so, I created a subdomain and all the required things and I added this code:
FirebaseDynamicLinks.getInstance()
.getDynamicLink( getIntent() )
.addOnSuccessListener( this, pendingDynamicLinkData -> {
Uri deepLink = null;
if (pendingDynamicLinkData != null) {
deepLink = pendingDynamicLinkData.getLink();
String bookID = deepLink.getQueryParameter( "id" );
if (bookID != null) {
startBookDetailActivity( bookID );
}
}
} )
.addOnFailureListener( this, e -> {
}
);
However, the users who already have the app installed on their phone don't have this piece of code in their application which means that if they click on the dynamic link it won't do the job.
Is there any other way I can handle the dynamic link for the period until all users get the latest version?
Thank you
You could have the user copy and past the code into the app but ultimately, this also requires that the app is updated to do so.
Perhaps you could use a cloud function that would return the data in the browser rather than the app, you could do this with a button that appears after a second and manually invoke the call.
But it might just be easier to encourage users to update and implement a callback system using real-time or firestore as a user inbox system for this kind of edge case.
I want to make an Android chat application. So I want to know how to get data from Firebase Firestore automatically, when new document create? Actually I do not wanna use add snapshot listener because of its give real-time data changes of a single document but want to find out real time updated Firebase Firestore document. Please suggest me.
I don't know if you can do this without a snapshot listener.
Check this code, if it is what you want.
private void addRealtimeUpdate() {
DocumentReference contactListener=db.collection("PhoneBook").document("Contacts");
contactListener.addSnapshotListener(new EventListener < DocumentSnapshot > () {
#Override
public void onEvent(DocumentSnapshot documentSnapshot,
FirebaseFirestoreException e) {
if (e != null) {
Log.d("ERROR", e.getMessage());
return;
}
if (documentSnapshot != null && documentSnapshot.exists()) {
Toast.makeText(MainActivity.this, "Current data:" +
documentSnapshot.getData(), Toast.LENGTH_SHORT).show();
}
}
});
}
To solve this, I recommend you to use CollectionReference's get() method. This is the correspondent addListenerForSingleValueEvent() method from Firebase real-time database.
Executes the query and returns the results as a QuerySnapshot.
If you want to use Firebase-UI library, this is a recommended way in which you can retrieve data from a Cloud Firestore database and display it in a RecyclerView using FirestoreRecyclerAdapter.
I don't know if you can do it with firestore but with realtime database you can use the .on(). If the rest of your app is using firestore, each project can use both a cloud firestore and a realtime database. The docs are really simple.
I'm making an application with Firebase where a User has to sign in to use the application. The MainActivity will only launch after the User has signed in, using FirebaseAuth and FirebaseAuth.AuthStateListener.
So in the Main Activity, I have all the information about the current User.
My question is, when navigating to other activities, is it better to pass more extras via Intents about the User (or any object) to SecondActivity, or is it better to read from the Firebase database in the SecondActivity?
(Both works fine for my app, but I'm thinking about good programming style / structure and thinking about resources, speed and performance)
Also worth mentioning, I want to keep in mind that almost all of the activities' screens / UI will be updated by the information about the current object, so I want the app to be as fast and responsive as possible. For some of the code I have in my project now, I have to use Thread.sleep(x), to let the UI wait for the database to finish reading before updating the UI. This is what I'm currently using in my Google Maps Activity.
The PK of the User is the Gmail, used for signing in. Each User has several ArrayLists (that contains objects) that will grow larger when using the application, so eventually, a lot of information will be passed.
Take a look at the example code below, but don't bother too much with the details, it's just some code that I put in there now. The important thing is the general structure of how to retrieve and pass information in each activity:
MainActivity:
Intent i = new Intent(this, SecondActivity.class);
i.putExtra("email", thisUser.getEmail());
startActivity(i);
SecondActivity:
private FirebaseDatabase Db;
private DatabaseReference destinationRef, userRef;
private String email;
private User thisUser;
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.SecondActivity);
email = getIntent().getStringExtra("email");
Db = FirebaseDatabase.getInstance();
userRef = Db.getReference().child("Users");
destinationRef = Db.getReference().child("Destinations");
getInfoFromDb();
}
private void getInfoFromDb(){
userRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u;
for(DataSnapshot data : dataSnapshot.getChildren(){
u = data.getValue(User.class);
u.setUid(data.getKey());
if(email.equalsIgnoreCase(u.getEmail())){
thisUser = u;
/* Update something else, based on this info */
}
}
}
#Override
public void onCancelled(DataSnapshot dataSnapshot) { }
});
destinationRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Destination d;
for(DataSnapshot data : dataSnapshot.getChildren()){
d = data.getValue(Destination.class);
d.setUid(data.getKey());
if(thisUser.getCurrentTrip().getDestinationName().equalsIgnoreCase(d.getDestinationName())){
/*Something else, update UI or whatever */
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) { }
});
}
Here is another (shorter) example:
MainActivity:
Intent i = new Intent(this, SecondActivity.class);
i.putExtra("email", thisUser.getEmail());
i.putExtra("rank", thisUser.getRank());
i.putExtra("points", thisUser.getPoints());
i.putExtra("someArray", thisUser.getSomeArray());
i.putStringArrayListExtra("somethingElse", thisUser.getSomeStringArrayList());
// And let's say we put in a lot more information
startActivity(i);
SecondActivity
thisEmail = getIntent().getStringExtra("email");
thisRank = getIntent().getStringExtra("rank");
thisEmail = getIntent().getIntExtra("points");
thisSomeArray = getIntent().getStringArrayExtra("someArray");
thisArrayList = getIntent().getStringArrayListExtra("somethingElse");
Which approach is better?
1) The first code example, where I read from the database in the SecondActivity to get info.
2) Send the whole thisUser-object (which can grow quite big, and serialization has to be used) from MainActivity to SecondActivity.
3) Pass more (can maybe be a lot) information from MainActivity with the Intents, to the other Activites.
Again, I'm thinking about good programming structure, practice, style and am concerned about speed, responsiveness and resources.
Thanks!
I would retrieve the data from the database, since you said it can be more information. So, its better to just retrieve the data from the database in the SecondActivity.
If you pass the data using intent it means you are sharing it between activities and not storing it.
Also lets say you want to do a query that involves more than one node (maybe two nodes under root(like a join) or nested nodes), you will have to retrieve the data from the database to be able to do that
Think of testing.
In one case, you need your test framework to pass in all this extra data to test just the second method. Coupling has been increased. The method is less cohesive, since it can’t operate independently.
In the other case, the test framework doesn’t need to pass in the extra data, because the method retrieves the required information itself. Coupling is decreased. The method is more cohesive.
My $0.02
Your question is very specific to the application being developed.
Passing data through intent or persisting it in DB is very subjective to what kind of data it is and what would be the action plan when you lose that data due to some reason.
Pros & Cons : Passing data in intent
Having data passed around in intent is good for transient or deduced data as it’s computed for taking some actions and shouldn’t be persisted or retrieved every time the activity is loaded.
Code will be more complicated as compared to DB approach as every time you traverse from one activity to another you have to add code to pass the intent or check the data passed or add new data in current activity. If system crashes you loose all data and state.
Pros & Cons : DB approach
having data in DB provides you a way to resume the state when there is crash or will act as checkpoint for future. It also means you have to maintain tables and code to handle them but it would be clean as the interfaces will be clean and defined. On same note, there can be multiple calls to save and retrieve data.
You also need to consider whether data is sensitive or not.
In nutshell, it’s purely upon your application needs and you have to identify what data is required for computation and what needs to be persisted and accordingly used mixed approach to achieve better performance with reliability.
I've been looking into the Android SDK's example of the SearchableDictionary for a while now, but I'm still not sure if that is the right approach.
The problem is, that I want to fill my hint list (see picture below) with data, which I will receive via a HTTP/JSON query. So I'm not sure if using a ContentProvider as used in the above example is the right thing to do. Can I access the hint list of the SearchBox in some way more direct?
You can overload the onSearchRequested for the searchmanager and return a custom data set the the given query. make sure to use an asyncTask if you are connecting to the web for your data to avoid ANR's
#Override
public boolean onSearchRequested() {
Bundle appData = new Bundle();
appData.put...();
...
startSearch(null, false, appData);
return true;
}