libPhoneNumber not giving correct US results on edittext - android

I am trying to create an edit text with a text watcher that displays the phone number correctly, to start out I am just testing it with a US number.
If I go to this site
http://libphonenumber.appspot.com/
And type in US and the number 9188143287 the results look perfect however when I implement the library as they say I am getting different results
Here is my fragment
ublic class PhoneNumberFragment extends Fragment{
private TextView next;
private EditText phoneNumber;
private PhoneNumberUtil phoneUtil;
private AsYouTypeFormatter formatter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_phone_number, container, false);
phoneUtil = PhoneNumberUtil.getInstance();
formatter = phoneUtil.getAsYouTypeFormatter("US");
init(v);
return v;
}
private void init(View v){
next = (TextView) v.findViewById(R.id.next);
phoneNumber = (EditText) v.findViewById(R.id.phoneNumber);
phoneNumber.addTextChangedListener(new PhoneNumberTextWatcher());
}
private void turnOnNext(){
next.setBackgroundResource(R.color.warningRed);
}
private class PhoneNumberTextWatcher implements TextWatcher{
private boolean isFormatting = false;
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO: implement your code
}
#Override
public void afterTextChanged(Editable s) {
// TODO: implement your code
}
#Override
public synchronized void onTextChanged(CharSequence s, int start, int before,
int count) {
if(before > count) {
return;
}
if(!isFormatting) {
isFormatting = true;
try {
formatter.clear();
for(int i=0; i<s.length();i++) {
phoneNumber.setText(formatter.inputDigit(s.charAt(i)));
phoneNumber.setSelection(phoneNumber.getText().length());
}
} catch (Exception e) {}
isFormatting = false;
}
}
}
}
My results are correct up to 7 digits, but then on the 8th digit the brackets are supposed to appear around the first 3 and they do not.
Thanks for any help!

Related

Android - How To retrieve EditText value from RecyclerView in MainActivity

How can I retrieve the value from all EditTexts created by the RecyclerView in MainActivity?
In my RecyclerView Adapter I'm extending my inner class:
public class MyPersonalAdapter extends RecyclerView.Adapter<MyPersonalAdapter.MyPersonalViewHolder>
I'm getting a reference to the EditText in that inner class:
class MyPersonalViewHolder extends RecyclerView.ViewHolder {
TextView numberTextView;
EditText nameEditText;
public MyPersonalViewHolder(View itemView) {
super(itemView);
numberTextView = (TextView) itemView.findViewById(R.id.tv_number);
nameEditText = (EditText) itemView.findViewById(R.id.et_name);
}
}
and in my MainActivity I want to use:
for (int i = 0; i < count; i++) {
String name = "Somehow get that name";
cv.put(MyContract.MyEntry.COLUMN_NAME, "name");
}
Got it working, here is the edited code:
mAdapter = new MyClassAdapter(this, mDataset.size);
mRecyclerView.setAdapter(mAdapter);
mRecyclerview.setItemViewCacheSize(mDataset.size());
List<ContentValues> list = new ArrayList<>();
for (int i = 0; i < mDataset.size(); i++) {
View view = recyclerView.getChildAt(i);
EditText nameEditText = (EditText) view.findViewById(R.id.et_name);
String name = nameEditText.getText().toString();
ContentValues cv = new ContentValues();
cv.put(MyContract.MyEntry.COLUMN_NAME, name);
list.add(cv)
}
// I encapsulated this in a try catch
for (ContentValues c:list) {
mDb.insert(MyClassContract.MyClassEntry.TABLE_NAME, null, c);
}
try this:
for(int i=0;i<adapter.getItemCount();i++){
MyPersonalViewHolder viewHolder= (MyPersonalViewHolder )
mRecyclerView.findViewHolderForAdapterPosition(i);
EditText editText=viewHolder.nameEditText;
}
Implement a addTextChangedListener inside bindview method in the recyclerview adapter.
everytime the edittext text is modified in any cell modify the arraylist string at that position.
And later when you need the whole arraylist, just send it back from the adapter class via any public getmethod.
This should be enough.
I created a getData function inside my Adapter class.
public String getData()
{
String s;
s=txt1.getText().toString();
return s;
}
Then in my MainActivity
public void onSave(View view) {
String[] s=new String[length];
for(int i=0;i<ad.getItemCount();i++)
{
s[i]=ad.getData().toString();
}
}
By this, you can save edit text entries in the array.
//So the other day I spend full day to get data(list of edittext) from recyclerview to activity when i press
button in activity
//perform onclick of button
Here is the code in adapter,Did't work with textchange listener..So i had to used textchange listener and setOnfoucusChange(100% working)
holder.mComment.setOnFocusChangeListener(new
View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
/* When focus is lost check that the text field
* has valid values.
*/
if (!hasFocus) {
String data=holder.mComment.getText().toString();
commentList[position]=data;
}
if(position==mList.size()-1){
holder.mComment.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence s, int i, int i1, int i2) {
commentList[position]=s.toString();
}
#Override
public void afterTextChanged(Editable editable) {
}
});
}
}
});
Intent intent = new Intent("mrn_intent");
Bundle args = new Bundle();
args.putSerializable("comment_list",(Serializable)commentList);
args.putSerializable("rating_list", (Serializable) mRatingList);
intent.putExtra("BUNDLE_COMMENT",args);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
And in activity write the following code
Bundle args2 = intent.getBundleExtra("BUNDLE_COMMENT");
if(args2!=null){
list = (String[]) args2.getSerializable("comment_list");
Log.d(TAG, "onReceive: list+++=>>>>>>"+list);
}
This worked for me:
mySetEnabled is a method I implemented within my viewHolder.
if(mRecView!=null) {
int size=mRecView.getChildCount();
for (int i = 0; i < size; i++) {
myAdapter.myViewHolder wordView = (myAdapter.myViewHolder)mRecView.findViewHolderForLayoutPosition(i);
if(wordView!=null)
wordView.mySetEnabled(state);
}
}
Try this way,
class MyPersonalViewHolder extends RecyclerView.ViewHolder {
TextView numberTextView;
EditText nameEditText;
public MyPersonalViewHolder(View itemView) {
super(itemView);
numberTextView = (TextView) itemView.findViewById(R.id.tv_number);
nameEditText = (EditText) itemView.findViewById(R.id.et_name);
nameEditText.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
values.add(getAdapterPosition(),s.toString());
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
}
Also, define a function
public String getValue(int position){
return values.get(position);
}
Now getValue can call from MainActivity.
OK. I had the same problem, but my solution was different and simpler. Basically, I'd a list of objects, and I was using the edittext to update their values. So, to do it correctly, instead of using position, I used a for loop and if I reach the object that have the same name of my textview, I break the loop and update using i as my index. You can see the code that I have been using in my adapter bellow:
int i;
for(i = 0; i<list.size(); i++){
if(list.get(i).getName().equals(holder.name.getText())){
break;
}
}
Commodity updated = list.get(i);
updated.setValor(Float.parseFloat(s.toString())); // recovering value of my edit text
list.set(i, updated);
atualizado[i] = Float.parseFloat(s.toString());

Use of different TextWatcher-implementations inside RecyclerView.Adapter

Currently I use a RecyclerView to represent a dynamically configuration list form.
Every configuration item (entry at RecyclerView list) contains one EditText item.
To avoid wrong user input (some fields allow only integer, others only one digit after comma), I've implemented two different TextWatcher-filters which correct illegal input ("DecimalFilterDigitsAfterComma" and "DecimalFilterInteger").
My RecyclerView has 16 configuration items in total, but can only display maximum 8 at one time.
My problem is that the TextWatchers are assigned to specific Items (Integers and Decimal-Point TextEdit). But when I'm scrolling a bit, they change their order, so that Decimal- and Integer-Filters get swapped.
The TextWatcher items will be created inside the ConfigurationAdapter which is a RecyclerView.Adapter. I've event managed that the TextWatcher is only created once for each entry by using the mListConfigInit which is a boolean flag list for the items.
ConfigurationAdapter.java:
public class ConfigurationAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
/*
...
*/
private List<ConfigItem> mConfiguration = new ArrayList<>();
// make sure that DecimalFilter is only created once for each item
private List<Boolean> mListConfigInit = new ArrayList<>();
public ConfigurationAdapter() {
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.listitem_configuration,
parent,
false);
final ConfigurationViewHolder vh = new ConfigurationViewHolder(v);
/*
...
*/
return vh;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final ConfigurationViewHolder vh = (ConfigurationViewHolder) holder;
ConfigItem config = mConfiguration.get(position);
if(config.ShowValueAsFloat()) {
vh.SetTextWatcherType(ConfigurationViewHolder.TextWatcherType.type_FloatActive);
} else {
vh.SetTextWatcherType(ConfigurationViewHolder.TextWatcherType.type_IntActive);
}
// set name and unit
vh.mName.setText(config.mName);
vh.mUnit.setText(config.mUnit);
/*
...
*/
}
#Override
public int getItemCount() {
return mConfiguration.size();
}
public void addConfigItem(ConfigItem item) {
mConfiguration.add(item);
mListConfigInit.add(new Boolean(false));
notifyItemInserted(mConfiguration.size() - 1);
//notifyDataSetChanged();
}
/*
...
*/
}
ConfigurationViewHolder.java (changed according to pskink-comments):
public final class ConfigurationViewHolder extends RecyclerView.ViewHolder implements TextWatcher {
public TextView mName;
public CheckBox mCheckbox;
public SeekBar mSeekbar;
public EditText mValueEditText;
public TextView mUnit;
private List<TextWatcher> mListTextWatchers = new ArrayList<>();
public enum TextWatcherType {
type_FloatActive(0),
type_IntActive(1);
private int mValue;
TextWatcherType(int value) {
mValue = value;
}
int val() { return mValue; }
}
private TextWatcherType mTextWatcherType = TextWatcherType.type_FloatActive;
public ConfigurationViewHolder(View itemView) {
super(itemView);
mName = (TextView) itemView.findViewById(R.id.textView_configuration_name);
mValueEditText = (EditText) itemView.findViewById(R.id.editText_configuration_value);
mUnit = (TextView) itemView.findViewById(R.id.textView_configuration_unit);
mCheckbox = (CheckBox) itemView.findViewById(R.id.checkbox_configuration);
mSeekbar = (SeekBar) itemView.findViewById(R.id.seekBar_configuration);
mListTextWatchers.add(0, new DecimalFilterDigitsAfterComma(mValueEditText, 1));
mListTextWatchers.add(1, new DecimalFilterInteger(mValueEditText));
mValueEditText.addTextChangedListener(this);
}
public void SetTextWatcherType(TextWatcherType textWatcherType) {
mTextWatcherType = textWatcherType;
}
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
#Override
public void afterTextChanged(Editable editable) {
mListTextWatchers.get(mTextWatcherType.val()).afterTextChanged(editable);
}
}
DecimalFilterInteger.java
public class DecimalFilterInteger implements TextWatcher {
private final static String TAG = ConfigurationAdapter.class.getSimpleName();
private final EditText mEditText;
private String mLastTextValue = new String("");
public DecimalFilterInteger(EditText editText) {
this.mEditText = editText;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public synchronized void afterTextChanged(final Editable text) {
String strInput = text.toString().trim();
if(strInput.isEmpty()) {
return;
}
if(strInput.equals(mLastTextValue)) { // return when same value as last time to avoid endless loop
return;
}
if ((strInput.charAt(0) == '.')) { // handle dot at beginning
strInput = "";
}
if(strInput.contains(".")){ // cut trailing comma
String numberBeforeDecimal = strInput.split("\\.")[0];
strInput = numberBeforeDecimal;
}
mEditText.removeTextChangedListener(this);
mEditText.getText().clear(); // do not use setText here to avoid changing the keyboard
mEditText.append(strInput); // back to default (e. g. from 123-mode to abc-mode),
// see: http://stackoverflow.com/questions/26365808/edittext-settext-changes-the-keyboard-type-to-default-from-123-to-abc
mLastTextValue = mEditText.getText().toString();
mEditText.setSelection(mEditText.getText().toString().trim().length());
mEditText.addTextChangedListener(this);
}
}
Many thanks in advance for your help!
The cause of the swap/switching behaviour of the two different TextWatcher-implementations inside the RecyclerView was that I called removeTextChangedListenerand addTextChangedListenerinside their afterTextChanged-methods to avoid retriggering of the afterTextChanged-method.
The best way to avoid retriggering is a simple check if the text changed since the last call:
public class DecimalFilterInteger implements TextWatcher {
private final static String TAG = ConfigurationAdapter.class.getSimpleName();
private final EditText mEditText;
private String mLastTextValue = new String("");
// ...
#Override
public synchronized void afterTextChanged(final Editable text) {
String strInput = text.toString().trim();
if(strInput.isEmpty()) {
return;
}
if(strInput.equals(mLastTextValue)) { // return when same value as last time to avoid endless loop
return;
}
if ((strInput.charAt(0) == '.')) { // handle dot at beginning
strInput = "";
}
if(strInput.contains(".")){ // cut trailing comma
String numberBeforeDecimal = strInput.split("\\.")[0];
strInput = numberBeforeDecimal;
}
//mEditText.removeTextChangedListener(this); // CAUSE OF SWAP-ERROR !!!
mEditText.getText().clear(); // do not use setText here to avoid changing the keyboard
mEditText.append(strInput); // back to default (e. g. from 123-mode to abc-mode),
// see: http://stackoverflow.com/questions/26365808/edittext-settext-changes-the-keyboard-type-to-default-from-123-to-abc
mLastTextValue = mEditText.getText().toString();
mEditText.setSelection(mEditText.getText().toString().trim().length());
//mEditText.addTextChangedListener(this); // CAUSE OF SWAP-ERROR !!!
}
}

Update activity's TextView from EditText value within ListView's item

So, I have an activity with a TextView and a ListView with a custom BaseAdapter. This activity looks like this:
As you can see, every item of the list is a custom layout and the basic idea is: every time the numeric EditText within it changes, the "total" TextView from the activity (which is the sum of the prices of every product) must be updated as well.
I suppose it must somehow be done from the Adapter class, but I don't know how to do it.
My Activity file looks like this (it gets products data from server via "GetCollectionProducts" AsyncTask, where I set the adapter):
public class ProductAisleActivity extends AppCompatActivity implements View.OnClickListener{
ListView productList;
Button participate;
ImageButton search;
EditText searchET;
TextView productsTotal;
Product[] colProducts;
RelativeLayout collectionHeader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_product_aisle);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
/* ...
Irrelevant code to this question
*/
productsTotal = (TextView) findViewById(R.id.products_aisle_total);
productsTotal.setText(
getResources().getString(
R.string.productsTotal,
String.valueOf(0.00)
)
);
productList = (ListView) findViewById(R.id.products_aisle_list);
new GetCollectionProducts().execute();
}
private class GetCollectionProducts extends AsyncTask<Void,Void,JSONArray>{
#Override
protected JSONArray doInBackground(Void... voids) {
/* Irrelevant code to this question */
}
#Override
protected void onPostExecute(JSONArray jsonArray) {
/* Irrelevant code to this question */
productList.setAdapter(
new CollectionProductsAdapter(
ProductAisleActivity.this,
colProducts
)
);
}
}
And my Adapter file looks as follows:
public class CollectionProductsAdapter extends BaseAdapter {
Context context;
ProductAisleActivity.Product[] data;
private static LayoutInflater inflater = null;
public CollectionProductsAdapter(Context context, ProductAisleActivity.Product[] data) {
this.context = context;
this.data = data;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return data.length;
}
#Override
public Object getItem(int i) {
return data[i];
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
View v = view;
if (v == null) {
v = inflater.inflate(R.layout.product_row_layout, null);
}
ProductAisleActivity.Product product = data[i];
/* ...
Irrelevant code to this question
*/
EditText productQuantity = (EditText) v.findViewById(R.id.productQuantity);
productQuantity.setText("0");
return v;
}
}
I'm stuck at this point, any help will be appreciated.
First you need to listen for any changes in the EditText so you can handle things dynamically without explicitly using something like a submit button. You can do this with a TextWatcher.
productQuanity.addTextChangedListener(new TextWatcher() {
private double originalCost = 0.0;
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Before we change the text, set the originalCost
// so we can know what the change is after the edit
originalCost = getCost(s.toString());
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// You don't need to utilize this method
}
#Override
public void afterTextChanged(Editable s) {
// After the change has taken place in the text,
// get the new cost and calculate the difference
double newCost = getCost(s.toString());
double changeInCost = newCost - originalCost;
}
private double getCost(String input){
String count = input.toString();
if(TextUtils.isEmpty(count))
return 0.0;
else
return (double) Integer.parseInt(count) * product.getPrice();
}
});
Now that we have the change in cost, what do we do with it? We need to notify the activity that we have a change. We can do that with an observer, which is fine, but for fun let's use an interface to implement a listener.
Modify your adapter class
public class CollectionProductsAdapter extends BaseAdapter {
public interface CostChangedListener{
void onCostChanged(double change);
}
Context context;
ProductAisleActivity.Product[] data;
private LayoutInflater inflater = null; // THIS SHOULDN'T BE STATIC
CostChangedListener listener;
public CollectionProductsAdapter(Context context, ProductAisleActivity.Product[] data, CostChangedListener listener) {
this.context = context;
this.data = data;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.listener = listener;
}
// The rest of your code
}
Now when we update the cost in our TextWatcher we can call
if(listener != null)
listener.onCostChanged(changeInCost);
Last, to make sure we utilize this correctly, we will need to pass a listener in our CollectionProductsAdapter constructor
productList.setAdapter(new CollectionProductsAdapter(
ProductAisleActivity.this, colProducts,
new CostChangeListener(){
#Override
public void onCostChanged(double change){
double currentTotal = Double.valueOf(productTotal.getText());
double newTotal = currentTotal + change;
productTotal.setText(String.valueOf(newTotal));
}));
Obviously you may need to tweak some of this to get it to match perfectly, and I haven't tested it so some things might be off a bit, but this should get you going in the right direction. If you have any issue feel free to comment and I will try to help you through it.
Notes
Do not keep a static reference like you were with your layout inflater
It is worth taking a look at the RecyclerView or at least the ViewHolder pattern with an Adapter
You want to add a textChangedListener for changing item values as user changes values in EditText.
You can use TextChangedListener here:
EditText myEditTextField = new EditText(this);
myEditTextField.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
#Override
public void afterTextChanged(Editable s) {
}
});
You can perform tasks according to your need. It has 3 methods:
1.beforeTextChanged
2.onTextChanged
3.afterTextChanged
So you can get your task done by the help of "afterTextChanged". You have to simply call your method of calculating price for no. of items when user enters a particular number.And it will show you the price as you want.
Hope this help!

editText validation and correction with TextWatcher

I'm very beginner to programming in android. Sorry if my question is obvious.
I have an editText with inputType="numberDecimal". I watch it's changes with TextWatcher, calculating from it's value (Double type), and show it on a TextView. The calculation is OK, except if the editText has the value ".". If the editText has the value ".", the program drops an error (force close).
My question is: how can I set the editText value to "0." with the use of addTextChangedListener if the editText gets the value "."? Have You got for this situacion a best practice? Thanks in advance for Your help.
My code is:
public class ConversionsFragment extends Fragment{
private EditText etDistBase;
private TextView tvMeterResult;
private TextView tvKmResult;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_conversions, container, false);
etDistBase = (EditText) rootView.findViewById(R.id.textEdit_conv_distance);
tvMeterResult = (TextView) rootView.findViewById(R.id.conv_dist_result_meter);
tvKmResult = (TextView) rootView.findViewById(R.id.conv_dist_result_km);
etDistBase.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){
}
public void onTextChanged(CharSequence s, int start, int before, int count){
calculateConvDistances();
}
});
return rootView;
}
private void calculateConvDistances() {
String baseText = etDistBase.getText().toString();
Double baseValue = 0.0,
meterResult = 0.0,
kmResult = 0.0;
// if (baseText == ".") {
// etDistBase.setText("0.");
// baseText = "0";
// }
if (baseText.length() == 0)
baseText = "0";
if (baseText != null) {
baseValue = Double.parseDouble(baseText);
meterResult = baseValue * 1000;
kmResult = baseValue;
} else {
meterResult = 0.0;
kmResult = 0.0;
}
tvMeterResult.setText(Double.toString(meterResult));
tvKmResult.setText(Double.toString(kmResult));
}
}
Try with this
if( editText.getText().toString().equals(".") ){
editText.setText("0.");
}
write into the afterTextChanged() method.
The working solution was to change the "." text to "0." in the afterTextChanged() method, as follows:
public class ConversionsFragment extends Fragment{
private EditText etDistBase;
private TextView tvMeterResult;
private TextView tvKmResult;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_conversions, container, false);
etDistBase = (EditText) rootView.findViewById(R.id.textEdit_conv_distance);
tvMeterResult = (TextView) rootView.findViewById(R.id.conv_dist_result_meter);
tvKmResult = (TextView) rootView.findViewById(R.id.conv_dist_result_km);
etDistBase.addTextChangedListener(new TextWatcher(){
public void afterTextChanged(Editable s) {
if (etDistBase.getText().toString().equals("."))
etDistBase.setText("0.");
etDistBase.setSelection(etDistBase.getText().length());
}
public void beforeTextChanged(CharSequence s, int start, int count, int after){
}
public void onTextChanged(CharSequence s, int start, int before, int count){
calculateConvDistances();
}
});
return rootView;
}
private void calculateConvDistances() {
String baseText = etDistBase.getText().toString();
Double baseValue = 0.0,
meterResult = 0.0,
kmResult = 0.0;
if (baseText.equals(".")) {
baseText = "0";
}
if (baseText.length() == 0)
baseText = "0";
if (baseText != null) {
baseValue = Double.parseDouble(baseText);
meterResult = baseValue * 1000;
kmResult = baseValue;
} else {
meterResult = 0.0;
kmResult = 0.0;
}
tvMeterResult.setText(Double.toString(meterResult));
tvKmResult.setText(Double.toString(kmResult));
}
}

How to clear text from an EditText when used with a TextWatcher

I have an EditText control on top of a ListView control in my layout. This layout is loaded into a Fragment derived class. I have also associated a TextWatcher interface with the EditText control so that each time text is entered into the EditText, the ListView filters the data based on the input text. The ListView's adapter implements Filterable behaviour by overriding GetFilter. The Fragment class that I am describing is part of a FragmentTabHost control which in turn loads 3 tabs at runtime.
Filtering the list based on what I enter in the EditText control works correctly. The issue I am facing is that when I click on some other Tab and then come back to my Tab which has this EditText with a TextWatcher, it is not clearing the previously entered text. I also notice that the filtered list is now empty. Once I manually remove the previous text from the EditText, the List re-appears with the old data.
Please let me know how to reset the filter and clear the text in the EditText control when I tab out of the current fragment. Basically I do not want the EditText control and the Filter to retain the old context each time I click on the Fragment. I have pasted sections of the code from the Fragment and List Adapter.
Thanks
Balaji
public class Favourites extends Fragment implements LoaderCallbacks<Cursor> {
ListView listView1;
ArrayList<FavouriteSearchResults> searchResults;
FavouritesBaseAdapter customAdapter;
private ProgressBar progressBar;
private EditText editText;
final int MENU_MAKE_CALL = 100;
final int MENU_SEND_MESSAGE = 101;
final int MENU_SEND_DIAL = 102;
final int MENU_COPY_CLIP = 103;
final int MENU_SEND_NUMBER = 104;
final int MENU_VIEW_CONTACT = 105;
private static final int LIST_ID = 1004;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setHasOptionsMenu(true); //Call this so that onCreateOptionsMenu is called
}
private class MyFocusChangeListener implements OnFocusChangeListener {
Context mContext;
public MyFocusChangeListener(Context context) {
mContext = context;
}
public void onFocusChange(View v, boolean hasFocus){
if(v.getId() == R.id.txtSearch && !hasFocus) {
InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.favourites, container, false);
editText = (EditText) v.findViewById(R.id.txtSearch);
OnFocusChangeListener ofcListener = new MyFocusChangeListener(getActivity());
editText.setOnFocusChangeListener(ofcListener);
editText.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
// When user changed the Text
customAdapter.getFilter().filter(cs);
}
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
});
#Override
public Filter getFilter() {
// TODO Auto-generated method stub
return new Filter() {
#Override
protected FilterResults performFiltering(CharSequence charSequence) {
FilterResults results = new FilterResults();
if(charSequence == null || charSequence.length() == 0) {
results.values = searchArrayList; //Return original list if search is cleared
results.count = searchArrayList.size();
}
else {
ArrayList<FavouriteSearchResults> tempResults = new ArrayList<FavouriteSearchResults>();
for(int i = 0;i < searchArrayList.size();i++) {
FavouriteSearchResults favResults = searchArrayList.get(i);
String sContactName = favResults.GetName();
String sId = favResults.GetId();
String searchChar = charSequence.toString();
if (sContactName.toLowerCase().contains(searchChar.toLowerCase())) {
FavouriteSearchResults newFavResults = new FavouriteSearchResults(sContactName);
newFavResults.SetId(sId);
tempResults.add(newFavResults);
}
}
results.values = tempResults;
results.count = tempResults.size();
}
return results;
}
#Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
//Set the filtered list into our copy list
searchFilteredArrayList = (ArrayList<FavouriteSearchResults>)filterResults.values;
notifyDataSetChanged();
}
};
First of all, I would point out that your getFilter() method is extremely not efficient. It creates new Filter every time user types/deletes a letter. This is quite stressful for the garbage collector. Instead, I would suggest creating Filter instance in your fragment and return this instance in getFilter() method.
Also, if you really want to clear edit text and reset filter - I would override onDestroyView method in your fragment implementation and do that stuff there.
#Override
public void onDestroyView() {
editText.setText("");
editText.setOnFocusChangeListener(null);
super.onDestroyView();
}
Also as you might know, anonymous classes indirectly store reference to the parent class, so just to be safe and avoid weird circular dependencies preventing your fragment of being GCed, I would suggest declaring your anonymous classes (TextWatcher and Filter) as public static classes:
public static class MyTextWatcher implements TextWatcher
{
public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
// When user changed the Text
//you might need to pass this adapter as a constructor parameter
customAdapter.getFilter().filter(cs);
}
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
public void afterTextChanged(Editable arg0) {
// TODO Auto-generated method stub
}
}
public static class MyFilter extends Filter
{
#Override
protected FilterResults performFiltering(CharSequence constraint) {
//you implementation
}
#Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
//you implementation
}
}
And then just instantiate those instances:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
.......
editText.addTextChangedListener(new MyTextWatcher());
.......
}
and
#Override
public Filter getFilter() {
if(filter == null)
{
filter = new MyFilter();
}
return filter;
}
Also, I've seen some memory leak issues related to EditText views. You might consider checking this post

Categories

Resources