i have a RecyclerView with Dialog Fragment , and i get data from user in via the Dialog and stored it in the database then , i display it in recyclerview , and all this is working , my problem is , when i add the data i must restart the app to display it into recycler , how i can notify the adapter data is change ?
the add button in the Dialog Fragment
add = (Button) rootView.findViewById(R.id.addbutton);
add.setOnClickListener(this);
private void insert() {
Title = addTitle.getText().toString();
Des= addDesc.getText().toString();
db.insertIntoDB(Title, Des);}
#Override
public void onClick(View v) {
if (addTitle.getText().toString().trim().equals("")) {
addTitle.setError(" Title is required!");
} else if (addDesc.getText().toString().trim().equals("")) {
addDesc.setError(" Postion is required!");
}
Toast.makeText(getContext(),"your data is saved", Toast.LENGTH_SHORT).show();
insert();
}
and this is the getdata method in the helper class
public List<ToDoModule> getDataFromDB(){
List<ToDoModule> modelList = new ArrayList<ToDoModule>();
String query = "select * from "+ TODO_TABLE;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(query,null);
if (cursor.moveToFirst()){
do {
ToDoModule model = new ToDoModule();
model.setActionTitle(cursor.getString(1));
model.setActionDesc(cursor.getString(2));
modelList.add(model);
}while (cursor.moveToNext());
}
return modelList;
}
and this is the main activity
public class MainActivity extends AppCompatActivity {
public List<ToDoModule> dbList;
RecyclerView mRecyclerView;
DatabaseHelpher helpher;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().hide();
helpher = new DatabaseHelpher(this);
dbList= new ArrayList<ToDoModule>();
dbList = helpher.getDataFromDB();
mRecyclerView = (RecyclerView)findViewById(R.id.AppRecyclerView);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new RecyclerAdapter(this,dbList);
this.dbList =helpher.getDataFromDB();
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setImageResource(R.drawable.ic_action_name);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FragmentManager fm = getSupportFragmentManager();
addAction add = new addAction();
add.show(fm,"fragment_edit_name");
}});}
#Override
protected void onResume() {
super.onResume();
}
}
DialogFragments, like all fragments, are directly tied to the lifecycle of the Activity that uses them. Therefore the onResume() callback is not called by the activity after a user dismisses the dialogFragment.
For simplicity and easy maintainability, I would create an interface,
public interface DialogFragUpdateListener {
public void OnDBUpdate();
}
which your activity will implement,
public class MainActivity extends AppCompatActivity implements DialogFragUpdateListener{
that receives a callback whenever the user finishes the action you are having them do in the DialogFragment. I would add this in your onClick() method after the insert() is called:
(DialogFragUpdateListener)getActivity()).OnDBUpdate()
Then in your activity, this callback method can them query the updated data from the database and update the adapter/recyclerview again:
public void OnDBUpdate() {
// Requery data from database here
getDataFromDB();
}
Check this out for reference:
https://developer.android.com/guide/components/fragments.html#CommunicatingWithActivity
Related
I have an activity from which I call the dialog. On positive dialog's event I'm trying to add a custom item form the "showAddPhraseDialog" method to the List (phrasesToSave) which is property of the activity's class.
But the list size do not increases.
Activity class:
public class AddActivity extends AppCompatActivity {
private RecyclerView rv_select_person;
private ChildHorizontalAdapter personAdapter;
private RecyclerView rv_conversation;
private UnsavedConversationAdapter conversationAdapter;
private List<UnsavedPhrase> phrasesToSave;
private List<Child> personsList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
phrasesToSave = new ArrayList<UnsavedPhrase>();
// conversation widgets
rv_conversation = (RecyclerView) findViewById(R.id.rv_conversation);
conversationAdapter = new UnsavedConversationAdapter(phrasesToSave);
LinearLayoutManager llm = new LinearLayoutManager(AddActivity.this);
rv_conversation.setLayoutManager(llm);
rv_conversation.setAdapter(conversationAdapter);
...
}
private void showAddPhraseDialog(final Child phrase_author)
{
boolean wrapInScrollView = true;
new MaterialDialog.Builder(AddActivity.this)
.title(R.string.label_what_was_said)
.customView(R.layout.dialog_add_phrase, wrapInScrollView)
.positiveText(R.string.button_add)
.onPositive(new MaterialDialog.SingleButtonCallback() {
#Override
public void onClick(#NonNull MaterialDialog dialog, #NonNull DialogAction which) {
EditText tePhrase = (EditText)dialog.findViewById(R.id.te_phrase);
String phrase_text = tePhrase.getText().toString();
if (!StringUtils.isNullAndEmpty(phrase_text)) {
UnsavedPhrase new_phrase = new UnsavedPhrase(phrase_text, phrase_author);
phrasesToSave.add(new_phrase);
}
}
})
.show();
}
}
Try to debug and check that after the phrasesToSave.add(new_phrase); the list has one new element in it. If it has a new element, but you don't see the element in your UI, you should notify the RecyclerView that it's data set has changed. Try calling notifyDataSetChanged(). Docs for it.
Your code looks fine. If there isn't a new element in phrasesToSave after the add, then try to clean your project. Build -> Clean Project
Sorry for late reply You forgot to notify the adapter
if(conversationAdapter != null)
{
conversationAdapter.notifyDataSetChanged();
}
In my App I have stored some mockdata to show at the starting of the app. Now I have another option to add data into Realm database. But in my app, all the duplicate data is stored within the database. For Example I have three data in setRealmData() method. within this method I created same data with similar information. This data is checked perfectly. But whenever I tried to add a new data with simialer name it also stored within the app, which I do not want actually. How can I duplicate check in with preload data to new data in Realm.
My Activity Class is
public class MyColleaguesPage extends AppCompatActivity implements MyColleaguesAdapter.ColleagueListListener{
private RecyclerView recyclerView;
private MyColleaguesAdapter adapter;
private Realm colleagueRealm;
private RealmResults<MyColleagueModel> dataResult;
private static final String DIALOG_TAG = "EmployeeDialog";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mycolleagues_layout);
// Showing and Enabling clicks on the Home/Up button
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
colleagueRealm = Realm.getDefaultInstance();
recyclerView = (RecyclerView) findViewById(R.id.colleagues_recycler);
setUpRecycler();
if (!Prefs.with(this).getPreLoad()) {
setRealmData();
}
showAllPersons();
}
private void showAllPersons() {
dataResult = colleagueRealm.where(MyColleagueModel.class).findAll();
setAdapter(dataResult);
adapter.notifyDataSetChanged();
}
private void setAdapter(RealmResults<MyColleagueModel> results) {
adapter = new MyColleaguesAdapter(this, colleagueRealm.where(MyColleagueModel.class).findAllSortedAsync("id"),this);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
private void setUpRecycler() {
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerView.setHasFixedSize(true);
// use a linear layout manager since the cards are vertically scrollable
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
}
private void setRealmData(){
List<MyColleagueModel> colleague = new ArrayList<>();
MyColleagueModel model = new MyColleagueModel();
model.setId(1);
model.setName("Name1");
model.setCompany("Comapny1");
model.setTitle("Title1");
colleague.add(model);
model = new MyColleagueModel();
model.setId(2);
model.setName("Name2");
model.setCompany("Comapny2");
model.setTitle("Title1");
colleague.add(model);
model = new MyColleagueModel();
model.setId(2);
model.setName("Name2");
model.setCompany("Comapny2");
model.setTitle("Title1");
colleague.add(model);
model = new MyColleagueModel();
model.setId(3);
model.setName("Name3");
model.setCompany("Comapny3");
model.setTitle("Title3");
colleague.add(model);
for (MyColleagueModel realmModel : colleague) {
// Persist the colleague data
colleagueRealm.beginTransaction();
colleagueRealm.copyToRealmOrUpdate(realmModel);
colleagueRealm.commitTransaction();
}
Prefs.with(this).setPreLoad(true);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.recycler_menu, menu);
final MenuItem item = menu.findItem(R.id.search);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == android.R.id.home) {
finish();
}
//onOptionsItemSelected(MenuItem item) add will open dialog box, which allows user to fill required data
if (id == R.id.addColleague) {
showAlertDialog();
return true;
}
return super.onOptionsItemSelected(item);
}
private void showAlertDialog() {
EditColleagueFragment dialog = new EditColleagueFragment();
//dialog.setPositiveButtonClickListener(this);
dialog.show(getSupportFragmentManager(), DIALOG_TAG);
//adapter.notifyDataSetChanged();
}
#Override
protected void onDestroy() {
if (colleagueRealm!= null)
colleagueRealm.close();
super.onDestroy();
}
}
My EditDialog Fragment Class is
public class EditColleagueFragment extends DialogFragment {
private EditText id;
private EditText name;
private EditText role;
private EditText company;
private EditText mobile;
private EditText email;
private EditText department;
private View view;
private LayoutInflater inflater;
private Realm mRealm;
/*public interface onSaveClickListener {
void onSaved();
}
private onSaveClickListener mSaveClickListener;
public void setPositiveButtonClickListener(onSaveClickListener listener){
mSaveClickListener=listener;
}*/
public EditColleagueFragment() {
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
inflater = getActivity().getLayoutInflater();
view = inflater.inflate(R.layout.edit_my_colleague, null);
id = (EditText) view.findViewById(R.id.id);
name = (EditText) view.findViewById(R.id.name);
role = (EditText) view.findViewById(R.id.role);
company = (EditText) view.findViewById(R.id.company);
mobile = (EditText) view.findViewById(R.id.mobile);
email = (EditText) view.findViewById(R.id.email);
department= (EditText) view.findViewById(R.id.department);
AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity());
dialog.setTitle("Add Colleague");
dialog.setView(view);
dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.cancel();
}
});
dialog.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
savePerson();
}
});
return dialog.create();
}
private void savePerson() {
mRealm = Realm.getDefaultInstance();
mRealm.beginTransaction();
MyColleagueModel model=new MyColleagueModel();
model.setId(id.getId());
model.setName(name.getText().toString());
model.setTitle(role.getText().toString());
model.setCompany(company.getText().toString());
model.setMobile(mobile.getText().toString());
model.setEmail(email.getText().toString());
model.setDepartment(department.getText().toString());
mRealm.copyToRealmOrUpdate(model);
mRealm.commitTransaction();
mRealm.close();
}
}
The way to avoid duplication of data using the Realm Mobile Platform is to use primary keys.
Normally, all insertions and updates are preserved when synchronizing data between clients, but often multiple clients want to insert data that is logically identical. To ensure that those insertions are collapsed into single objects, you can use a primary key column on the model by which the objects can be identified on both clients. If two clients each insert an object with the same primary key value, the objects will be considered logically the same, and you will end up with just the one object after synchronization.
You haven't shared your model, but it looks like there is an "ID" field — that could serve as the primary key. :-)
Note that if you are only making local changes (no synchronization), primary key conflicts will result in an error being thrown, and you manually have to handle the case of preexisting objects.
If using primary keys is inconvenient for your use case, you always have the option to wait for download to complete and then manually clean up the database — just make sure that clients are able to make the same decisions about which object to discard, so as to avoid throwing away more than necessary.
try use code below
public <E extends RealmModel> boolean isDataExist(Class<E> eClass, int id) {
E data = colleagueRealm.where(eClass).equalTo("id", id).findFirst();
return data != null;
}
private void initData(){
if(isDataExist(MyColleagueModel.class, id.getText().toString())){
// data exist
}else{
// insert new
}
I have a LongClickListener in my RecyclerView's Adapter file that listens for LongClicks on CardViews in a RecyclerView list. The Listener is linked with an interface to the RecyclerView Activity file.
Step 1 after the LongClick launches a DialogFragment for the user to confirm deletion of a CardView. The dialog presents "Cancel" or "OK" choices. "Cancel" just negates the DialogFragment.
Step 2 is where "OK" was selected and the delete code in the DatabaseHelper file will remove the CardView data from the SQLite database.
Step 3 will be an intent to run the RecyclerView Activity again so that the RecyclerView list refreshes and shows the updated list (with the previous CardView removed since the data was deleted in the database).
I am good with Step 1 as a LongClick on any CardView is launches the DialogFragment as expected. I am stuck on Step 2 in the Fragment line "dbHelper.deletefromDB(UserData userdata);". Android Studio warning message is "Cannot resolve symbol 'userdata'". What am I missing here? Below shows the various files in question.
ListActivity file:
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dbList = dbHelper.getAllDataFromDB();
...
ListAdapter mAdapter;
mAdapter = new ListAdapter(this, dbList);
mRecyclerView.setAdapter(mAdapter);
mAdapter.setonItemClickListener(new ListAdapter.ClickListener() {
#Override
public void onItemLongClick(int position, View view) {
FragmentManager fm = getSupportFragmentManager();
DeleteCardViewFragment delCardViewDialog = new DeleteCardViewFragment();
delCardViewDialog.show(fm, "delcardview dialog");
}
});
DatabaseHelper file:
public class DatabaseHelper extends SQLiteOpenHelper {
...
public void deletefromDB(UserData userData) {
SQLiteDatabase db = this.getWritableDatabase();
db.beginTransaction();
db.delete(DBContract.DBEntry.TABLE_NAME_USERINPUTS, DBContract.DBEntry.COLUMN_NAME_ID + " = ?",
new String[]{String.valueOf(userData.getId())});
db.setTransactionSuccessful();
db.endTransaction();
if(db.isOpen())
db.close();
}
}
DeleteCardViewFragment file:
public class DeleteCardViewFragment extends DialogFragment {
DatabaseHelper dbHelper;
public DeleteCardViewFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.delcardview_layout, container, false);
getDialog().setTitle("Delete card");
dbHelper = new DatabaseHelper(getActivity());
Button btnCancel = (Button) rootView.findViewById(R.id.btnCancel);
btnCancel.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
getDialog().cancel();
}
});
Button btnOK = (Button) rootView.findViewById(R.id.btnOK);
btnOK.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
dbHelper.deletefromDB(UserData userdata);
dismiss();
}
});
...
}
}
I'm working on the fragment, when I click a button, it will turn to another activity, after the activity saved data to database, it will return back to the fragment, however, the fragment can't show the newest data, I need to go to the activity of the fragment, then come back to the fragment again, it will show newest data.
Here is my code of fragment. I thought that because I put the setAdapter in the onActivityCreated() method, I tried to put it in onCreate() and onCreateView(), both will return nullpointer error.
public class TodoFragment extends ListFragment {
private TodoDataSource datasource;
private Todo item;
List<Todo> todoList;
MyCustomAdapter adapt;
ListView listTask;
EditText t;
public TodoFragment(){
}
/*#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//setHasOptionsMenu(true);
datasource = new TodoDataSource(getActivity());
datasource.open();
todoList = datasource.getAllTodos();
adapt= new MyCustomAdapter(getActivity(), R.layout.todo_list, todoList);
//ListView listTask =(ListView) rootView.findViewById(android.R.id.list);
listTask.setAdapter(adapt);
}*/
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// if (activity != null) {
// Create an instance of the custom adapter for the GridView. A static array of location data
// is stored in the Application sub-class for this app. This data would normally come
// from a database or a web service.
datasource = new TodoDataSource(getActivity());
datasource.open();
todoList = datasource.getAllTodos();
adapt= new MyCustomAdapter(getActivity(), R.layout.todo_list, todoList);
//ListView listTask =(ListView) rootView.findViewById(android.R.id.list);
listTask.setAdapter(adapt);
Button button = (Button) getActivity().findViewById(R.id.simpleadd);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//String summary = t.getText().toString();
Intent i = new Intent(getActivity(), TodoDetailActivity.class);
//Bundle bundle = new Bundle();
// bundle.putString("Summary", summary);
//i.putExtras(bundle);
startActivity(i);
}
});
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.main, menu);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_todo, container, false);
t = (EditText) rootView.findViewById(R.id.simple);
listTask = (ListView) rootView.findViewById(android.R.id.list);
return rootView;
}
#Override
public void onResume() {
datasource.open();
super.onResume();
adapt.notifyDataSetChanged();
}
#Override
public void onPause() {
datasource.close();
super.onPause();
}
}
Here is part of my another activity code.
it will update the database and return to the fragment.
confirmButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (TextUtils.isEmpty(mTitleText.getText().toString())) {
makeToast();
} else {
final String category = mCategory.getSelectedItem().toString();
final String summary = mTitleText.getText().toString();
final String description = mBodyText.getText().toString();
datasource.createTodo(category, summary, description);
setResult(RESULT_OK);
finish();
}
}
});
It looks like you aren't updating your data source todoList before calling notifyDataSetChanged() in onResume().
Edit: Clear the list first, and then re-populate. Also add logging to help track down the issue:
#Override
public void onResume() {
super.onResume();
datasource.open();
todoList.clear();
todoList.addAll(datasource.getAllTodos());
adapt.notifyDataSetChanged();
Log.d("MyApp", "Size of data: " + todoList.size() );
}
Once you have added that code, try adding a few records, and watch your logcat to see if the size goes up. You can also cycle through each record, if you post your Todo class I can give you some example code.
I am using a ListFragment for displaying a list from a database in my activity. I have included a search function. Unfortunately the "old" ListFragments seem to remain in the background and the ListFragments containing the result of the query are displayed on top of it. How can I avoid, that the old ListFragments are displayed?
My FragmentActivity:
private Button buttonSearch;
private TextView searchString;
public static String search = null;
static IShoppinglist shoppinglistManager;
static IAktionen aktionenManager;
private AktionenListListFragment listFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "ListFragmentActivity created");
super.onCreate(savedInstanceState);
setContentView(R.layout.articlelist);
shoppinglistManager = new Shoppinglist(this);
aktionenManager = new Aktionen(this);
buttonSearch = (Button) findViewById(R.id.search_Button);
buttonSearch.setOnClickListener(searchListAktionen);
//show all entries on start
listFragment = new AktionenListListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_articlelist, listFragment).commit();
}
OnClickListener searchListAktionen = new OnClickListener() {
public void onClick(View v) {
try{
searchString = (TextView) findViewById(R.id.input_search_bezeichnung);
search = searchString.getText().toString().trim();
Log.d(TAG, "search Button clicked "+search);
if(search.trim().length()==0){
search=null;
}
//show all entries on start
listFragment = new AktionenListListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_articlelist, listFragment).commit();
}catch(Exception ex){
ex.printStackTrace();
}
}
};
Thanks in advance,
update:
thank you for your answers. I tried to implement them, but the main problem seems to be nowthat the onCreate and onActivityCreated method in the ListFragment are called twice (as I can see in my log messages).
my new code:
#Override
public void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "ListFragmentActivity created");
super.onCreate(savedInstanceState);
//force commit
getSupportFragmentManager().executePendingTransactions();
if(getSupportFragmentManager().findFragmentByTag(tag) == null) {
setContentView(R.layout.articlelist);
shoppinglistManager = new Shoppinglist(this);
aktionenManager = new Aktionen(this);
buttonSearch = (Button) findViewById(R.id.search_Button);
buttonSearch.setOnClickListener(searchListAktionen);
listFragment = new AktionenListListFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_articlelist, listFragment,tag).commit();
}else{
Log.d(TAG, "ListFragment already exists");
}
}
I tried to set a unique tag for my ListFragment but this solution does not work.
I guess that one of the ListFragments is displayed in the background and the other is updated.
So first you need to stop making new ListFragments everytime your list is refreshed and just have a public method in your ListFragment that the Activity can call to restart the loader with the proper parameters. Then:
In your onLoadFinished(),
you should make a new adapter with the list you want to replace it with
myAdapter = new AktionenListCustomCursorAdapter(getActivity(), myCursor);
and call:
this.getListView().setAdapter(myAdapter);
So:
public void onLoadFinished(Loader<Cursor> mAdapter, Cursor myCursor) {
if(myCursor!=null){
//getting the data from the database
Log.d(TAG, "search String "+AktionenListFragmentActivity.search);
if(AktionenListFragmentActivity.search==null){
myCursor = AktionenListFragmentActivity.aktionenManager.fetchAllArticles();
}else{
myCursor = AktionenListFragmentActivity.aktionenManager.fetchItemsByBezeichnung(AktionenListFragmentActivity.search);
}
myAdapter = new AktionenListCustomCursorAdapter(getActivity(), myCursor);
this.getListView().setAdapter(myAdapter);
}
}
Hopefully this solved your question as I understood it. If you have any questions please leave it in the comment below and I will expand my answer. If it worked for you please accept answer. :D