问题
In my app I am using Realm DB to store all the data in local database. I have some initial mock data which I want to show at the starting of the app. Previously I implemented begintransaction method. But after reading the documentation I have implented execute tranasction method. Beacuse this method is updating my new data easily. Now the problem is, whenever I click the option to show the recyclerview, the data is looping each time. for example I have 3 data. If I go back to previous page and again go to this recyclerview page, it becomes double, next time it becomes tripple and so on. I want to show only the updated data into the view. Like if I add 4th data iwant to show this to recyclerview. How can I stop looping on each run in my app.
Here is my code
Person Page
public class InitialData implements Realm.Transaction {
@Override
public void execute(Realm realm) {
List<PersoneModel> person = new ArrayList<>();
PersonModel model = new PersonModel();
model.setId(1 + System.currentTimeMillis());
model.setName("Name1");
model.setCompany("Comapny1");
model.setTitle("Title1");
person.add(model);
model = new PersonModel();
model.setId(2 + System.currentTimeMillis());
model.setName("Name2");
model.setCompany("Company2");
model.setTitle("Title2");
person.add(model);
model = new PersonModel();
model.setId(2 + System.currentTimeMillis());
model.setName("Name2");
model.setCompany("Company2");
model.setTitle("Title2");
person.add(model);
model = new PersonModel();
model.setId(3 + System.currentTimeMillis());
model.setName("Name3");
model.setCompany("Comapny3");
model.setTitle("Title3");
person.add(model);
for (PersonModel realmModel : colleague) {
realm.insertOrUpdate(realmModel);
}
}
@Override
public boolean equals(Object obj) {
return obj != null && obj instanceof InitialData;
}
@Override
public int hashCode() {
return InitialData.class.hashCode();
}
}
News Page Initial Data
public class InitialDataNews implements Realm.Transaction {
@Override
public void execute(Realm realm) {
List<NewsModel> newsItem = new ArrayList<>();
NewsModel model = new NewsModel();
model.setId(1+System.currentTimeMillis());
model.setImage(R.drawable.image1);
model.setTitle("title1");
model.setDate("12.07.2017");
model.setDetail("deascription");
newsItem.add(model);
model = new NewsModel();
model.setId(3+System.currentTimeMillis());
model.setImage(R.drawable.image3);
model.setTitle("title2");
model.setDate("05.05.2017");
model.setDetail("description");
newsItem.add(model);
model = new NewsModel();
model.setId(4+System.currentTimeMillis());
model.setImage(R.drawable.image4);
model.setTitle("title3");
model.setDate("13.04.2017");
model.setDetail("description3");
newsItem.add(model);
.....
for (NewsModel realmModel : newsItem) {
realm.insertOrUpdate(realmModel);
}
}
@Override
public boolean equals(Object obj) {
return obj != null && obj instanceof InitialData;
}
@Override
public int hashCode() {
return InitialData.class.hashCode();
}
}
Base Application
@Override
public void onCreate() {
super.onCreate();
// The Realm file will be located in Context.getFilesDir() with name "default.realm"
//Here we setup the realm configuration.
//Setting a default configuration in custom Application class, will ensure that it is available in the rest of the code.
Realm.init(this);
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.initialData(CompositeInitialData.of(new InitialDataNews(), new InitialData()).build());
Realm.setDefaultConfiguration(realmConfiguration);
}
Add change Listener
public class PersonPage extends AppCompatActivity implements PersonAdapter.PersonListListener{
private RecyclerView recyclerView;
private PersonAdapter adapter;
private Realm PersonRealm;
private RealmResults<PersoneModel> personResult;
private RealmChangeListener realmListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mycolleagues_layout);
personRealm = Realm.getDefaultInstance();
recyclerView = (RecyclerView) findViewById(R.id.colleagues_recycler);
realmListener=new RealmChangeListener() {
@Override
public void onChange(Object o) {
showAllPersons();
}};
colleagueRealm.addChangeListener(realmListener);
setUpRecycler();
}
private void showAllPersons() {
realmResult = personRealm.where(PersonModel.class).findAllAsync();
setAdapter(realmResult);
adapter.notifyDataSetChanged();
}
private void setAdapter(RealmResults<PersonModel> results) {
adapter = new PersonAdapter(this, personRealm.where(PersonModel.class).findAllSortedAsync("id"),this);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
回答1:
That's because in onCreate()
, you run basicCRUD(personRealm);
which adds new person models
PersonModel model = new PersonModel();
model.setId(1 + System.currentTimeMillis());
model.setName("Name1");
model.setCompany("Comapny1");
model.setTitle("Title1");
person.add(model);
As you set id as 1 + System.currentTimeMillis()
, it will be a new object with a different primary key, and it gets inserted. If it were just 1
, 2
and so on then it'd update them as the same object.
Thankfully, Realm provides the initialData(Realm.Transaction) method on the RealmConfiguration.Builder() which allows you to create the initial data for the database only when the database is first created, or if the data is deleted after deleteRealmIfMigrationNeeded()
.
public class InitialData implements Realm.Transaction {
@Override
public void execute(Realm realm) {
List<PersonModel> person = new ArrayList<>();
PersonModel model = new PersonModel();
model.setId(1 + System.currentTimeMillis());
model.setName("Name1");
model.setCompany("Comapny1");
model.setTitle("Title1");
person.add(model);
model = new PersonModel();
model.setId(2 + System.currentTimeMillis());
model.setName("Name2");
model.setCompany("Company2");
model.setTitle("Title2");
person.add(model);
model = new PersonModel();
model.setId(3 + System.currentTimeMillis());
model.setName("Name3");
model.setCompany("Company23");
model.setTitle("Title3");
person.add(model);
model = new PersonModel();
model.setId(4 + System.currentTimeMillis());
model.setName("Name4");
model.setCompany("Comapny4");
model.setTitle("Title4");
person.add(model);
for (PersonModel realmModel : person) {
realm.insertOrUpdate(realmModel);
}
}
@Override
public boolean equals(Object object) {
return object != null && object instanceof InitialData;
}
@Override
public int hashCode() {
return InitialData.class.hashCode();
}
}
And
Realm.init(this);
Realm.setDefaultConfiguration(new RealmConfiguration.Builder()
.deleteRealmIfMigrationNeeded()
.initialData(new InitialData())
.build());
EDIT:
To provide multiple "initial datas" in only one "initial data" (as you provide 1 transaction), you can rely on the composite design pattern
to provide multiple initial datas in just one initial data, like so
public final class InitialDataPersons implements Realm.Transaction {
@Override
public void execute(Realm realm) {
List<PersonModel> person = new ArrayList<>();
PersonModel model = new PersonModel();
model.setId(1 + System.currentTimeMillis());
model.setName("Name1");
model.setCompany("Comapny1");
model.setTitle("Title1");
person.add(model);
model = new PersonModel();
model.setId(2 + System.currentTimeMillis());
model.setName("Name2");
model.setCompany("Company2");
model.setTitle("Title2");
person.add(model);
model = new PersonModel();
model.setId(3 + System.currentTimeMillis());
model.setName("Name3");
model.setCompany("Company23");
model.setTitle("Title3");
person.add(model);
model = new PersonModel();
model.setId(4 + System.currentTimeMillis());
model.setName("Name4");
model.setCompany("Comapny4");
model.setTitle("Title4");
person.add(model);
for (PersonModel realmModel : person) {
realm.insertOrUpdate(realmModel);
}
}
@Override
public boolean equals(Object object) {
return object != null && object instanceof InitialDataPersons;
}
@Override
public int hashCode() {
return InitialDataPersons.class.hashCode();
}
}
and
public final class InitialDataNews implements Realm.Transaction {
@Override
public void execute(Realm realm) {
List<NewsModel> newsItem = new ArrayList<>();
NewsModel model = new NewsModel();
model.setId(1+System.currentTimeMillis());
model.setImage(R.drawable.image1);
model.setTitle("title1");
model.setDate("12.07.2017");
model.setDetail("deascription");
newsItem.add(model);
model = new NewsModel();
model.setId(3+System.currentTimeMillis());
model.setImage(R.drawable.image3);
model.setTitle("title2");
model.setDate("05.05.2017");
model.setDetail("description");
newsItem.add(model);
model = new NewsModel();
model.setId(4+System.currentTimeMillis());
model.setImage(R.drawable.image4);
model.setTitle("title3");
model.setDate("13.04.2017");
model.setDetail("description3");
newsItem.add(model);
.....
for (NewsModel realmModel : newsItem) {
realm.insertOrUpdate(realmModel);
}
}
@Override
public boolean equals(Object obj) {
return obj != null && obj instanceof InitialDataNews;
}
@Override
public int hashCode() {
return InitialDataNews.class.hashCode();
}
}
and
public final class CompositeInitialData implements Realm.Transaction {
private final Realm.Transaction[] transactions;
private CompositeInitialData(Realm.Transaction... transactions) { // `of` is prettier
this.transactions = transactions;
}
public static CompositeInitialData of(Realm.Transaction... transactions) {
return new CompositeInitialData(transactions);
}
@Override
public void execute(Realm realm) {
for(Realm.Transaction transaction : transactions) {
transaction.execute(realm);
}
}
@Override
public boolean equals(Object obj) {
return obj != null && obj instanceof CompositeInitialData; // you might want autogenerated equals instead
}
@Override
public int hashCode() {
return CompositeInitialData.class.hashCode(); // you might want autogenerated hashCode instead
}
}
This way you can provide
Realm.init(this);
Realm.setDefaultConfiguration(new RealmConfiguration.Builder()
.deleteIfMigrationNeeded()
.initialData(CompositeInitialData.of(new InitialDataNews(), new InitialDataPersons()))
.build());
来源:https://stackoverflow.com/questions/45592132/execute-transaction-method-using-realm-continues-to-loop-on-each-run-android