Sorry for my bad english and a stupid noob question.
I have a SimpleCursorAdapter and a ListView with Buttons on each item (row in database).
I realize deleting row but I don`t know how to refresh the ListView.
I hope that somebody can help me with simple and clear examples
my adapter
public class MySimpleCursorAdapter extends SimpleCursorAdapter {
Context context;
public MySimpleCursorAdapter(Context contxt, int layout, Cursor c, String[] from, int[] to, int flags) {
super(contxt, layout, c, from, to, flags);
context=contxt;
}
public View newView(Context _context, Cursor _cursor, ViewGroup parent){
LayoutInflater inflater = (LayoutInflater) _context.getSystemService(_context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.listform_item, parent, false);
return view;
}
#Override
public void bindView(View view, Context Context, Cursor cursor) {
String name = cursor.getString(cursor.getColumnIndex(DBHelper.FORM_NAME));
String title = cursor.getString(cursor.getColumnIndex(DBHelper.FORM_TITLE));
TextView formname = (TextView)view.findViewById(R.id.tvFormName);
formname.setText(name);
TextView formtitle=(TextView)view.findViewById(R.id.tvFormTitle);
formtitle.setText(title);
ImageButton yourButton = (ImageButton)view.findViewById(R.id.ibtnDelete);
yourButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(view != null) {
Object obj = view.getTag();
//if(obj != null && obj instanceof Integer) {
dbForm form=new dbForm(context);
form.open();
String st=obj.toString();
form.deleteForm(Long.valueOf(st).longValue());
Toast.makeText(context, "Delete row with id = " + st, Toast.LENGTH_LONG).show();
}
}
});
Object obj = cursor.getString(cursor.getColumnIndex(DBHelper.FORM_ID));
yourButton.setTag(obj);
}
}
I also use a CursorLoader in Main to acces the database
UPD: i use use cursor loader and a dont undertand how call his reset in my custom adapter, hope for help.
public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {
ListView lvForms;
dbForm table_form;
SimpleCursorAdapter scAdapter;
/**
* Called when the activity is first created.
*/
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
table_form = new dbForm(this);
table_form.open();
String[] from = new String[]{DBHelper.FORM_NAME, DBHelper.FORM_TITLE};
int[] to = new int[]{R.id.tvFormName, R.id.tvFormTitle};
scAdapter = new MySimpleCursorAdapter(this, R.layout.listform_item, null, from, to, 0);
lvForms = (ListView) findViewById(R.id.lvForms);
lvForms.setAdapter(scAdapter);
registerForContextMenu(lvForms);
getSupportLoaderManager().initLoader(0, null, this);
}
public void onButtonClick(View view) {
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
}
protected void onDestroy() {
super.onDestroy();
table_form.close();
// закрываем подключение при выходе
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle bndl) {
return new MyCursorLoader(this, table_form);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
scAdapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
scAdapter.swapCursor(null);
}
static class MyCursorLoader extends CursorLoader {
dbForm table_form;
public MyCursorLoader(Context context, dbForm table_form) {
super(context);
this.table_form = table_form;
}
#Override
public Cursor loadInBackground() {
Cursor cursor = table_form.getAllData();
return cursor;
}
}
}
For a SimpleCursorAdapter it's best to use a CursorLoader like this :
public Loader<Cursor> onCreateLoader(int id,Bundle arg) {
return new SimpleCursorLoader(this) {
public Cursor loadInBackground() {
// This field reserved to what you want to load in your cursor adater and you return it (for example database query result)
// return Cursor ;
}
};
}
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
}
public void onLoaderReset(Loader<Cursor> loader){
adapter.swapCursor(null);
}
And in your MainActivity or where you will instanciate the adapter, just before add this :
getLoaderManager().initLoader(0x01, null, this);
// declare your new Custom Simple Cursor Adapter here
scAdapter = new MySimpleCursorAdapter ....
And add :
public void onResume() {
super.onResume();
// Restart loader so that it refreshes displayed items according to database
getLoaderManager().restartLoader(0x01, null, this);
}
I work with loaders this way, I hope it helps you .
You should reload your cursor and update your cursor adapter:
// Reload your cursor here
Cursor newCursor = ….;
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD){
adapter.swapCursor(newCurosr);
} else {
adapter.changeCursor(newCursor);
}
Then, notify your list view about data changes:
adapter.notifyDataSetChanged();
Related
I am deleting a row from my local database using the long press on the UI and after deleting, the row would be removed automatically from among the list in User Interface.
public class AllData extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
DotCursorAdapter mAdapter;
private ListView lv;
Context context = this;
private final int LOADER_ID = 860;
public static DatabaseHandler dbHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lv = (ListView) findViewById(R.id.lists);
dbHelper = new DatabaseHandler(this);
mAdapter = new DotCursorAdapter(this, null, 1);
getSupportLoaderManager().initLoader(LOADER_ID, null, this);
lv.setAdapter(mAdapter);
lv.setTextFilterEnabled(true);
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
return new DumbLoader(this);
}
#Override
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
mAdapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> cursorLoader) {
mAdapter.swapCursor(null);
}
/**
* DumbLoader sub class
*/
public static class DumbLoader extends CursorLoader {
public DumbLoader(Context context) {
super(context);
}
#Override
public Cursor loadInBackground() {
Cursor c = dbHelper.FetchAllData();
return c;
}
}
public final class DotCursorAdapter extends CursorAdapter {
public DotCursorAdapter(Context context, Cursor cursor, int flags) {
super(context, cursor, 0);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.visitation_activity, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
/**
* Data from the local database
*/
final String id = cursor.getString(cursor.getColumnIndexOrThrow("_id"));
final String date = cursor.getString(cursor.getColumnIndexOrThrow("created_at"));
view.setTag(Long.valueOf(id));
view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {
((AllData) mContext).deleteData(((Long) view.getTag()).longValue());
return true;
}
});
}
}
/**
* Delete data and update list view
*/
public void deleteData(long id) {
final long alarmId = id;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Please confirm")
.setTitle("Delete set?")
.setCancelable(true)
.setNegativeButton("Cancel", null)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dbHelper.deleteData(alarmId);
//Refresh the list of the alarms in the adaptor
dbHelper.FetchAllData();
//Notify the adapter the data has changed
mAdapter.notifyDataSetChanged();
}
}).show();
}}
With the codes above I am able to delete the data from the local database, but it doesn't remove the deleted row from the user interface, unless I refresh the page.
Please is there a way to automatically remove the deleted row from among the list view after the deletion has taken place. Thanks in advance.
use this getSupportLoaderManager().restartLoader(0, null, AllData.this); instead of mAdapter.notifyDataSetChanged(); to refresh list items
or you can use intent and keep the source activity and target activity same..... and use this line after deleting the row
Intent i = new Intent(sourceActivity.this,targetActivity.this);
startActivity(i);
sourceActivity.finish();
In my onCreate:
ListView Definition:
listView = (ListView) findViewById(R.id.listView1);
Loader Manager:
getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() {
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(ListDetailActivity.this,
ReceiptProvider.URI_RECEIPT, Receipt.FIELDS, null, null,
null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
System.out.println("Cursor: " + c);
}
#Override
public void onLoaderReset(Loader<Cursor> arg0) {
}
});
My custom Cursor adapter:
private class CurAdapter extends CursorAdapter {
public CurAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView tv = (TextView) view.findViewById(R.id.textView2);
String name = (cursor.getString(cursor.getColumnIndexOrThrow("receipt_name")));
tv.setText(name);
//setImage(image, iv);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = LayoutInflater.from(context).inflate(R.layout.list_layout, null);
return view;
}
}
How do I set the Cursor to list now? I know how to do it for a SimpleCursorAdapter, but I am clueless on how to do it for a Cursor Adapter, any hints?
For now I am doing it like:
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
CurAdapter Cur = new CurAdapter(ListDetailActivity.this, c, 0);
listView.setAdapter(Cur);
}
It works properly, but I am not sure if this is the proper way to do this?
maybe so:
listView.setAdapter(new CurAdapter(this, cursor));
you need to set your adapter to listview in init method and hold the reference to adapter as a field. it is ok to pass null as a cursor parameter. There are two methods in CursorAdapter class changeCursor and swapCursor, use one you need to set the cursor in onLoadFinished.
Update: https://developer.android.com/training/load-data-background/handle-results.html
I'm trying to have a multiselect preference with data that is populated from a database via a cursor. I've got this so far
Cursor cursor = getActivity().getContentResolver().query(EntryProvider.WEBSITES_URI,null,null,null,EntryProvider.WEBSITES_SORT_ORDER);
while (cursor.moveToNext()) {
String name = cursor.getString(EntryData.COL_WEBSITE_NAME);
String displayName = cursor.getString(EntryData.COL_WEBSITE_ENABLED);
entries.add(name);
entriesValues.add(displayName);
}
feedSelectionPref = (MultiSelectListPreference)findPreference("feedChooser");
feedSelectionPref.setEntries(entries.toArray(new CharSequence[]{}));
feedSelectionPref.setEntryValues(entriesValues.toArray(new CharSequence[]{}));
and it fill up the prefrence fine, but I cannot figure out how to get the saved values and persist them to the database.
How can I get the new values from the preference? I tried setOnPreferenceChangeListener but it gave me the same values that I filled the list with, not the new ones.
(Would it be easier to just build a listview with checkboxes?)
So I solved the problem by just creating a popup list activity.
public class FeedChooserPopupActivity extends Activity {
ListView listView;
Cursor cursor;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_feed_chooser);
initViews();
}
private void initViews(){
setupCursor();
setupListView();
setupButton();
}
private void setupButton() {
((Button)findViewById(R.id.feedOkbutton)).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FeedChooserPopupActivity.this.finish();
}
});
}
private void setupCursor() {
cursor = getContentResolver().query(EntryProvider.WEBSITES_URI,null,null,null,EntryProvider.WEBSITES_SORT_ORDER);
}
private void setupListView() {
listView = (ListView)findViewById(R.id.feedListView);
listView.setAdapter(new FeedCursorAdapter(this,
cursor,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER
));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (view != null) {
String websiteName = ((TextView)view.findViewById(R.id.feedTextView)).getText().toString();
CheckBox checkBox = (CheckBox)view.findViewById(R.id.feedCheckBox);
checkBox.setChecked(!checkBox.isChecked());
ContentValues cv = new ContentValues();
int enabled = 0;
if(checkBox.isChecked()){
enabled = 1;
}
cv.put(EntryData.KEY_WEBSITE_ENABLED, enabled);
String where = EntryData.KEY_WEBSITE_NAME+" = '"+websiteName+"'";
getContentResolver().update(EntryProvider.WEBSITES_URI,cv,where,null);
}
}
});
}
private class FeedCursorAdapter extends CursorAdapter {
public FeedCursorAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.feed_chooser_list_item,parent,false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
((TextView)view.findViewById(R.id.feedTextView)).setText(cursor.getString(EntryData.COL_WEBSITE_NAME));
((CheckBox)view.findViewById(R.id.feedCheckBox)).setChecked(
cursor.getInt(EntryData.COL_WEBSITE_ENABLED)==1
);
}
}
can you help me with simple eample? I have listitem with textboxes and 2 iagebutton, how i can bind listeners to my buttons without writing new custom adapter by null(i hope override just simplecursoradapter).
Sorry for my hard english, and i hope, that you give me clear and simple for understanding examples.
public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor> {
ListView lvForms;
dbForm table_form;
SimpleCursorAdapter scAdapter;
/**
* Called when the activity is first created.
*/
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
table_form=new dbForm(this);
table_form.open();
String[] from = new String[]{DBHelper.FORM_NAME, DBHelper.FORM_TITLE};
int[] to = new int[]{R.id.tvFormName, R.id.tvFormTitle};
scAdapter = new SimpleCursorAdapter(this, R.layout.listform_item, null, from, to, 0);
lvForms = (ListView) findViewById(R.id.lvForms);
lvForms.setAdapter(scAdapter);
registerForContextMenu(lvForms);
getSupportLoaderManager().initLoader(0, null, this);
}
// обработка нажатия кнопки
public void onButtonClick(View view) {
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
}
protected void onDestroy() {
super.onDestroy();
table_form.close();
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle bndl) {
return new MyCursorLoader(this, table_form);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
scAdapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
static class MyCursorLoader extends CursorLoader {
dbForm table_form;
public MyCursorLoader(Context context, dbForm table_form) {
super(context);
this.table_form = table_form;
}
#Override
public Cursor loadInBackground() {
Cursor cursor = table_form.getAllData();
return cursor;
}
}
}
UPD: i write custom class
class MySimpleCursorAdapter extends SimpleCursorAdapter {
public MySimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView != null) {
return convertView;
}
return LayoutInflater.from(context).inflate(R.layout.listform_item);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
String name = cursor.getString(cursor.getColumnIndex(DBHelper.FORM_NAME));
TextView text = (TextView) findViewById(R.id.tvFormName);
text.setText(name);
Button yourButton = (Button) findViewById(R.id.ibtnDelete);
yourButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
}
}
but have error on return LayoutInflater.from(context).inflate(R.layout.listform_item); and can you tell me how now use listener for button(for delete item, for example)? how get number of item where we click on button?
Don`t use getView in overriding the simple cursor adapter and other cursor adapters. You must override the newView and bindView methods.
Here is my working code
public View newView(Context _context, Cursor _cursor, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) _context.getSystemService(_context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.listform_item, parent, false);
return view;
}
#Override
public void bindView(View view, Context Context, Cursor cursor) {
String name = cursor.getString(cursor.getColumnIndex(DBHelper.FORM_NAME));
String title = cursor.getString(cursor.getColumnIndex(DBHelper.FORM_TITLE));
TextView formname = (TextView) view.findViewById(R.id.tvFormName);
formname.setText(name);
TextView formtitle = (TextView) view.findViewById(R.id.tvFormTitle);
formtitle.setText(title);
ImageButton yourButton = (ImageButton) view.findViewById(R.id.ibtnDelete);
yourButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (view != null) {
Object obj = view.getTag();
//if(obj != null && obj instanceof Integer) {
dbForm form = new dbForm(context);
form.open();
String st = obj.toString();
form.deleteForm(Long.valueOf(st).longValue());
Toast.makeText(context, "Delete row with id = " + st, Toast.LENGTH_LONG).show();
}
}
});
Object obj = cursor.getString(cursor.getColumnIndex(DBHelper.FORM_ID));
yourButton.setTag(obj);
}
You have to subclass SimpleCursorAdapter.
Override two methods getView and bindView:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView != null) {
return convertView;
}
return LayoutInflater.from(context).inflate( R.layout.listform_item);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
String name = cursor.getString(cursor.getColumnIndex(DBHelper.FORM_NAME));
TextView text = (TextView) viewfindViewById(R.id.tvFormName);
text.setText(name );
Button yourButton = (Button) viewfindViewById(R.id.magic_button);
yourButton.setOnClickListener(new View.OnClickListener(){ //implement listener here});
}
I'am loading data into listview from cursors by initiating multiple loaders. I want my listview to show the data from all cursors but data in listview is changing immediately with a 2 seconds interval and showing data of only last cursor. Please help me. Where iam going wrong? Do I have to merge the cursors?
Inside onCreateView() of my fragment :
for (int i = 0; i < idsArray.length; i++) {
Bundle b = new Bundle();
b.putInt("id", idsArray[i]);
getLoaderManager().initLoader(idsArray[i], b, this); //initiating multiple loaders
}
adapter = new CustomAdapter(getActivity(), R.layout.list_row, null, column_names_array, ui_ids_array, 0);
listView.setAdapter(adapter);
And loader callback methods :
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle b) {
Builder uriBuilder = MY_PROVIDER_URI.buildUpon();
uriBuilder.appendPath("categories");
uriBuilder.appendPath(String.valueOf(b.getInt("id")));
uriBuilder.appendPath("data");
return new CursorLoader(getActivity(), uriBuilder.build(), null, null, null, null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if(adapter != null && data != null){
adapter.swapCursor(data);
adapter.notifyDataSetChanged();
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
And here is my adapter class :
public class CustomAdapter extends SimpleCursorAdapter {
Cursor cursor;
Context context;
Activity activity;
int layout;
public CustomAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags ) {
super(context, layout, c, from, to, flags);
this.cursor = c;
this.context = context;
this.activity = (Activity) context;
this.layout = layout;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(this.layout, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
super.bindView(view, context, cursor);
ViewHolder holder = (ViewHolder) view.getTag();
if (holder == null) {
holder = new ViewHolder();
//finding UI elements in list row here
view.setTag(holder);
}
//binding data to views of viewholder here
}
static class ViewHolder {
//variables of all my UI elements
}
}
Your loop :
for (int i = 0; i < idsArray.length; i++) {
Bundle b = new Bundle();
b.putInt("id", idsArray[i]);
getLoaderManager().initLoader(idsArray[i], b, this); //initiating multiple loaders
}
will result in creating multiple Loaders, once a Loader has finished loading its data, the method
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if(adapter != null && data != null){
// This line result in replacing the last Cursor by the new one
adapter.swapCursor(data);
adapter.notifyDataSetChanged();
}
}
is invoked. When the last Loader has finished loading the Cursor, its data will replace the last Cursor because of swapCursor.
If you look at the CursorAdapter documentation, you will notice that this CursorAdapter can only manage one Cursor at a time.
To resolve your problem, you should try to query all the wanted data into a single query, resulting in a single Cursor.