I will like to know if we can continuously call some service for fetching results and displaying in Autocomplete list.
I have one screen with the text box and when user starts entering in that textbox the autocomplete should get filled with the data. The data will not be hardcoded and will be fetched through http connection. I think I need to call http connection in onTextChanged method of Edittext but is that the perfect solution.
Moreover, should this type of implementation done in mobile application. Since, this feature is web based. Can this be done in mobile application too?
Is this feasible?
Write a custom SimpleCursorAdapter. Now associate this adapter to your EditText. Here is the code to construct a Cursor object and return it:
public class ValueCursorAdapter extends SimpleCursorAdapter implements Filterable
{
...
// overrise the newView() to associate mCursor[1] and mCursor[2] to relevant views within
...
#Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint)
{
MatrixCursor mCursor = new MatrixCursor(new String[] { "_id", "uri", "label" });
.. // result = ??
while (result.hasNext())
{
mCursor.addRow(new Object[] { count, "uri", "title"});
count++;
}
return mCursor;
}
}
Here is an example for Customizing Cursor Adapter. You might need to customize it to fit your requirements.
Related
I have a RecyclerView with a FirebaseRecyclerAdapter. I want to populate the RecyclerView with a list of names when the user starts typing into the SearchView.
public class SchoolsAdapter extends FirebaseRecyclerAdapter<School, SchoolsAdapter.SchoolViewHolder> {
public SchoolsAdapter(Query ref) {
super(School.class, R.layout.item_school, SchoolViewHolder.class, ref);
}
#Override
public void populateViewHolder(SchoolViewHolder schoolViewHolder, School school, int position) {
schoolViewHolder.name.setText(school.getName());
schoolViewHolder.address.setText(school.getAddress());
}
static class SchoolViewHolder extends RecyclerView.ViewHolder {
public TextView name;
public TextView address;
public SchoolViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.school_item_tview_name);
address = (TextView) itemView.findViewById(R.id.school_item_tview_address);
}
}
}
I'm guessing I need to add a QueryTextListener to the searchview that would update the Query in the adapter. Would this break the FirebaseRecyclerAdapter?
Or should I
#Override
public boolean onQueryTextChange(String newText) {
mRecyclerView.setAdapter(new SchoolAdapter(ref.orderByChild("name").startAt(userQuery).endAt(userQuery+"~"))
return false;
}
whenever the user types something?
Also the docs talk about ordering and sorting firebase queries but don't explicitly say the best way to do string pattern matching. What's the best way to do string matching so that the recycler view shows all results which have the search query as a substring of the database record, and possibly those that are 1 edit distance away as well.
Also a way to ignorecase on queries?
I just finished doing something near to what you're looking for, I'm not sure it's the most elegant solution, but I'll throw out some ideas and if you think my idea will help I can definitely provide some examples.
Firstly, when I extended the base FirebaseAdapter I added a new filter named mFullList, since mItems of the FirebaseAdapter will be used for the display list, I don't want to keep going back to the network when I didn't have to. I then override all the methods in my child class to update mFullList with the values from the Firebase callbacks, sort them, filter them then call super.X() with the new list.
Quickly:
public reset(List)
mFullList = List
Collections.sort(mFullList, Comparator)
getFilter().filter(filterString)
The filterString is a field within the Adapter and is updated during the call to getFilter().filter(). During the perform filter I then loop through the mFullList and do a compare of:
mFullList.get(pos).getName().toLowerCase().contains(filterString.toLowerCase);
Once fitlering is done you have a new list that is passed to Filter.publishResults in the FilterResults object. publishResults calls a method in the class that performs the update and notify.
filterCompleted(List)
getItems().clear
getItems().addAll
notify
Essentially, I didn't want the FirebaseAdapater to stop getting the full list of items, I just wanted the users request to filter that full list and handle their request appropriately. Also, I didn't see a point to the added network requests based the user typing an extra character.
Using this method you can just use:
adapter.getFilter().filter("something")
to filter the list based on your updated field, and
adapter.getFilter().filter("")
to reset the full list (as long as your performFilter() handled it correctly. This way new updates from FireBase will be filtered based on the users selection, as well as when a user types in new values, won't require making new Firebase network requests.
I´m changing my application to use CursorLoader instead of startManagingCursor....
And I have one AutoCompleteTextView, SimpleCursorAdapter and in my setFilterQueryProvider implementation, in "runQuery" method I have
mProdutoAdapter.setFilterQueryProvider(new FilterQueryProvider() {
#Override
public Cursor runQuery(CharSequence constraint) {
Cursor cursor = mVendasDb.getProdutos(constraint.toString());
startManagingCursor(cursor);
return cursor;
}
});
How can I change this part to make it works with CursorLoader?
Should I discard setQueryFilterProvider and use TextWatcher in the AutocompleteTextView and then call getLoaderManager().restartLoader(0, bundleFilter, this)??? I have no idea how to proced!
bundleFilter would have the text came from textwatcher.
Is it ok using this aproach? Is it the best to do in this case?
This is a fine approach, according to the android developer website :
Restarting a Loader :
To discard your old data, you use restartLoader(). For example, this implementation of SearchView.OnQueryTextListener restarts the loader when the user's query changes. The loader needs to be restarted so that it can use the revised search filter to do a new query:
I have a database, a ListView, and a CustomCursorAdapter that extends CursorAdapter. A menu button adds an item to the database. I want the ListView to update and show this change. Normally it doesn't show this new item until i go to the homescreen and reopen the application.
I did eventually get it to work by calling cursor.requery() or mCustomCursorAdapter.changeCursor(newCursor) whenever I added a new item, but when I set autoRequery to false in the CursorAdapter constructor, it worked just the same. Why does it update correctly when autoRequery is set to false?
Am I using CursorAdapter correctly? What is the standard way of keeping the list updated with the database? And what does autoRequery do?
The idiomatic and imho correct way to automatically update Cursors is to call Cursor#setNotificationUri when they are created and before they are handed off to whatever requested them. Then call ContentResolver#notifyChange when anything in that Cursor's Uri's namespace changes.
For example, suppose you were creating a simple mail application and you wanted to update when new mail arrived but also provide various views on the mail. I'd have some basic Uri's defined.
content://org.example/all_mail
content://org.example/labels
content://org.example/messages
Now, say I wanted to get a cursor that gave me all mail and be updated when new mail arrives:
Cursor c;
//code to get data
c.setNotificationUri(getContentResolver(), Uri.parse("content://org.example/all_mail");
Now new mail arrives so I notify:
//Do stuff to store in database
getContentResolver().notifyChange(Uri.parse("content://org.example/all_mail", null);
I should also notify all the Cursors that selected for labels this new message met
for(String label : message.getLabels() {
getContentResolver().notifyChange(Uri.parse("content://org.example/lables/" + label, null);
}
And also, maybe a cursor is viewing that one specific message so notify them as well:
getContentResolver().notifyChange(Uri.parse("content://org.example/messages/" + message.getMessageId(), null);
The getContentResolver() calls happen where the data is accessed. So if it's in a Service or ContentProvider that is where you setNotificationUri and notifyChange. You should not be doing that from where the data is accessed, e.g., an Activity.
AlarmProvider is a simple ContentProvider that uses this method to update Cursors.
I created next method for ListView updating:
/**
* Method of refreshing Cursor, Adapter and ListView after database
* changing
*/
public void refreshListView() {
databaseCursor = db.getReadableDatabase().query(
CurrentTableName,
null,
null,
null,
null,
null,
"title"+SortingOrder);
databaseListAdapter = new DomainAdapter(this,
android.R.layout.simple_list_item_2,
databaseCursor,
new String[] {"title", "description"},
new int[] { android.R.id.text1, android.R.id.text2 });
databaseListAdapter.notifyDataSetChanged();
DomainView.setAdapter(databaseListAdapter);
}
end calls it each time after some changing in database
Right now, I'm running into issues trying to implement a FilterQueryProvider in my custom SimpleCursorAdapter, since I'm unsure of what to do in the FilterQueryProvider's runQuery function.
In other words, since the query that comprises my ListView basically gets the rowID, name, and a third column from my databases's table, I want to be able to filter the cursor based on the partial value of the name column.
However, I am uncertain of whether I can do this directly from runQuery without expanding my DB class since I want to filter the existing cursor, or will I have to create a new query function in my DB class that partially searches my name column, and if so, how would I go about creating the query statement while using the CharSequence constraint argument in runQuery?
I am also concerned about the performance issues associated with trying to run multiple queries based on partial text since the DB table in question has about 1300-1400 rows. In other words, would I run into a bottleneck trying to filter the cursor?
You need to run a query that will return a new filtered cursor:
public class MyActivity extends ListActivity implements FilterQueryProvider {
private Cursor cursor;
#Override
public Cursor runQuery(CharSequence constraint) {
if(cursor != null) {
cursor.close();
}
cursor = somehowGetAFilteredCursorFor(constraint);
startManagingCursor(cursor);
return cursor;
}
}
I have an Android ListActivity that is backed by a database Cursor through a SimpleCursorAdapter.
When the items are clicked, a flag field in the coresponding row in the database is toggled and the view in the list needs to be updated.
The problem is, when the view that's updated goes off screen and is recycled, the old value is displayed on the view when it returns into view. The same thing happens whenever thr list is redrawb (orientation changes, etc).
I use notifydatasetchanged() to refresh the cursor adapter but it seems ineffective.
How should I be updating the database so the cursor is updated as well?
Call requery() on the Cursor when you change data in the database that you want reflected in that Cursor (or things the Cursor populates, like a ListView via a CursorAdapter).
A Cursor is akin to an ODBC client-side cursor -- it holds all of the data represented by the query result. Hence, just because you change the data in the database, the Cursor will not know about those changes unless you refresh it via requery().
UPDATE: This whole question and set of answers should be deleted due to old age, but that's apparently impossible. Anyone seeking Android answers should bear in mind that the Android is a swiftly-moving target, and answers from 2009 are typically worse than are newer answers.
The current solution is to obtain a fresh Cursor and use either changeCursor() or swapCursor() on the CursorAdapter to affect a data change.
requery is now deprecated. from the documentation:
This method is deprecated.
Don't use this. Just request a new cursor, so you can do this asynchronously and update your list view once the new cursor comes back.
after obtaining a new cursor one can use theadapter.changeCursor(cursor). this should update the view.
In case of using loader and automagically generated cursor you can call:
getLoaderManager().restartLoader(0, null, this);
in your activity, just after changing something on a DB, to regenerate new cursor.
Don't forget to also have event handlers defined:
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
CursorLoader cursorLoader =
new CursorLoader(this,
YOUR_URI,
YOUR_PROJECTION, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
adapter.swapCursor(null);
}
I am not clear if you set the autoRequery property of CursorAdapter to true.
The adapter will check the autoRequery property; if it is false, then the cursor will not be changed.
requery() is already deprecated, just implement the simple updateUI() method like this in your CursorAdapter's child class and call it after data updates:
private void updateUI(){
swapCursor(dbHelper.getCursor());
notifyDataSetChanged();
}
It's easy.
private Db mDbAdapter;
private Cursor mCursor;
private SimpleCursorAdapter mCursorAd;
.....................................
//After removing the item from the DB, use this
.....................................
mCursor = mDbAdapter.getAllItems();
mCursorAd.swapCursor(mCursor);
Or use CursorLoader...