My recyclerview gets data from json api and populate list of articles. I have now implemented a commenting system with the help of firebase realtime database. I want to show number of comments below each article image in recyclerview. I tried several methods to implement that but all of them are not very effective.
At first I implemented database query based on article unique id for each view but since recyclerview has over 100 articles so it was making over 100 instance calls to database and was causing huge bandwidth problem.
Then I made one query to get all comments count from database and saved them locally in SQLite database and inside recyclerview i query SQLite databse to get comments counts but inserting 100 rows with article id and comments count in SQLite is slow.
What do you guys recommend best method for such task where I will spend least amount of bandwidth and get comment counts also?
My db structure is like this.
get comments method
public void getComments() {
keyrf = FirebaseDatabase.getInstance().getReference().child("Keys");
keyrf.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
HashMap map = new HashMap();
for( DataSnapshot child : dataSnapshot.getChildren() ) {
String childKey = child.getKey();
String c = child.child("c").getValue().toString();
map.put(childKey, c);
addComments(MainActivity.this, childKey, c);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
insert comments method
public static void addComments(Context context, String childKey, String c) {
try {
SQLiteDatabase myDB = context.openOrCreateDatabase("MyDb", Context.MODE_PRIVATE, null);
myDB.execSQL("CREATE TABLE IF NOT EXISTS comments (articleId INTEGER not null unique, comment INTEGER not null)");
String sql = "REPLACE INTO comments (articleId, comment) VALUES (?, ?)";
SQLiteStatement statement = myDB.compileStatement(sql);
statement.bindString(1, childKey);
statement.bindString(2, c);
statement.execute();
} catch (Exception e) {
}
}
What do you guys recommend best method for such task where I will spend least amount of bandwidth and get comment counts also?
The workaround here is to keep a count property somewhere in the database and update that whenever you add/delete child nodes.
So you can consider using a new section that might look similar to this:
Fireabase-root
|
--- numberOfComments
|
--- commentId: 12
|
--- commentId: 10
|
--- commentId: 20
So everytime you add or delete a post, increase / decrease that count by one. And because the number of comments might be updated in an multi user environment, I recommend you to use FirebaseTransactions as explained my answer from this post.
Related
I've integrated Realm android to my project.
I want to keep my table restriction to store max 100 records. If any new records come then check for if its limit increases to 100 then It should delete those records (101..N). The table should contain the last 100 records only.
Any help will be appreciable.
Thanks in advance!
There is no automatic way of doing this. But if you add a timestamp in your model class (say, created), you could add a listener and delete the old object. Something like:
realmListener = new RealmChangeListener() {
#Override
public void onChange(Realm realm) {
RealmResults<YourClass> objs;
int nObjsToDelete;
objs = realm.where(YourClass.class).sort(created).findAll();
nObjsToDelete = objs.size()-100;
objs.limit(nObjectToDelete).findAll().deleteAllFromRealm();
}
};
realm.addChangeListener(realmListener);
I have recently started switching my app from Parse to Firebase. Everything is going great so far, but I have not been able to find a Firebase equivalent method to Parse's whereContainedIn(String key, Collection values).
This was a very useful method that allowed me to pass in an array of ids and it would return all of the rows that matched that id. So far with Firebase, I have it returning all all of the rows in the database then looping through them to see if that row's id is contained in my array of ids. The other way is to query for each id individually, which doesn't work well with Firebase's asynchronous behavior. This is what I am doing now for the first approach:
List<String> userIds = new ArrayList<>();
userIds.add("2");
userIds.add("32");
userIds.add("12545");
userIds.add("187");
DatabaseReference firebaseRef = FirebaseDatabase.getInstance().getReference();
Query queryRef = firebaseRef.child("videos");
queryRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Video> usersVideos = new ArrayList<Video>();
for (DataSnapshot videoSnapshot : dataSnapshot.getChildren()) {
Video video = videoSnapshot.getValue(Video.class);
if (userIds.contains(video.userId)) {
usersVideos.add(video);
}
}
// usersVideos is now populated with the videos for the users
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d(TAG, "CANCELLED");
}
});
Neither of these methods seem reasonable since my table will contain hundreds of thousands of records.
Any help would be greatly appreciated!
Make another reference that can be looked up by userId and have it return all videoIds that this user has. From there you can query the videos. That means each time you save you will need to save in two spots. Sort of a pain, but it is what Firebase recommends.
So your reference will look more like:
videos -
| - <videoId> -
| - <video stuffs>
| - userId
videosByUser -
| - <userId> -
| 0 - <videoIdA>
| 1 - <videoIdB>
| - <userId2> -
| 0 - <videoIdA>
can't you just perhaps do a for loop over your ids and inside the for loop write a valueventlistener that will be called for each iterated item`?
Does anyone know if it is possible to programmatically clear all of the data in a Backendless table at once? I found this article that shows how to remove individual objects one at a time but nothing on clearing the whole table at once: https://backendless.com/documentation/data/android/data_deleting_data_objects.htm
I figured out a way to do it but I don't know how efficient it is. Basically, I have a Class called LocalPhoneNum, which make up the objects that will be saved in my app table. The class contains a userID, name and phone num. I query the table to find a user with a specific email (right now there's just one user), then use the foundContacts variable in a loop to delete each object one by one.
String whereClause = "userEmailID = mark";
BackendlessDataQuery dataQuery = new BackendlessDataQuery();
dataQuery.setWhereClause( whereClause );
Backendless.Persistence.of(LocalPhoneNum.class).find(dataQuery, new AsyncCallback<BackendlessCollection<LocalPhoneNum>>(){
#Override
public void handleResponse( BackendlessCollection<LocalPhoneNum> foundContacts )
{
for (LocalPhoneNum temp : foundContacts.getData()){
Backendless.Persistence.of( LocalPhoneNum.class ).remove( temp, new AsyncCallback<Long>()
{
public void handleResponse( Long response )
{
Toast.makeText(getActivity(), "DELETED", Toast.LENGTH_LONG).show();
}
public void handleFault( BackendlessFault fault )
{
Toast.makeText(getActivity(), "NOT DELETED "+fault, Toast.LENGTH_LONG).show();
}
} );
}
Please let me know if there is a better solution or if this one is fine. Thank you!
Use the "bulk delete" operation with the 'where' query like "objectId is not null":
https://backendless.com/documentation/data/rest/data_deleting_data_objects.htm
This is my first Application with database, I hope that someone can help me to understand this problem. I have this insert method:
public long insertData(String name, int password){
....
contentValues.put(KEY_NAME, name);
contentValues.put(KEY_PASSWORD, password);
return db.insert(DBHelper.TABle_NAME, null, contentValues);
}
I can insert few data with this method, but what about if I have thousands of rows? how can I insert all these data into database? where can I write all these data, in extra class or what?
As others have said, you'll need to do some sort of iteration.
Efficiency can be gained by performing a bulk transaction. Here's an example:
public int bulkInsert(#NonNull ContentValues[] values) {
int insertCount = 0;
SQLiteDatabase db = mSqlHelper.getWritableDatabase();
try {
db.beginTransaction();
for (ContentValues value : values) {
if (db.insertOrThrow(tableName, null, value) == -1) {
throw new Exception("Unknown error while inserting entry in database.");
}
insertCount++;
}
db.setTransactionSuccessful();
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred while bulk-inserting database entries.\n" + e.getMessage(), e);
} finally {
db.endTransaction();
}
return insertCount;
}
There is no 'bulk load' facility that I'm aware of.
You'd just have to spin through the list, and insert the items.
You might want to think about why you're potentially trying to insert thousands of items into a database on a hardware-limited device like a phone or a tablet.
Might it be better to put the data on a server, and create an API that you can use to load data (for display) by pages?
you can do it the same way, that you do with few data, you only need to catch the thousands rows to insert into your database using your method, you can use asyntask, or a service to do that
You can use the same method to insert any amount of records, whether it's 1 or 1,000. Use a loop to call your insert method and add your records to your database. Consider putting your database executions in an AsyncTask to prevent your UI thread from hanging.
Your data can come from anywhere, as long as it's formatted to fit your function parameters String, int
I am new to android and maybe its a silly question but i am not getting it. See i am designing a game in which we give scores to some persons. So i want to store the names of the persons in a database while installation and then their scores set to 0 initially which will be updated according to what the users select. Here i am not able to figure out that how should i enter the data as it will be around 100 names and their scores. Using INSERT INTO() statement will make it like 100 statements. So is there any short method like can we do it through strings or something. Just guessing though. Any help would be appreciated.
You don't hard-code names or scores into your SQL statements. Instead, you use parameters.
var command = new SQLiteCommand()
command.CommandText = "INSERT INTO Scores (name, score) VALUES(#name, #score)";
command.CommandType = CommandType.Text;
foreach (var item in data)
{
command.Parameters.Add(new SQLiteParameter("#name", item.Name));
command.Parameters.Add(new SQLiteParameter("#score", item.Score));
command.ExecuteNonQuery();
}
and then just loop through all of the names and scores.
I recommend you using a transaction.
You can archive this stating you want to use a transaction with beginTransaction(), do all the inserts on makeAllInserts() with a loop and if everything works then call setTransactionSuccessful() to do it in a batch operation. If something goes wrong, on the finally section you will call endTransaction() without setting the success, this will execute a rollback.
db.beginTransaction();
try {
makeAllInserts();
db.setTransactionSuccessful();
}catch {
//Error in between database transaction
}finally {
db.endTransaction();
}
For the makeAllInserts function, something like this could work out:
public void makeAllInserts() {
for(int i = 0; i < myData.size(); i++) {
myDataBase = openDatabase();
ContentValues values = new ContentValues();
values.put("name", myData.get(i).getName());
values.put("score", myData.get(i).getScore());
myDataBase.insert("MYTABLE", nullColumnHack, values);
}
}
If you also want to know about the nullColumnHack here you have a good link -> https://stackoverflow.com/a/2663620/709671
Hope it helps.