I have a list view populated from a sqlite data fetched with a cursor which was displayed with an adapter, I want to sort the list view on action bar menu click but cursor seems not as straight forward like an array list.
Snippet the receives cursor object and passed to adapter in the onCreate()
databaseManager = new DatabaseManager(this);
databaseManager.open();
cursor = databaseManager.queryAllInsects();
swapCursor(cursor);
mAdapter = new InsectRecyclerAdapter(this, cursor);
bugsInsectRecyclerview.setAdapter(mAdapter);
In the optionsItemSelected() where the menu bar would be called to trigger a refresh and sort.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_sort_by_name:
// WHERE SORTING WOULD BE TRIGGERED tried querying the database again an passing sort order to a cursor seems not working
Cursor cursor2 = databaseManager.queryAllInsects(BugsContract.BugsEntry.COLUMN_FRIENDLYNAME);
swapCursor(cursor2);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
How can I possibly sort the listview populated from cursor alphabetically?
An example with a list of users.
Create a comparator :
public class NameComparator implements Comparator<User> {
#Override
public int compare(User x, User y) {
if (x == null) {
if (y != null) return -1;
}
if (y == null) return 1;
int startComparison = x.getFirstName().compareTo(y.getFirstName());
if (startComparison == 0)
startComparison = x.getLastName().compareTo(y.getLastName());
return startComparison;
}
}
Then use it :
Collections.sort(userList, new NameComparator() {});
Try sorting the ArrayList inside the adapter then calling notifyDataSetChanged(). If the data is not changing you could always sort the data given to the adapter before you assign it to the adapter
cursor.sort();
mAdapter = new InsectRecyclerAdapter(this, cursor);
Related
I am building a budget database and I can get all the transactions into the listview and displayed on the screen. I have created a textview to hold the sum of all the transaction values but can't figure out how to get it to display in the textview. I get the following error:
Attempt to invoke virtual method
'android.database.sqlite.SQLiteDatabase
android.content.Context.openOrCreateDatabase(java.lang.String, int,
android.database.sqlite.SQLiteDatabase$CursorFactory)' on a null
object reference.
Here is the code I am trying to get to work:
SQLiteDatabase database = mDbHelper.getReadableDatabase();
public int cmIncomeSum() {
int total = 0;
Cursor sumQuery = database.rawQuery("SELECT SUM(income) FROM transactions WHERE income >=0 AND expense ISNULL AND strftime('%m',date)=strftime('%m',date('now')) AND strftime('%Y',date)=strftime('%Y',date('now'))", null);
if (sumQuery.moveToFirst()) {
total = sumQuery.getInt(0);
}
return total;
}
and the textview:
TextView cmIncomeSumTextView = (TextView) findViewById(R.id.cm_income_sum_text_view);
cmIncomeSumTextView.setText(sum);
and here is the entire activity:
public class CMIncomeTransactionsActivity extends AppCompatActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
/** Identifier for the transaction data loader */
private static final int TRANSACTION_LOADER = 0;
/** Adapter for the ListView */
IncomeCursorAdapter mCursorAdapter;
// Database helper object //
private BudgetDbHelper mDbHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cm_income_transactions);
// Setup FAB to open EditorActivity
Button fab = (Button) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(CMIncomeTransactionsActivity.this, IncomeEditorActivity.class);
startActivity(intent);
}
});
// Find the ListView which will be populated with the transaction data
ListView incomeListView = (ListView) findViewById(R.id.list);
// Find and set empty view on the ListView, so that it only shows when the list has 0 items.
View emptyView = findViewById(R.id.empty_view);
incomeListView.setEmptyView(emptyView);
// Setup an Adapter to create a list item for each row of transaction data in the Cursor.
mCursorAdapter = new IncomeCursorAdapter(this, null);
incomeListView.setAdapter(mCursorAdapter);
// Setup the item click listener
incomeListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
// Create new intent to go to {#link EditorActivity}
Intent intent = new Intent(CMIncomeTransactionsActivity.this, IncomeEditorActivity.class);
// Form the content URI that represents the specific transaction that was clicked on,
// by appending the "id" (passed as input to this method) onto the
// {#link BudgetEntry#CONTENT_URI}.
Uri currentTransactionUri = ContentUris.withAppendedId(BudgetEntry.CONTENT_URI, id);
// Set the URI on the data field of the intent
intent.setData(currentTransactionUri);
// Launch the {#link EditorActivity} to display the data for the current transaction.
startActivity(intent);
}
});
// Kick off the loader
getLoaderManager().initLoader(TRANSACTION_LOADER, null, this);
// Define query for the SUM of the current month income and display it on the screen//
TextView cmIncomeSumTextView = (TextView) findViewById(R.id.cm_income_sum_text_view);
cmIncomeSumTextView.setText(cmIncomeSum());
}
SQLiteDatabase database = mDbHelper.getReadableDatabase();
public int cmIncomeSum() {
int total = 0;
Cursor sumQuery = database.rawQuery("SELECT SUM(income) FROM transactions WHERE income >=0 AND expense ISNULL AND strftime('%m',date)=strftime('%m',date('now')) AND strftime('%Y',date)=strftime('%Y',date('now'))", null);
if (sumQuery.moveToFirst()) {
total = sumQuery.getInt(0);
}
return total;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu options from the res/menu/menu_catalog.xml file.
// This adds menu items to the app bar.
getMenuInflater().inflate(R.menu.menu_catalog, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
#Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
// Define a projection that specifies the columns from the table we care about.
String[] projection = {
BudgetEntry._ID,
BudgetEntry.COLUMN_DATE,
BudgetEntry.COLUMN_DESCRIPTION,
BudgetEntry.COLUMN_INCOME,
BudgetEntry.COLUMN_INCOME_CATEGORY,
BudgetEntry.COLUMN_EXPENSE,
BudgetEntry.COLUMN_STATUS};
// Where clause to only display income transactions //
String selection = "income >=0 AND expense ISNULL AND strftime('%m',date)=strftime('%m',date('now')) AND strftime('%Y',date)=strftime('%Y',date('now'))";
// This loader will execute the ContentProvider's query method on a background thread
return new CursorLoader(this, // Parent activity context
BudgetEntry.CONTENT_URI, // Provider content URI to query
projection, // Columns to include in the resulting Cursor //
selection, // Where selection clause /
null, // selection arguments //
BudgetEntry.COLUMN_DATE); // Default sort order //
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Update {#link IncomeCursorAdapter} with this new cursor containing updated transaction data
mCursorAdapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
// Callback called when the data needs to be deleted
mCursorAdapter.swapCursor(null);
}
}
I have looked at many different posts here and none have been helpful.
Please help!
for example, I want show name of the characters that family is "Heard" or "Carry" or everybody you want who to be saved in a database and saved that in an array list:
in one of a method of the MyDataBaseClass:
public Cursor showName(String family){
SQLiteDatabase db = this.getWritableDatabase();
Cursor data = db.rawQuery(" SELECT Name FROM "+TBL_NAME+ " WHERE Family==?" , new String[]{family});
return data;
}
and in main scope:
MyDataBaseClass db = new MyDataBaseClass();
Cursor res = db.showName("Heard");
if (res.getCount() == 0) {
//do nothing
} else {
ArrayList<String> list = new ArrayList<>();
while (res.moveToNext()) {
list.add(res.getString(0));
}
}
this answer may not exactly what you want to do but I hope to help you
You have not initialized mDbHelper in CMIncomeTransactionsActivity class, so initialize mDbHelper in onCreate and try.
I want to populate spinner from sqlite database. After I am retrieving the relevant data it showed junk values. Could you please help me to fix this. I will attach my codes here.
--java File--
public class AddNewMovieActivity extends AppCompatActivity {
private Spinner movieTypes;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_new_movie);
movieTypes = (Spinner) findViewById(R.id.spinMovieType);
loadSpinnerData();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_add_new_movie, menu);
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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private void loadSpinnerData() {
// database handler
DBHelper db = new DBHelper(this);
// Spinner Drop down elements
List<MovieType> lables = db.getAllMovieTypes();
// Creating adapter for spinner
ArrayAdapter<MovieType> dataAdapter = new ArrayAdapter<MovieType>(this,android.R.layout.simple_spinner_item,lables);
// Drop down layout style - list view with radio button
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// attaching data adapter to spinner
movieTypes.setAdapter(dataAdapter);
}
}
-- DBHelper--
public List<MovieType> getAllMovieTypes() {
SQLiteDatabase db = getReadableDatabase();
List<MovieType> lst = new ArrayList<MovieType>();
Cursor cursor = db.query(TABLE_MOVIE_TYPE, null, COLUMN_STATUS + "=?", new String[]{"A"}, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
while (!cursor.isAfterLast()){
String type = cursor.getString(1).toString();
MovieType movieType = new MovieType(type);
movieType.setTypeId(cursor.getInt(0));
lst.add(movieType);
cursor.moveToNext();
}
}
db.close();
return lst;
}
I just want to show the movie types from the database. Please help me. this code returns the object values. but I need the string value of it. I have tried to convert my object to string. but I couldn't find a proper way to fix it. Actually I am very new to Android. so please help me.
What you can do is to Override toString() method in your MovieType class
public class MovieType{
//Whatever fields you have here
//Override toString()
#Override
public String toString() {
return your_field_name;
/***put the field name which you want to show in spinner
Or
You can append multiple fileds
return field1 + field2+......;
***/
}
}
And your all set, you would then see the value of the field in your spinner, what you have set in toString() method.
You can make custom adapter or you can make your list of String type.
As you have mentioned that you just want to show movies type. You can do this in your getAllMovieTypes() function.
public List<String> getAllMovieTypes() {
SQLiteDatabase db = getReadableDatabase();
List<String> lst = new ArrayList<String>();
Cursor cursor = db.query(TABLE_MOVIE_TYPE, null, COLUMN_STATUS + "=?", new String[]{"A"}, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
while (!cursor.isAfterLast()){
String type = cursor.getString(1).toString();
lst.add(type);
cursor.moveToNext();
}
}
db.close();
return lst;
}
Now, you can display only type.
I have a SQLite database in my app for which I made a ContentProvider class.
I also have a RecyclerView into which I load an ArrayList of objects into its adapter to populate the RecyclerView.
Currently, when the activity starts I get a Cursor via my ContentProvider, loop through the Cursor to create an ArrayList of objects that I then set as part of my RecyclerView.Adapter.
All that works, but what I really want is for my RecyclerView to dynamically update as new data is loaded into the SQLite database via the content provider.
I have seen posts listing this library CursorRecyclerAdapter but I do not want to use it because you do not get the nice RecyclerView animations on insert/delete.
I was trying to somehow use the LoaderManager.LoaderCallbacks<Cursor> call back methods to get a cursor, convert to arraylist, then swap that in my RecyclerView adapter but couldn't figure it out.
Could someone please show me some example code on how to set it up in my Activity so that the RecyclerView will refresh when new data is written into the local database via a local content provider?
Here is what my RecyclerView.Adapter looks like:
public class MyAdapter extends RecyclerView.Adapter<AdapterTodoList.Holder> {
private List<TodoItem> itemList;
private Context mContext;
//data
String message;
Long datetime;
//this class takes a context and a list of the items you want to populate into the recycler view
public AdapterTodoList(Context context, List<TodoItem> itemList) {
this.itemList = itemList;
this.mContext = context;
}
#Override
public Holder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
//our xml showing how one row looks
View row = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recycler_view_todo_item, viewGroup, false);
Holder holder = new Holder(row);
return holder;
}
#Override
public void onBindViewHolder(Holder holder, final int position) {
holder.recyclerLinearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(mContext, "Recycle Click" + position, Toast.LENGTH_SHORT).show();
}
});
//get one item
TodoItem data = itemList.get(position);
Log.d("Test", "onBindViewHolder position " + position);
message = data.getMessage();
datetime = data.getDatetime();
//convert long to date
String dateString = new SimpleDateFormat("MM/dd/yyyy").format(new Date(datetime));
//set the holder
holder.messageTextView.setText(message);
}
#Override
public int getItemCount() {
return itemList.size();
}
public class Holder extends RecyclerView.ViewHolder {
protected ImageView checkBoxImageView;
protected TextView messageTextView;
protected LinearLayout recyclerLinearLayout;
public Holder(View view) {
super(view);
//checkBoxImageView = (ImageView) view.findViewById(R.id.checkBoxImageView);
messageTextView = (TextView) view.findViewById(R.id.messageTextView);
//the whole view
recyclerLinearLayout = (LinearLayout) view.findViewById(R.id.recyclerItemLinearLayout);
}
}
}
Here is what my Activity looks like so far:
public class HomeRec extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{
private Toolbar mToolbar;
//recyclerview and adapter
private RecyclerView mRecyclerView;
private MyAdapter adapter;
//the swipe refresh layout that wraps the recyclerview
private SwipeRefreshLayout mSwipeRefreshLayout;
//this will hold all of our results from our query.
List<TodoItem> itemList = new ArrayList<TodoItem>();
private Cursor mCursor;
//resources from layout
EditText toDoEditText;
Button cancelButton;
Button addButton;
//variables
private String message;
private long datetime;
//loader
private SimpleCursorAdapter mTodoAdapter;
private static final int TODO_LOADER = 0;
// These indices are tied to Projection. If Projection changes, these
// must change.
public static final int COL_ID = 0;
public static final int COL_MESSAGE = 1;
public static final int COL_DATETIME = 2;
public static final int COL_CHECKED = 3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_rec);
mToolbar = (Toolbar) findViewById(R.id.app_bar);
//set the Toolbar as ActionBar
setSupportActionBar(mToolbar);
// Initialize recycler view //
mRecyclerView = (RecyclerView) findViewById(R.id.todoRecyclerView);
mRecyclerView.hasFixedSize();
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//set a grey line divider for each item in recycler view
mRecyclerView.addItemDecoration(
new DividerItemDecoration(this, null, false, true));
// END Initialize recycler view //
//initiate the swipe to refresh layout
mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
// Refresh items
refreshItems();
}
void refreshItems() {
// Load items
// ...
// Load complete
onItemsLoadComplete();
}
void onItemsLoadComplete() {
// Update the adapter and notify data set changed
// ...
// Stop refresh animation
mSwipeRefreshLayout.setRefreshing(false);
}
});
//set colors for swipe to refresh
mSwipeRefreshLayout.setColorSchemeResources(
R.color.refresh_progress_2,
R.color.refresh_progress_3);
//fire my asynctask to get data for the first time
new MessagesAsyncTask().execute();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_home_rec, menu);
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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
//Not sure what to do here or how to make this work.
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
//Not sure what to do here or how to make this work.
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
//Not sure what to do here or how to make this work.
}
public class MessagesAsyncTask extends AsyncTask<Void, Void, List<TodoItem>> {
//the cursor for the query to content provider
private Cursor mCursor;
#Override
protected void onPreExecute() {
}
#Override
protected List<TodoItem> doInBackground(Void... params) {
// A "projection" defines the columns that will be returned for each row
String[] projection =
{
DataProvider.COL_ID, // Contract class constant for the COL_ID column name
DataProvider.COL_MESSAGE, // Contract class constant for the COL_MESSAGE column name
DataProvider.COL_DATETIME, // Contract class constant for the COL_DATETIME column name
DataProvider.COL_CHECKED // Contract class constant for the COL_CHECKED column name
};
// Defines a string to contain the selection clause
String selectionClause = null;
// An array to contain selection arguments
String[] selectionArgs = null;
// An ORDER BY clause, or null to get results in the default sort order
String sortOrder = DataProvider.COL_DATETIME + " DESC";
// Does a query against the table and returns a Cursor object
mCursor = getContentResolver().query(
DataProvider.CONTENT_URI_TODO, // The content URI of the Todo table
projection, // The columns to return for each row
selectionClause, // Either null, or the word the user entered
selectionArgs, // Either empty, or the string the user entered
sortOrder); // The sort order for the returned rows
// Some providers return null if an error occurs, others throw an exception
if (null == mCursor) {
// Insert code here to handle the error.
} else if (mCursor.getCount() < 1) {
// If the Cursor is empty, the provider found no matches
} else {
// Insert code here to do something with the results
}
//convert cursor to arraylist of objects
while (mCursor.moveToNext()) {
itemList.add(new TodoItem(mCursor.getInt(mCursor.getColumnIndex(DataProvider.COL_ID)),
mCursor.getString(mCursor.getColumnIndex(DataProvider.COL_MESSAGE)),
mCursor.getLong(mCursor.getColumnIndex(DataProvider.COL_DATETIME)),
mCursor.getInt(mCursor.getColumnIndex(DataProvider.COL_CHECKED))
));
}
mCursor.close();
return itemList;
}
#Override
protected void onPostExecute(List<TodoItem> itemList) {
if (!itemList.isEmpty()) {
adapter = new MyAdapter(HomeRec.this, itemList);
mRecyclerView.setAdapter(adapter);
} else {
Toast.makeText(getApplicationContext(), "No data to display", Toast.LENGTH_LONG).show();
}
}
}
}
I m not sure what you need but I think you should add this method To adapter and call once your data was pulled
public void swapItems(List< TodoItem > todolist){
this.mTodoList = todolist;
notifyDataSetChanged();
}
Hope this would help :D
from your question I assume that you are loading the data from the database and somewhere there is a code that is updating the database. And on every update you want to update your RecyclerView, If this is the case continue reading. I am not going to explain this completely but there are a lot of source that will explain you this.
Use BroadcastReciever : In the place where you are updating your database sendBroadcast(). And in the activity use the BroadcastReceiver
example and in the onReceive() function call load the data in your ArrayList and call the adapter.notifyDataSetChanged()
Instead of making new adapter each time in onPostExecute and set it to recyclerview again you can notify adapter after modifying list elements.
OR
If you want to make adapter using arraylist instead of cursoradapter using loader i have made sample for you with data provided by you. You can use this as a reference:
public class DataBaseActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private List itemList;
private MyAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_data_base);
RecyclerView recycle=(RecyclerView)findViewById(R.id.rv_data);
SwipeRefreshLayout swipeRefreshLayout= (SwipeRefreshLayout) findViewById(R.id.srl_data);
recycle.setLayoutManager(new LinearLayoutManager(this));
itemList=new ArrayList();
mAdapter= new MyAdapter(this, itemList);
recycle.setAdapter(mAdapter);
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
getContentResolver().notifyChange(DataProvider.CONTENT_URI_TODO, null); //if you are using content provider
//getSupportLoaderManager().restartLoader(100, null, DataBaseActivity.this); // if you are using support lib
//getLoaderManager().restartLoader(100, null, DataBaseActivity.this); //if you are not using support lib
}
});
// getLoaderManager().initLoader(100, null, this); //if you are not using support lib
getSupportLoaderManager().initLoader(100, null, this);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection =
{
DataProvider.COL_ID, // Contract class constant for the COL_ID column name
DataProvider.COL_MESSAGE, // Contract class constant for the COL_MESSAGE column name
DataProvider.COL_DATETIME, // Contract class constant for the COL_DATETIME column name
DataProvider.COL_CHECKED // Contract class constant for the COL_CHECKED column name
};
// Defines a string to contain the selection clause
String selectionClause = null;
// An array to contain selection arguments
String[] selectionArgs = null;
// An ORDER BY clause, or null to get results in the default sort order
String sortOrder = DataProvider.COL_DATETIME + " DESC";
return new CursorLoader(this,DataProvider.CONTENT_URI_TODO, // The content URI of the Todo table
projection, // The columns to return for each row
selectionClause, // Either null, or the word the user entered
selectionArgs, // Either empty, or the string the user entered
sortOrder);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
if(data!=null && data.getCount()>0)
{
itemList.clear();
while (data.moveToNext()) {
itemList.add(new TodoItem(data.getInt(data.getColumnIndex(DataProvider.COL_ID)),
data.getString(data.getColumnIndex(DataProvider.COL_MESSAGE)),
data.getLong(data.getColumnIndex(DataProvider.COL_DATETIME)),
data.getInt(data.getColumnIndex(DataProvider.COL_CHECKED))
));
}
}
else
Toast.makeText(getApplicationContext(), "No data to display", Toast.LENGTH_LONG).show();
if(data!=null)
data.close();
mAdapter.notifyDataSetChanged();
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
}
}
For "listening" to your ContentProvider changes, you'll could try to integrate ContentObserver into your ContentProvider, so it can trigger the necessary events when a transaction is done on your ContentProvider. After which, you'll declare an ContentObserver to your CONTENT_URI, then you can trigger an update to your RecyclerView.
More info on implementing ContentObserver here.
A sample code for updating an item in your RecyclerView would be,
public void update(T data){
synchronized (mLock){
if(data != null && mData.contains(data)){
int index = mData.indexOf(data);
mData.set(index, data);
notifyItemChanged(index);
}
}
}
Wherein T is the type of object if your row returns, mLock is just an instance object to acquire a lock, mData the list of items you've provided to your RecyclerView. You get the gist. :D
Hope it helps.
Refresh cursor every second
final Handler handler = new Handler();
final int delay = 1000; //milliseconds
handler.postDelayed(new Runnable(){
public void run(){
//Call cursor loader to refresh cursor
getSupportLoaderManager().restartLoader(LOADER_ID, null, MainActivity.this);
handler.postDelayed(this, delay);
}
}, delay);
I am writing a note taking app within android eclipse. My app currently selects all the notes from within the SQLite database and uses them to populate a ListView. This ListView is clickable, and currently redirects the user to the EditNote activity.
However, I would like to be able to populate the EditTexts within the EditNote activity based on the ID of the ListView note that is clicked.
(So that if I clicked the first ListView Item and it's ID was 2 then the value 2 would be passed through to EditNote)
This would require obtaining the ID of the ListView Item that was clicked, and then passing it through using .putExtra(); to the EditNote activity.
So my question is: how would I obtain the ID and then pass it through to the EditNote activity? So that I can then use the ID to make additional querys on that activity.
Thank you very much for your time.
Any additional questions I will answer to the best of my ability.
Initialising things
DatabaseHelper dbh;
ArrayList<String> listItems = new ArrayList<String>();
ArrayAdapter<String> adapter;
Context mCtx;
ListView lv;
onCreate method with onClickListeners
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
refreshData();
mCtx = this;
lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View view,
int position, long id) {
Intent i = new Intent(mCtx, EditNote.class);
i.putExtra("ID", listItems.get(position));
startActivity(i);
}
});
refreshData method (used to populate the ListView)
public void refreshData(){
dbh = new DatabaseHelper(this);
dbh.open();
adapter = new ArrayAdapter<String> (this, android.R.layout.simple_list_item_1, listItems);
setListAdapter(adapter);
ArrayList<String[]> searchResult = new ArrayList<String[]>();
//EditText searchTitle = (EditText) findViewById(R.id.searchC);
listItems.clear();
searchResult = dbh.fetchNotes("");
//searchResult = dbh.fetchNotes(searchTitle.getText().toString());
String title = "", note = "", id = "";
for (int count = 0 ; count < searchResult.size() ; count++) {
note = searchResult.get(count)[2];
title = searchResult.get(count)[1];
id = searchResult.get(count)[0];
listItems.add(title);
}
adapter.notifyDataSetChanged();
}
/*private void setID(String setID) {
this.id = setID;
}
private String getID(){
return id;
}*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
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 == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
DatabaseHelper activity - fetchNotes - used to query the database
public ArrayList<String[]> fetchNotes(String title) throws SQLException {
ArrayList<String[]> myArray = new ArrayList<String[]>();
int pointer = 0;
Cursor mCursor = mDb.query(TABLE_NAME, new String[] {"_id", "title",
"note"}, null, null,
null, null, "_id");
int idColumn = mCursor.getColumnIndex("_id");
int titleColumn = mCursor.getColumnIndex("title");
int noteColumn = mCursor.getColumnIndex("note");
if (mCursor != null){
//If possible move to the first record within the cursor
if (mCursor.moveToFirst()){
do {
//for each record add a new string array to our Array List
myArray.add(new String[3]);
//
myArray.get(pointer)[0] = mCursor.getString(idColumn);
//Save the note into the string array
myArray.get(pointer)[1] = mCursor.getString(titleColumn);
//Save the title into the string array
myArray.get(pointer)[2] = mCursor.getString(noteColumn);
//increment our pointer variable.
pointer++;
} while (mCursor.moveToNext()); // If possible move to the next record
} else {
myArray.add(new String[3]);
myArray.get(pointer)[0] = "";
myArray.get(pointer)[1] = "";
myArray.get(pointer)[2] = "";
}
}
return myArray;
}
Also here's my create table, just in case
private static final String DATABASE_CREATE =
"CREATE TABLE " + TABLE_NAME + " (" +
"_id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"title TEXT NOT NULL, " +
"note TEXT NOT NULL); ";
I will try to help you also i think your code can be more optimized ...
in your fetchNotes() just return the cursor instead of creating ArrayList if suppose you created ArrayList here and it occupies 100 entries again in the caller function you are using the listItems ArrayList... i know android has garbage collector but why to employ it if there is option to avoid ?
your myArray is String[] ArrayList but your listItems is not hence you can only access the titles coz this is wat you are storing here listItems.add(title);
a. So you can either use listItems directly in fetchNotes() like MainActivity.listitems (supposing listItem is declared in MainActivity class ) use after declaring ArrayList<String[]> listItems=new ArrayList<String[]>(); as public static ArrayList<String[]> listItems=new ArrayList<String[]>();
or
b. you can simply return the cursor only and do exactly like the myArray type of operation on listItems.
Now you can access the "id" by refering the index you stored the id in listItems.
listItems.get(position)[2] ( supposing you stored the id at index 2 ).
I tried to keep it as simple as possible and expect that it will help you ...
Not sure I understand this completely. Are you not passing the "title" already and your database helper can fetch results using "title"? Is this not working or do you want to optimize it by passing the ID? Even if you want to pass the ID, you can do that using the same mechanism.
I have a SQLite database that I am saving user selected data to. This data will be visible in a listview and if you long click on the data it will delete that item. This is working as I see the item disappear from the listview, but when I restart the application and all the listview items are brought back in from the database, everything that was deleted is coming back. I am using this statement:
public void deleteAlarmEntry(int pos){
Log.i("Deleting item from pos: ", String.valueOf(pos));
db.delete(MySQLHelper.TABLE_NAME, MySQLHelper.ID_COL + "='" + pos + "'", null);
}
I can see the statement being called in the logs. Is there a better way to make sure that the statement is executing correctly? Is something wrong here?
Here is my removeItem method called in the MainActivity on long click of the listview item:
public void removeItem(int position) {
alarmItemArray.remove(position);
dataSource.deleteAlarmEntry(position);
alarmAdapter.notifyDataSetChanged();
}
The dataSource.deleteAlarmEntry() calls the above database remove.
Also, on application startup I am bringing the entries into a temp arraylist and then parsing the time to get the adapter arraylist like so:
dataSource = new WeatherDataSource(this);
dataSource.open();
ArrayList<AlarmEntry> alarmEntries = (ArrayList<AlarmEntry>) dataSource.getAllWeatherEntries();
alarmItemArray = getTimeFromEntries(alarmEntries);
alarmAdapter = new ArrayAdapter<String>(this,
R.layout.activity_alarm_item, R.id.time, alarmItemArray);
lv = (MyListView) findViewById(R.id.listview);
lv.setAdapter(alarmAdapter);
Here is the database's getAllWeatherEntries:
public List<AlarmEntry> getAllWeatherEntries(){
List<AlarmEntry> weatherEntry = new ArrayList<AlarmEntry>();
Cursor cursor = db.query(MySQLHelper.TABLE_NAME, cols, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
AlarmEntry m = cursorToEntry(cursor);
weatherEntry.add(m);
Log.i("Get all weather entries", m.getTime());
cursor.moveToNext();
}
cursor.close();
return weatherEntry;
}
You're just passing everything from that item to your query.
In OnContextMenuItemSelected you will need to do something similar to the below; you will need to change the parameters of your deleteAlarmEntry to receive a string instead of an int.
#Override
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
String selectedID;
// adapter is the Adapter from creating the listview
selectedID = String.valueOf(adapter.getItemId(info.position));
deleteAlarmEntry(selectedID);
}
You will also need to modify the db.delete to return a number, ie int result = db.delete() per the function. http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
EDIT:
you may want to use OnItemLongClickListener instead of OnLongClickListener
http://developer.android.com/reference/android/widget/AdapterView.OnItemLongClickListener.html
lv.setOnItemLongClickListener(new OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
String id = String.valueOf(alarmAdapter.getItemId(position);
removeItem(id);
}
});
SECOND EDIT:
Try this for cursoradapter, i'd recommend using a simple cursor adapter:
http://developer.android.com/reference/android/widget/SimpleCursorAdapter.html
String[] from = new String[]{"time"}; //enter your time column name here
int[] to = new int[]{R.id.time};
Cursor cursor = db.query(MySQLHelper.TABLE_NAME, cols, null, null, null, null, null);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,R.layout.activity_alarm_item, cursor, from, to);
lv.setAdapter(adapter);
use,
public void deleteAlarmEntry(int pos) {
db.delete(MySQLHelper.TABLE_NAME, MySQLHelper.ID_COL + "=?", new String[]{pos + ""});
}