I have a list view in android where i have to check every time do display the List item or not
to reduce the requests what i did is saved the id in a single row like
1,2,10,
everything was working fine to search i just had to use
String[] favs = fav.split(",");
for (int index = 0; index <(favs.length); index++) {
if(favs[index]==""){}else {
wishlist.add(Integer.parseInt(favs[index].trim()));
}
if(clicklist.contains((int)temp.getId())) //like this
and to remove from db like, this
temp2.replaceAll(""+m1.getId()+",", "") // and save in the db
now issue is i have two more data field associated with id like
10|data1|data2,100|apple|dog,150|data12|data24
Question 1 is this data model ok for small db
Question 2 how to perform search and delete in new data set?
please help!
Using a db is a proper choice here, i suggest you to take a look to the recently released Room, an Android component made by Google developers to support data persistence more easily.
You should of course know the basis of sql language.
In your case you should annotate your data class with #Entity annotation:
#Entity
public class DataModel {
#PrimaryKey
private int uid;
#ColumnInfo(name = "animal")
private String animal;
#ColumnInfo(name = "fruit")
private String fruit;
// Getters and setters are ignored for brevity,
// but they're required for Room to work.
}
And then, to answer your question about CRUD operations, define a Dao:
#Dao
public interface UserDao {
#Query("SELECT * FROM DataModel")
List<DataModel> getAll();
#Insert
void insertAll(DataModel... dataModels);
#Delete
void delete(DataModel dataModel);
}
Related
I am building a mood tracker android application using Room database with Java language.
I am planning to use android built-in emojis for the user to input their desired emoji, but I am not sure how to store it in the Room db and then retrieve the data to display in another fragment?
Will really appreciate if someone could provide some guidance on this or attach relevant tutorial video links about it because I am still new to mobile app development
As far as Room is concerned you only need to store some means of knowing what the emoji is, perhaps the Unicode for the emoji.
e.g. grinning face is 0x1F600, perhaps a descriptive. You can then set a TextView, as an example, incorporating the emoji.
Perhaps you could have a table just containing the emoji's and then store a reference (have a relationship) to this table.
A very simple working Room example follows.
The result will be a list of emoji's displayed in a ListView.
This example has a table that stores the emoji codes along with a description of the emoji . The table has been named emoji and the Entity class is EmojiTable as per :-
#Entity(tableName = "emoji")
class EmojiTable {
#PrimaryKey(autoGenerate = false)
#ColumnInfo(name = "_id")
Long id;
#ColumnInfo(name = "emoji_code", index = true)
String emoji_code;
#ColumnInfo(name = "emojidesc")
String emoji_desc;
// Default constructor
EmojiTable(){}
// Alternative Constructor
#Ignore
EmojiTable(String emoji_code,String emoji_desc) {
this.emoji_code = emoji_code;
this.emoji_desc = emoji_desc;
}
// Override default toString method to return the emoji followed by it's decsription
#Ignore
public String toString() {
return new String(Character.toChars(Integer.decode(emoji_code))) + " " + emoji_desc;
}
}
3 columns
the _id column for a unique identifier
the emoji_code column for the hex code of the emoji
the emoji_desc column for a description of the emoji
Note the toString method has been overidden to return a string containing the emoji followed by it's description. This is used to set the TextView in the ListView.
otherwise the default toString method is used which displays the object.
To accompany the emoji table the DAO AllDao for the database actions :-
#Dao
interface AllDao {
// Insertion of a row
#Insert(entity = EmojiTable.class, onConflict = OnConflictStrategy.IGNORE)
long insertEmoji(EmojiTable e);
//Deletion of ALL rows
#Query("DELETE FROM emoji")
int deleteAll();
// Get ALL rows
#Query("SELECT * FROM emoji")
List<EmojiTable> getAllEmojis();
// Get a row by the id passed to the method
#Query("SELECT * FROM emoji WHERE emoji._id = :id")
EmojiTable getEmojiById(Long id);
// Get the number of rows (used to detect changes)
#Query("SELECT count(*) FROM emoji")
Long getRowsInEmojiTable();
}
The #Database abstract class MyDatabase
#Database(entities = {EmojiTable.class}, version = 1)
abstract class MyDatabase extends RoomDatabase {
abstract AllDao getAllDao();
}
A class, namely EmojiList that defines emoji's/ master list of emoji's.
using this changes (if the number of emoji's changes) allows the emoji's stored in the database to be changed (should a new version of the App be deployed).
.
class EmojiList {
public static final EmojiTable[] EMOJIS = {
new EmojiTable("0x1F600","Grinning Face"),
new EmojiTable("0x1F602","Unknown"),
new EmojiTable("0x1F911","Money-Mouth Face")
};
}
3 emoji's defined
The Layout that includes a ListView for display of the List of Emoji's :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
/>
<ListView
android:id="#+id/emojilist"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/design_default_color_secondary"/>
</LinearLayout>
Nothing special here other than a background colour to see where the list is.
Finally putting it all together the Activity MainActivity
public class MainActivity extends AppCompatActivity {
MyDatabase db;
AllDao dao;
List<EmojiTable> emojiList_list;
ListView emojiList_listview;
ArrayAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Instantiate the MyDatabase object with a built Room Database
db = Room.databaseBuilder(this,MyDatabase.class,"mydb")
.allowMainThreadQueries()
.build();
// Instantiate the dao interface
dao = db.getAllDao();
// Check to see if the emoji's stored equals the master list
// If not rebuild the emjoi table
if (dao.getRowsInEmojiTable() != EmojiList.EMOJIS.length) {
dao.deleteAll(); // Delete all existing rows
for(EmojiTable e: EmojiList.EMOJIS) {
dao.insertEmoji(e);
}
}
// Very simple list of all emojis
emojiList_list = dao.getAllEmojis(); //
emojiList_listview = this.findViewById(R.id.emojilist);
adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1,emojiList_list);
emojiList_listview.setAdapter(adapter);
}
}
Result
When run the App looks like :-
The database (via Database Inspector) :-
I am searching everywhere but not found the exact way to use Inner Join on Realm DB in Android, check my code
public class UserName extends RealmObject {
private int UserID;
private String UserName;
// Getter Setters
}
public class UserDepartment extends RealmObject {
private int UserID;
private String UserDepartment;
// Getter Setters
}
In SQLite by using following query we easily get data
Select n.UserName, d.UserDepartment
FROM Name n INNER JOIN Department d
ON n.UserID=d.UserID
ORDER BY d.UserDepartment
But how to do same thing on Realm DB to get result...
Thanks in Advance!!
As you may know Realm is a non-relational database and concepts like join belongs for relational database. but if you need to have both UserName and UserDepartment in a single model class there are lots of implementations. but due to my experiences and according to realm constraints in using objects on different threads and updating objects snapshot with realm file, I suggest you to create a new entity, just like this:
class User extends RealmObject{
private int userId;
private UserName username;
private UserDepartment userDepartment;
}
whenever you insert a record into either UserName or UserDepartment you need to insert a record or update existing record in User.
Im building an app following architecture guidelines.Implemented room db caching + network.Need to get latest page number from separate entity.
My model:
#Entity(tableName = "top_rated_movie_page")
public class Top_Rated_Movies_Page {
#PrimaryKey(autoGenerate = true)
private int db_id;
private Integer page;
private Integer total_results;
private Integer total_pages;
#Ignore
private List<Result> results;
...
Result class contains data which i display in my paged list which observes changes from db.
Using PagedList.BoundaryCallback i need to fetch new data from network and insert it into db.
But i need to get page number somehow.
My dao:
#Insert
void insertAll(Top_Rated_Movies_Page page,List<Result> top_rated_results);
#Query("SELECT * FROM Result")
DataSource.Factory<Integer, Result> getAllResults();
#Query("SELECT * FROM top_rated_movie_page WHERE page= (SELECT MAX(page) FROM top_rated_movie_page)")
LiveData<Top_Rated_Movies_Page> getMoviePage();
I was thinking to observe Top_Rated_Movies_Page from db in my repository class with observeForever() to get that page number.
Is that the best way to approach this?
Since the only time you'll read the next page key or update the backing DB is through BoundaryCallback, you can just read / write your next page key directly.
So in your onItemAtEndLoad() implementation you want something like:
String nextMoviePage = db.runInTransaction(() -> {
movieDao.nextRemoteKey().key;
});
// Make sure not to run on main thread
MovieNetworkResponse response = networkApi.fetchNextMoviePage(remoteKey);
db.runInTransaction(() -> {
movieDao.clearAll(); // Remove previous key
movieDao.insertKey(RemoteKey(response.nextPageKey)); // Insert new key
movieDao.insertAll(response.movies); // Update DataSource + invalidate()
});
Your DAO:
#Insert
void insertAll(List<Result> top_rated_results);
#Query("SELECT * FROM Result")
DataSource.Factory<Integer, Result> getAllResults();
#Query("SELECT * FROM result_key LIMIT 1")
String nextRemoteKey();
#Insert
void insertKey(RemoteKey remoteKey);
And don't forget to clear out both the items and remoteKey whenever you expect to refresh the data!
In the case where you want to keep track of different keys for query, you can simply add that column to your RemoteKey entity.
FYI: Paging2 has been superseded by Paging3 (though just launched alpha01), here is the similar Paging3 sample which solves exactly your use-case: https://github.com/android/architecture-components-samples/blob/master/PagingWithNetworkSample/app/src/main/java/com/android/example/paging/pagingwithnetwork/reddit/repository/inDb/PageKeyedRemoteMediator.kt
I have to insert a value to table one in a hour for a specific id. I know it can be achieved by SQLite trigger but i read somewhere else that Room database currently doesn't support SQLite trigger function.
How to achieve above task? I have included my data model here.
#Entity(tableName = "device_table")
public class Device {
#PrimaryKey (autoGenerate = true)
private int id;
private String userId;
private long time;
public Device(String userId) {
this.userId = userId;
}
// and rest of the getter setter methods
}
I think you don't need SQLite trigger there (if update of your row doesn't depend on insert/delete another row|rows). You can divide your task to 2 subtasks:
How to create function, that updates row in Sqlite with some id.
How in Android invoke this function once in an hour.
For first subtask decision depends on how you want to update your data.
The simplest decision here - to use in your DAO interface method with #Insert annotation:
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertDevice(device: Device)
You should put "updated" instance of your data class Device to this method.
"OnConflictStrategy.REPLACE" means that if row with this "id" exists, then row will be overridden, else - it will be added.
For second subtask you can use one of the mechanisms - Handler, Executor, Timer, AlarmManager, WorkManager (last works even if your app is inactive). There are many answers/examples on using them here on SO.
Please bear with me, i'm new to architecture components and android in general.
My question is similar to this question but unfortunately the accepted answer doesn't seem to work.
I have an example one to many relation like in this answer. My example database has two tables USERS and PETS as shown in the following images:
Let's say I want to get a list of users containing a list of their pets grouped by user id only with pets younger than 5.
The result should look like this (pseudo code):
{uId: 2, [Pet3, Pet4]; uId: 4, [Pet6, Pet7];}
Another requirement is that the Dao needs to return the list as a LiveData object because I'm using MVVM architecture and want it to be Lifecycle aware and observable.
With these requirements, the UserDao would look like this:
#Dao
interface UserDao {
#Insert
void insert(User user);
#Transaction
#Query("SELECT USERS.uId, PETS.pId , PETS.userId, PETS.age " +
"FROM USERS INNER JOIN PETS ON PETS.userId = USERS.uId " +
"WHERE PETS.age < 5 " +
"GROUP BY USERS.uId")
LiveData<List<UserWithPets>> getUserPets();
}
User Entity:
#Entity
public class User {
#PrimaryKey
public int id; // User id
}
Pet Entity:
#Entity
public class Pet {
#PrimaryKey
public int id; // Pet id
public int userId; // User id
public int age;
}
The problem is now: how should i design the UserWithPets that room understands it and maps the cursor the way i want?
Here is what i tried so far:
Approach 1:
The most convenient way in my opinion would be using a Relation, like in the POJO below.
UserWithPets POJO:
public class UserWithPets {
#Embedded
public User user;
#Relation(parentColumn = "id", entityColumn = "userId", entity = Pet.class)
public List<Pet> pets;
}
Unfortunately, the functionality to assign a condition to a relation is not yet implemented by google. So we always get a full list of pets for every user that owns a pet younger than 5. Hopefully this will be possible soon, since the feature request is already assigned here and here.
Statement from google from this feature request: "we are planning to implement some query rewriting logic to fix these, not for 2.1 but hopefully in 2.2 where we'll focus more on relations."
Approach 2:
Another option would be Embedding both, User and Pet like:
public class UserWithPets {
#Embedded
public User user;
#Embedded
public Pet pet;
}
This doesn't work either, because now we only get 1 pet per user.
Approach 3:
this answer suggests to just create a merged class that extends from user like:
public class UserWithPets extends User {
#Embedded(prefix = "PETS_")
List<Pet> pets = new ArrayList<>();
}
I tried in many ways, with contructor and without, but i can't get it to work. it always gives errors like "Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type). - java.util.List"
or
The query returns some columns ... which are not used by UserWithPets. So any advice is welcome here.
Approach 4:
Just make two queries and stitch the results together. How would i do that using LiveData? Where should the joining operation be done? I can't do it in the Activity, that's not the point of an MVVM pattern. And not in the repository or viewmodel, since LiveData is immutable. Or is there another way?
What would be a working solution to get a result with the above requirements?