Folks.
I've designed a currency exchange application in which i got all exchange rates once at application start and create own SQLite DB then easily pull them into the converter interface. I've designed the change to be done in my Edittext onTextChanged listener with a textwatcher and all works perfectly. I've also have a listview in the same activity for Favorite exchange rates and its also has to be calculated every time the edittext changes. My main problem is that I've got a slow performance and freeze issues in my application. I've tried to implement Asynctask to process the calculations but it didn't help me and i still get the performance issues. Hereunder my code for your reference. Please Advice !!
Text Watcher :
valval.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void afterTextChanged(final Editable s)
{
Calculate();
}
});
Calculate :
private void Calculate()
{
curs = mDb.query(MyDbHelper.TABLE_NAME, columns, MyDbHelper.COL_Common
+ "=" + "?", new String[] { From[xxxto] + From[xxxfrom] },
null, null, null);
cursD = mDb.query(MyDbHelper.TABLE_NAME, columns, MyDbHelper.COL_Common
+ "=" + "?", new String[] { From[xxxfrom] + From[xxxto] },
null, null, null);
curs.moveToFirst();
cursD.moveToFirst();
double selection = curs.getDouble(curs
.getColumnIndex(MyDbHelper.COL_Currone));
double selection2 = cursD.getDouble(cursD
.getColumnIndex(MyDbHelper.COL_Currone));
Long myNum = Long.parseLong(valval.getText().toString().trim());
double myNum3 = Double.parseDouble(new DecimalFormat("#.######").format(myNum * selection2));
valval2.setText(String.valueOf(myNum3));
Cursor B = mDb.query(MyDbHelper.TABLE_NAME, columns,
MyDbHelper.COL_CurrFavor + " LIKE ? And "
+ MyDbHelper.COL_Currsecond + " LIKE ?", new String[] {
"YES", "EUR" }, null, null, null);
for (int s = 0; s < B.getCount() - 1; s++)
{
B.moveToPosition(s);
String ZVZV = B.getString(0);
int BSBS = B.getInt(9);
Cursor curcur = mDb.query(MyDbHelper.TABLE_NAME, columns, MyDbHelper.COL_Common
+ "=" + "?", new String[] { From[xxxfrom] + From[BSBS-1] },
null, null, null);
curcur.moveToFirst();
double calcal = curcur.getDouble(6);
ContentValues args = new ContentValues();
double formattedNumber = Double.parseDouble(new DecimalFormat("#.######").format(myNum * calcal));
args.put(MyDbHelper.COL_Currsum,formattedNumber );
mDb.update(MyDbHelper.TABLE_NAME, args, "_id =" + ZVZV, null);
}
cursm.requery();
}
What I can imagine of from your description is, you're most likely having 2 EditTexts, where user only input to first, and you will sync the converted value for second, is this true? If it is, may I suggest you not to perform the operation right after every text change?
You may want to do Calculate() only after user finishes his input, perhaps one second delay of calculation is acceptable?
// Declare these as class variable
private Handler handler = new Handler();
private Runnable calculateRunnable = new Runnable() {
public void run() {
Calculate();
}
}
As for your TextWatcher, change this
public void afterTextChanged(final Editable s) {
handler.removeCallbacks(calculateRunnable);
handler.postDelayed(calculateRunnable, 1000);
}
Related
I am using a AutoCompleteTextView (will later be changing this to an editText but one problem at a time) to filter the results of my listView implementing a textWatcher:
fqp = new FilterQueryProvider() {
#Override
public Cursor runQuery(CharSequence constraint) {
String itemName = constraint.toString();
return getSearch(itemName);
}
};
Cursor getSearch(String itemName) {
String searchSelect = "(" + MediaStore.Audio.Media.TITLE + " LIKE ? )";
String[] selectArgs = { "%" + itemName + "%"};
Cursor searchCursor = getContentResolver().query(
queryUri,
projection,
searchSelect,
selectArgs,
MediaStore.Audio.Media.TITLE + " ASC"
);
return searchCursor;
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
String empty = "";
if(s.toString() == empty){
adapter.changeCursor(getAll());
adapter.notifyDataSetChanged();
}else{
adapter.getFilter().filter(s.toString());
adapter.notifyDataSetChanged();
}
}
This filter works just fine, but i need to figure out a way to reset my list once my autoCompleteTextView is empty. Surely there is a correct way to do this other than testing if it's empty but that's what i tried to no avail. Also should i just create two Cursors: one containing my full list and the other my filtered list so i don't have to re-query the content provider?
The issue seems to lie in this line
if(s.toString() == empty)
In Java, you cannot compare Strings like this, you need to use
if(s.toString().equals(empty))
Also TextWatcher is not getting called because the listener is not linked to your AutoCompleteTextView.
Also should i just create two Cursors: one containing my full list and the other my filtered list so i don't have to re-query the content provider?
If the filtered list will have the same data every time, then yes it's better to keep a reference to it instead of doing a new query.
Example using EditText:
adapter.setFilterQueryProvider(fqp);
search.addTextChangedListener(watch);
fqp = new FilterQueryProvider() {
#Override
public Cursor runQuery(CharSequence constraint) {
String itemName = constraint.toString();
return getSearch(itemName);
}
};
Cursor cursor = getContentResolver().query(
queryUri,
projection,
null,
null,
MediaStore.Audio.Media.TITLE+" ASC"
);
Cursor getSearch(String itemName) {
String searchSelect = "(" + MediaStore.Audio.Media.TITLE + " LIKE ? )";
String[] selectArgs = { "%" + itemName + "%"};
Cursor searchCursor = getContentResolver().query(
queryUri,
projection,
searchSelect,
selectArgs,
MediaStore.Audio.Media.TITLE + " ASC"
);
return searchCursor;
}
TextWatcher watch = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
String empty = "";
if (s.toString().equals(empty)) {
adapter.changeCursor(cursor);
adapter.notifyDataSetChanged();
} else {
adapter.getFilter().filter(s.toString());
adapter.notifyDataSetChanged();
}
}
#Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
};
I have created a database in sqlite for android with variables like Acc No, name, date etc etc.
i have many edit text in my activity. when the acc no is entered in Acc No edit text, the corresponding name should appear in below Name edit text. how to do that.
my DB code is given below
public void getName(Editable account_edit_txt){
"Acc_No " + account_edit_txt, null, null, null, null);
Cursor cursor = db.query(DATABASE_TABLE, new String[] {"Cust_Name","Acc_No"}, "Acc_No=?",new String[]{"account_edit_txt"}, null, null, null);
Log.e("running", "cursor run");
if(cursor!=null)
{
Log.e("running", "curosr is not null");
while(cursor.isFirst())
{
Log.e("running", "cursor while loop enter");
String temp = (cursor.getString(cursor.getColumnIndex("Cust_Name")));
String temp2 =(cursor.getString(cursor.getColumnIndex("Acc_No")));
Log.e("running", "id acc num" +temp+ " name"+temp2);
}
}
Activity code is given below
public class TransactionActivity extends Activity {
EditText acc_edit;
TextView acc_txt;
Editable account_edit_txt;
Connection connection;
String name;
SQLiteDatabase sdb;
AccountDBAdapter db = new AccountDBAdapter(this);
//
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.transaction_page);
acc_edit = (EditText) findViewById(R.id.edittext_Acc_No);
acc_txt = (TextView) findViewById(R.id.text_show_name);
final String editable = String.valueOf(acc_edit.getText());
Log.e("editable value", "" + account_edit_txt);
acc_edit.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int count,
int after) {
if (start >= 2) {
db.open();
account_edit_txt = acc_edit.getText();
db.getName(account_edit_txt);
db.close();
}
}
#Override
public void beforeTextChanged(CharSequence arg0, int arg1,
int arg2, int arg3) {
}
#Override
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
});
}
}
Below function will help you to retrieve account holder name for given account number.
Non need to fecth Acc_No again. Ad you are already have account number which user has inserted.
Also assuming that there will be only one record associated with the give account number.
public String getAccountHolderName(String accountNumber) {
String accountHolderName = null;
Cursor cursor = db.query(DATABASE_TABLE, new String[] { "Cust_Name" },
"Acc_No=?", new String[] { accountNumber }, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
accountHolderName = (cursor.getString(cursor
.getColumnIndex("Cust_Name")));
cursor.close();
}
return accountHolderName;
}
I have a simple ListActivity that uses the SimpleCursorAdapter. I allow users to change one of the values using an EditText. I perform simple validation to make sure that the number entered is less than 100. If the user entered value fails validation, I want to put the old value back.
I've tried a few different ways. My current approach is to requery it out of the database, but this isn't working. I'm always getting the value associated with the last entry in the ListActivity, regardless of which one was actually changed. I noticed in LogCat that onTextChanged and afterTextChanged are firing multiple times for each row in the ListActivity and not just the one that changed.
Here's the code:
public class MySimpleCursorAdapter extends SimpleCursorAdapter {
Context lcontext;
boolean changed;
String lastval;
private PortfolioData pfdata;
public MySimpleCursorAdapter(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
lcontext = context;
}
#Override
public View getView(final int pos, View v, ViewGroup parent) {
v = super.getView(pos, v, parent);
final EditText et = (EditText) v.findViewById(R.id.classpercentage);
final TextView tv = (TextView) v.findViewById(R.id._id);
et.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
Log.d("TEST", "In afterTextChanged s=" + s.toString() + " "
+ tv.getText() + " POS = " + Integer.toString(pos));
lastval = tv.getText().toString();
if (changed == true) {
String enteredValue = s.toString();
if (checkNullValues(enteredValue)) {
if (Float.parseFloat(enteredValue.trim()) > 100.0f) {
AlertDialog.Builder builder = new AlertDialog.Builder(
lcontext);
builder.setMessage("Percentage Value should be Less than 100");
builder.setPositiveButton("Ok",
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface arg0, int arg1) {
String sql = "select c.percentage as PERCENTAGE " +
"from asset_classes c WHERE c._id = " + lastval + ";";
pfdata = new PortfolioData(lcontext);
SQLiteDatabase db = pfdata.getReadableDatabase();
Cursor cursor = db.rawQuery(sql, null);
if (cursor != null)
{
cursor.moveToFirst();
et.setText(cursor.getString(0));
}
cursor.close();
pfdata.close();
}
});
// End of the Alert
if (changed == true)
{
builder.show();
}
}
}
changed = false;
}
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// Log.d("TEST", "In beforeTextChanged start=" +
// Integer.toString(start) +" count="+ Integer.toString(count) +
// " after=" + Integer.toString(after) + " s=" + s + " " + tv);
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
Log.d("TEST", "In onTextChanged start=" +
Integer.toString(start) + " count=" + Integer.toString(count)
+ " before=" + Integer.toString(before) + " s=" + s + " " +
tv);
changed = true;
}
});
return v;
}
}
I would really appreciate a fresh perspective on this. As always, thanks in advance.
Try to use an onFocusChangeListener. When it gets focus, save the current text into field of the class.
Something like:
String oldText - Would be your old text field.
Then you do:
et.setOnFocusChangeListener(new OnFocusChangeListener()) {
#Override
public void onFocusChange(View whatever, boolean hasFocus) {
if (hasFocus) {
//code
} else {
//code or maybe empty
}
}
}
Then if the number is > 100 you just get the oldText value and put in the EditText.
I think you're not aware of recycling in ListView. Having 1000 rows in Cursor there is only 10-20 (depends on screen size) row views created.
Don't store data in view!
At beggining I recommend you to read http://commonsware.com/Android/excerpt.pdf
I want to ask a little question. I want to know which is the best way I can filter my list view which I am populating from sqlite database and I want to filter it depending on users entered letters in edit text. I'm not showing any code because I have only sqlite statements and that's it. I have to change the sqlite statement which I'm using to populate the database.
So my question is, how can I change my sqlite statement when user entered letters in edit text, and how can I update my listview with the new data filtered with the new sql statement.
I had the same issue and solved it as follows:
//Search text and changed handler
EditText tbSearch = (EditText)findViewById(R.id.android_searchbox);
tbSearch.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void afterTextChanged(Editable s) {
ListView av = getListView();
SimpleCursorAdapter filterAdapter = (SimpleCursorAdapter)av.getAdapter();
filterAdapter.getFilter().filter(s.toString());
}
});
entries.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
return mDbHelper.fetchAllEntries(constraint);
}
});
With this approach you will need a method similar to FetchAllEntries(string sFilter)
/*
* Override to return a Cursor over the list of Entries filtered by a
* constraint
*
* #return Cursor over filtered Entries
*/
public Cursor fetchAllEntries(CharSequence constraint) {
if (constraint == null || constraint.length() == 0) {
// Return the full list
return fetchAllEntries();
} else {
String value = "%" + constraint.toString() + "%";
String[] columns = new String[] { KEY_ROWID, KEY_TITLE,
KEY_BODY, KEY_USER_PROFICIENCY };
return mDb.query(DATABASE_TABLE, columns,
KEY_TITLE + " like ? OR " + KEY_BODY + " like ? ", new String[] { value, value }, null, null,
KEY_TITLE + " ASC ");
}
}
Here I have a table with two columns (title, body)
Check the answer to your previous question, they are very similar : search bar
I'm trying to remove a couple of rows in a sqlite database programmatically for android and am wondering what the whereArgs are referring to in this documentation:
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#delete(java.lang.String,%20java.lang.String,%20java.lang.String[])
Can someone give me an example?
whereArgs are the values to the where clause. When you use the "?" (placeholder) in the second argument (whereClause), you've to provide the whereArgs. See this post for details.
Put "=?" on the end of the second argument (whereClause), like this:
delete(CONTENT_URI, TEXT + "=?", new String [] { text } );
The number of ? is the number of arguments.
Placeholders ? don't work (buggy) - so you need to construct the whereClause (selection) and send null arguments (selectionArgs)
e.g. To load a dynamic list from using user search text:
mCustomerMenuList = (ListView)findViewById(R.id.customer_menu_list);
mSearchText = (EditText)findViewById(R.id.autoCompleteTextView1);
mSearchText.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable t) {
//Reload the query using the search text
ManageMyCustomerMenuList();
mCustomerMenuList.setAdapter(mAdapter);
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// Auto-generated method stub
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
// Auto-generated method stub
}
});
and in your ManageMyCustomerMenuList() query code place something like:
String s = mSearchText.getText().toString().toLowerCase();
String whereClause = Browser.BookmarkColumns.TITLE+" LIKE ?";
String whereArgs [] = new String[] {"%" +s+"%"};
mCustomerCursor = managedQuery(android.provider.Browser.BOOKMARKS_URI,
new String[] {
Browser.BookmarkColumns._ID,
Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL
}, whereClause, whereArgs, mSqlLimit
);
mAdapter = new SimpleCursorAdapter(this, R.layout.row_layout_test,
mCustomerCursor, new String[] {
Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL
}, new int[] {
R.id.test_layout_view1,
R.id.test_layout_view2
}
);