Android ListView constantly reloading image elements imported from firebase - android

In an android app I have made, the home page shows a list a games in a listview, each row being custom made to include a textview and an imageview and some buttons. The imageview's src comes from downloading th image from my google cloud firebase, and the functionality of this works well, but when the listview is scrolled through there is an issue. The images seem to be unloaded when scrolled away from, which causes a bit of lag when they are reloaded once scrolled back to. I imagine this is built in to prevent a listview from loading many high resolution images and keeping them loaded, but for my list, keeping the images loaded won't be a problem. Is there a way I can turn this off and just keep the images loaded? Here is a video of the problem:
https://www.youtube.com/watch?v=FYYJWZcvBy4&feature=youtu.be
here is the code of the listview and getting the image from firebase:
public void showData(DataSnapshot dataSnapshot){
TextView toolbarTitle = findViewById(R.id.toolbarTitle);
toolbarTitle.setText("Popular Games");
ArrayList<GameInformation> PopularGames = new ArrayList<>();
Iterator<DataSnapshot> items = dataSnapshot.child("Games").getChildren().iterator();
PopularGames.clear();
while(items.hasNext()){
GameInformation game = new GameInformation();
DataSnapshot item = items.next();
game.setGameName(item.child("Name").getValue(String.class));
game.setActiveLobbies(Integer.parseInt(item.child("Live Lobbies").getValue().toString()));
game.setPicturePath(item.child("FilePathName").getValue().toString());
Iterator<DataSnapshot> itemsDeep1 = item.child("consoles").getChildren().iterator();
while(itemsDeep1.hasNext()){
DataSnapshot itemDeep = itemsDeep1.next();
game.setConsoles(itemDeep.getValue(String.class));
}
Iterator<DataSnapshot> itemsDeep2 = item.child("genres").getChildren().iterator();
while(itemsDeep2.hasNext()){
DataSnapshot itemDeep = itemsDeep2.next();
game.setGenres(itemDeep.getValue(String.class));
}
if (game.getActiveLobbies() == 1){
PopularGames.add(game);
}
}
Log.d(TAG, "Hello Here" + PopularGames.size());
ArrayAdapter adapter = new CustomListAdapter(this, PopularGames);
mListView.setAdapter(adapter);
}
getting the image:
storageRef.child("Games/"+singleGame.getPicturePath()+".jpg").getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Glide.with(getContext()).load(uri).into(gameImageID);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
// Handle any errors
}
});

The delay you're facing is because there are 2 operations (each one takes a few secs to complete) being performed when you get each image:
The image is read from Firebase Storage using getDownloadUrl()
The image is displayed with Glide
I recommend that when you store the images, save their Download URL to the database instead of saving their path. This way, you'd no longer need to call for getDownloadURL(). You'd simply load the image with a single operation:
Glide.with(getContext()).load(singleGame.getPicturePath()).into(gameImageID);
Not related to the question:
You can simplify your code by using a forEach loop (instead of while) in your Iterators:
PopularGames.clear();
for(DataSnapshot item : dataSnapshot.child("Games").getChildren()){
GameInformation game = new GameInformation();
game.setGameName(item.child("Name").getValue(String.class));
game.setActiveLobbies(Integer.parseInt(item.child("Live Lobbies").getValue().toString()));
game.setPicturePath(item.child("FilePathName").getValue().toString());
for(DataSnapshot itemDeep: item.child("consoles").getChildren()){
game.setConsoles(itemDeep.getValue(String.class));
}
for(DataSnapshot itemDeep: item.child("genres").getChildren()){
game.setGenres(itemDeep.getValue(String.class));
}
if (game.getActiveLobbies() == 1){
PopularGames.add(game);
}
}
Log.d(TAG, "Hello Here" + PopularGames.size());

Related

Image View Continues To Display On If Statement

Issue:
Im sure im missing something super easy, but I am not able to figure it out.
I have an if statement for a recycler view which basically says to pull in all data of the current user and put it in a recycler view.
What I want to happen:
If there is no data for the current user (so if the recycler view is empty), then display a particular image.
What's currently happening:
The image continues to display, even when the current user's data (recycler view) is displayed.
The image is displaying over the recycler view.
I need the image to be "GONE", if the recycler view is displayed with the current user data.
What I Believe The Issue Is:
I believe this is happening because the system is thinking that because there are other users that are not the current users that exist in the database, then display the image. However, im trying to figure out how to only display the image, if there is no data for the current user. Sorry if I didn't explain this correctly. Let me know if you have any questions. Thank you so much for the help!
Additional Notes
Let me know if you need to see the xml but I have already checked and the image is set to gone on the xml.
private void fetchInviteList() {
String currentUser;
currentUser = mAuth.getUid();
DatabaseReference notificationInviteRef = FirebaseDatabase.getInstance().getReference().child(Strings.InvitesReference);
notificationInviteRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot1) {
ArrayList<Model_Notifications_Invite> model_notifications_invites = new ArrayList<>();
for (DataSnapshot snapshot2:snapshot1.getChildren()) {
for (DataSnapshot snapshot3:snapshot2.getChildren()) {
String notificationPath = snapshot3.child("inviteeUserId").getValue(String.class);
if(notificationPath.equals(currentUser)){
Model_Notifications_Invite invites = snapshot3.getValue(Model_Notifications_Invite.class);
model_notifications_invites.add(invites);
} else if (!notificationPath.equals(currentUser)){
happyImage.setVisibility(View.VISIBLE);
}
}
}
myNotificationsAdapter.updateNotificationsList(model_notifications_invites);
}
#Override
public void onCancelled(DatabaseError databaseError) {
//throw databaseError.toException();
}
});
}
JSON
The first node is like the group id.
The child directly underneath that, is the current user id.
There is another child with the same user id thats called - "inviteeUserId."
"Invites": {
"-NAHHVbARBzsi0mCk4j9": {
"DrpEs5nJH4RVVdOXlgVB1EJQQDz1": {
"inviteDate": "August 25",
"inviteTime": "02:39:33 PM",
"inviteeUserId": "DrpEs5nJH4RVVdOXlgVB1EJQQDz1",
"inviterUserId": "iJ8ZuvIPtEd4pdKiychcnskgyHU2",
"bookId": "-NAHHVbARBzsi0mCk4j9"
},
"oWaE8TWfyAalpWyD9oUdV80ocsw2": {
"inviteDate": "August 25",
"inviteTime": "04:08:28 PM",
"inviteeUserId": "oWaE8TWfyAalpWyD9oUdV80ocsw2",
"inviterUserId": "iJ8ZuvIPtEd4pdKiychcnskgyHU2",
"bookId": "-NAHHVbARBzsi0mCk4j9"
}
}

Is there a better way to load a picture in android studio?

I am making an app using Java in android studio, and in it I want users to have the option to set a custom profile picture. I'm using firebase storage to store the images for the PFPs, and taking them from there every time I load it, but it always takes around half a second or so to load the profile picture: gif of the problem
Here's my code for loading the pfp in the homepage (I am using de.hdodenhof.circleimageview.CircleImageView to make the ImageView circular):
public class HomePage extends AppCompatActivity {
de.hdodenhof.circleimageview.CircleImageView pfpImage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_page);
pfpImage = findViewById(R.id.pfpImg);
Intent intent = getIntent();
if (intent != null && intent.hasExtra("UserEmail")) {
String userEmail = intent.getExtras().getString("UserEmail");
StorageReference userPfp = DBRef.refStorage.child("ProfileImages/Users/" + userEmail.replace(".",",")); //DBRef is a class I created to reference all Firebase related objects.
userPfp.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Picasso.with(HomePage.this).load(uri).into(pfpImage); // I am using com.squareup.picasso:picasso:2.5.2 to load the image from the Uri.
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(HomePage.this, "Profile Picture Loading Failed", Toast.LENGTH_SHORT).show();
}
});
}
else
pfpImage.setImageResource(R.drawable.doggo);
}
}
Is there some better way to load/store the pictures so they appear when the page loads?
EDIT: I managed to negate this by not loading from Firebase every time the activity is opened, but only the first time and saving it, using an idea from this post
There is other library named glide that can load picture faster when the page loads.
Here is the link for the reference.
https://guides.codepath.com/android/Displaying-Images-with-the-Glide-Library

How To Populate A Gridview With Images Retreieved From Firebase Storage

I have reviewed other similar posts before posting this, mine is different
I am current retrieving a list of download urls from my Firestore data base, then trying to download those images from my firebase storage to display them in a gridview.
This is my code so far:
final Query chatRoomMsgs = db.collection("chatrooms").document(chatRoomID).collection("Messages").whereEqualTo("sentby", firebaseAuth.getUid());
chatRoomMsgs.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
ArrayList<String> sentPicsURLS = new ArrayList<String>();
for(QueryDocumentSnapshot documentSnapshot: queryDocumentSnapshots){
for(int i = 0; i < queryDocumentSnapshots.size(); i++) {
sentPicsURLS.add(documentSnapshot.get("image").toString());
if(i == (queryDocumentSnapshots.size()-1)){
//now download the images and place them into the proper view
for(int z = 0; z < sentPicsURLS.size(); z++){
}
}
}
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
This is where the images should be pulled and pushed into a gridview:
for(int z = 0; z < sentPicsURLS.size(); z++){
//right here
}
But I am having trouble creating an adapter that can handle this. I have a valid gridview in the activity and I have a layout file that contains an imageview with a ID.
final ArrayAdapter arrayAdapter = new ArrayAdapter(Chatroom.this, R.layout.chatroom_sent_images,R.id.sent_iv);
sentPics.setAdapter(arrayAdapter);
sentPics.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//empty for now
}
});
The part I am missing (seems to be) where I actually loop through sentPicsURLS and then add them to the adapter... maybe with something like arrayAdapter.addAll(sentPicsURLS); inside the //right here for loop?
Right now the gridview is showing empty without even the default image view included in R.layout.chatroom_sent_images. I feel like I am so close, what am I missing? Thanks!
Edit
Here is my chatroom database structure, every chatroom and chatroom message is structured the same way.
As I see in your screenshot, your document hols only a single image. So to solve this, there is no need for an extra inner for-loop. To create a list of those images, please use the following lines of code:
Query chatRoomMsgs = db.collection("chatrooms").document(chatRoomID)
.collection("Messages").whereEqualTo("sentby", firebaseAuth.getUid());
chatRoomMsgs.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
ArrayList<String> sentPicsURLS = new ArrayList<>();
for (QueryDocumentSnapshot document : task.getResult()) {
sentPicsURLS.add(document.getString("image"));
}
//Do what you need to do with your list
Log.d(TAG, "List size: " + sentPicsURLS.size());
}
}
});
Be also aware that Firebase APIs are asynchronous and you can use that list only inside the callback. Now, the result in your logcat will be size of your list.

firebase database download huge usage

I've a realtime database of only 200 B and my app has approx. 500 active users.
In the app I query the database to add data to some arraylist:
public class FirebaseApplication extends Application {
...
#Override
public void onCreate() {
super.onCreate();
...
//reference to the root of the cloud database
mDatabase = FirebaseDatabase.getInstance().getReference();
mNamesPoloSubRoot = mDatabase.child("PoloniexNames");
//listen for change in the cloud. If there is some additional item,
//add it to the list populated from hard coded items.
mNamesPoloSubRoot.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
GenericTypeIndicator<List<String>> gt = new GenericTypeIndicator<List<String>>() {};
List names = snapshot.getValue(gt);
if( names == null ) {
//Log.v(LOG_TAG_FIREBASE,"No extra coins");
}
else {
// Log.v(LOG_TAG_FIREBASE,"extra coins!" );
additionalNamesPolo = new ArrayList<String>(names);
//attach the new coins at the bottom of the hard coded list
NamesPoloniexA.addAll(additionalNamesPolo);
}
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.e(LOG_TAG_FIREBASE, "Failed to read value.", error.toException());
}
});
...
}
}
I've 9 of such listeners. The data consumptions is approx. 100 MB every day!
At this rate I will soon hit the 10GB/month limit. If I'm correct this data should be loaded every time a user open the app and every time I change remotely the data from server (this happens very rarely, like 2 times in a month). If opening the app loads, let's say, 1 KB, then this means that app should have been opened more than 100.000 times a day, and this it's not true by at least an order of magnitude.
My database is something like:
{
"PoloniexAbbreviations" : [ "LGD", "PTOY", "PTOY" ],
"PoloniexCurrencyPairs" : [ "ETH_LGD", "BTC_PTOY", "ETH_PTOY" ],
"PoloniexNames" : [ "Legends", "Patientory", "Patientory" ]
}
Notice that many of the children called by the app are very often null (since there are no data to add remotely to the app), so the entire database can even be empty, but some data seems to be downloaded anyway (the size of the database, even if null, is not zero).
What I'm doing wrong? Or it's an issue of Firebase?

Access cached images (Picasso)

I'm having a loading screen where I fetch data belonging to the logged in user. Among this data is their profile images (three of them).
What I want to do is to cache the images when I download them with their URL in Loading screen. Then in the next activity I want to access the cached images to display them in that activity. So basically load all images in one activity to be used in another one. This way (I figured) I won't have to make a http request everytime user enters the activity where their profile image is shown. Which gives a better user experience.
So it's the matter of getting the images from cache to screen that I can't work out, cause I think I've loaded them into cache correctly, seen below.
Here's my current method in Loading Activity:
Backendless.Data.of(UserFileMapping.class).find(new AsyncCallback<BackendlessCollection<UserFileMapping>>() {
#Override
public void handleResponse(BackendlessCollection<UserFileMapping> response) {
Iterator<UserFileMapping> iterator = response.getCurrentPage().iterator();
while(iterator.hasNext()){
UserFileMapping fileMapping = iterator.next();
String profile1 = fileMapping.profile_url;
String profile2 = fileMapping.profile_url_2;
String profile3 = fileMapping.profile_url_3;
Picasso.with(getApplicationContext())
.load(profile1)
.fetch(new Callback() {
#Override
public void onSuccess() {
continue_button.setVisibility(View.VISIBLE);
loading_text.setText("Done!");
}
#Override
public void onError() {
//Make toast
}
});
}
}
#Override
public void handleFault(BackendlessFault fault) {
System.out.println("FAULT:" + fault.getCode());
}
});
It's the issue with downloading all three images at once as well, but that isn't as important as the caching question. If you have a good idea on this in addition to the cache issue I would gladly like to hear it too.

Categories

Resources