Here's a newbie to Android Developing.
While I'm making an app that calculate the calories burnt from exercise, I found that adding a TextWatcher to the EditText will cause crashing even I only add it on the "etEnergy".
I've searched many questions about crashed, but most of them are making a infinity loop in the listener and solved by remove the listener then add it back later. I added that but it doesn't work.
I found this message in Logcat when I can't find the log I made in the method:
Warning ActivityManager(744): Activity pause timeout for ActivityRecord{41ea1128 u0 [package name]/.MainActivity t65 f}
The following are the problem codes in MainActivity.java. Without them I can execute correctly but I need them to complete this app.
protected EditText etEnergy,etWeight,etTime;
protected TextView tvCals;
//double t,a; //don't make any sense in following code.
myTextWatch tw;
class myTextWatch implements 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) {
etEnergy.removeTextChangedListener(this);
etWeight.removeTextChangedListener(this);
etTime.removeTextChangedListener(this);
Log.d("TextWatcher","TextChangedListenerRemoved");
etEnergy.addTextChangedListener(this);
etWeight.addTextChangedListener(this);
etTime.addTextChangedListener(this);
}
#Override
public void afterTextChanged(Editable s) {
}
}//end of class myTextWatch
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etEnergy=(EditText) findViewById(R.id.etEnergy);
etWeight=(EditText) findViewById(R.id.etWeight);
etTime=(EditText) findViewById(R.id.etTime);
etEnergy.addTextChangedListener(tw);
etWeight.addTextChangedListener(tw);
etTime.addTextChangedListener(tw);
tvCals=(TextView) findViewById(R.id.tvCals);
}
Almost forgot to say that I'm using Android Studio 1.1.0 and app will be run on a physical device which is a HTC Butterfly that the Android version is 4.4.2 and the minimum API Level of the app is 14(IceCreamSandwich/4.0).
English is not my native language but I'll try hard to read any reply.
Thanks for your reading.
Also appreciates for your answering!
It seems that your EditText's are null. Please make sure that in activity_main layout you have EditText's with following ids: etEnergy, etWeight, etTime
And as a side note - you're not actually creating a new object of your myTextWatch and trying to pass null in addTextChangedListener(tw).
try this
protected EditText etEnergy,etWeight,etTime;
protected TextView tvCals;
//double t,a; //don't make any sense in following code.
TextWatch tw;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etEnergy=(EditText) findViewById(R.id.etEnergy);
etWeight=(EditText) findViewById(R.id.etWeight);
etTime=(EditText) findViewById(R.id.etTime);
etEnergy.addTextChangedListener(tw);
etWeight.addTextChangedListener(tw);
etTime.addTextChangedListener(tw);
tvCals=(TextView) findViewById(R.id.tvCals);
}
tw= 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) {
etEnergy.removeTextChangedListener(this);
etWeight.removeTextChangedListener(this);
etTime.removeTextChangedListener(this);
Log.d("TextWatcher","TextChangedListenerRemoved");
etEnergy.addTextChangedListener(this);
etWeight.addTextChangedListener(this);
etTime.addTextChangedListener(this);
}
#Override
public void afterTextChanged(Editable s) {
}
};//end of class myTextWatch
Related
I have an EditText where I need to hold its value in a MutableLiveData in a viewmodel.
Is it okay to be calling the method setValue("the changed edittext string") every time the user edits something in the EditText?
The reason why I'm doing this is to keep the data alive even if the user for example rotated the screen.
Is there any other way to achieve the same result? Cause I feel like it can be expensive and it's a bad practice calling the method over and over. here's an example in an activity:
public class NoteActivity extends AppCompatActivity {
private ActivityNoteBinding binding;
private NoteViewModel viewmodel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_note);
viewmodel = new ViewModelProvider(this).get(NoteViewModel.class);
addObservers();
addListeners();
}
private void addObservers() {
viewmodel.noteBodyLiveData.observe(this, s -> binding.noteBody.setText(s));
}
private void addListeners() {
binding.noteBody.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) {
viewmodel.noteBodyLiveData.setValue(String.valueOf(s));
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
The LiveData Objects are initialized with the data corresponding to what's in the database.
Thanks in advance!
I am working in an Android studio project. Here I want to implement one searching system. I have an edittext and an imagebutton. When user writers something in edittext and press imagebutton, system shows the relevant data from some database. This much I have covered.
Moreover, I want to implement a system where while user writes at least a specific length of letters (say 3) in edittext, the searching will start automatically. With more adding of letters the searching will be filtered accordingly. Is it possible to do this? Or something similar to this?
on searchview there is this syntax. just check the length of the text
public void onQueryTextChange(String query) {
if(query.length() >= 3) {
searchStarts();
}
}
or if you dont use search view just use textwatcher
textWatcher = 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) {
if (timer != null) {
timer.cancel();
}
}
#Override
public void afterTextChanged(Editable s) {
if(s.length() > 3){
searchStarts();
}
};
you have to add text watcher to your edit text. I will show you the solution with using debounce to avoid updating list all time user type a text.
So lets start with adding textWatcher to your edittext field:
searchField.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) {
//this one is for all letters, you can check the s length eg if(s.length() >= 3)
searchSubject.onNext(s.toString());
}
#Override
public void afterTextChanged(Editable s) {
}
});
This solution use rxjava if you do not want to do it just replace searchSubject with calling your search method.
So the fields:
private PublishSubject<String> searchSubject = PublishSubject.create();
private Subscription searchSubscription;
private String currentSearchPrefix = "";
And subscription (call this method onResume):
/**
* Subscribe to searchSubject to update list of items depends on given prefix.
* Debounce on changes 500 milliseconds
*/
private void subscribeSearch() {
searchSubscription = searchSubject
.debounce(500, TimeUnit.MILLISECONDS)
.onBackpressureLatest()
.subscribe(result -> {
currentSearchPrefix = result;
MainActivity.this.runOnUiThread(this::refreshList);
});
}
My method refreshList just update list by filter it using currentSearchprefix by one of field. Remember to unsubscribe searchSubscription onPause().
I want to know how can i update fragment recyclerview data of fragment when user change the City name.
Suppose I have one textview(which holds the city name) in my activity I'm sending the value of textview to fragment using intent, for the first time its works fine but when the value of textview changed the fragment recyclerview data wont update according to the textview value(i.e city name).
For better understanding I'm giving an example.
Suppose in my textview city name is set to MUMBAI for the first time the data is fetching perfectly fine from database to recyclerview but when the texview value changed to suppose Pune then the fragment recyclerview data wont get update according to city name.
The working is same as OLX fetching result according to city names.
thank you in advance and hope I explain properly.
I would add a textChangeListener to the textView in the activity, and create a method inside the fragment for receiving the data and updating the fragment.
Something like this perhaps:
Fragment frag = ...
tv.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) {
frag.updateSomething("some argument");
}
});
Create UpdateCallback interface:
interface UpdateCallback {
public void update(String s);
}
Implement update method on fragment:
class MyFragment Extends Fragment implements UpdateCallback {
#Override
public void update(String s){
...
}
}
Finally call method in afterTextChanged():
textView.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) {
myFragment.update(s);
}
});
I have an EditText and a TextWatcher. while testing in our test device we never found StackOverflowError, but once we published our app in Google Play Store, we are getting StackOverflowError issue for some user. Why this is happening, I go through some of link but not got the perfect answer. Is anything need to be done in my code.
Skeleton of my code:
weightEditText.addTextChangedListener(new TextWatcher()
{
#Override
public void onTextChanged(CharSequence s, int start, int before, int count){
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
m_currentWeight = weightEditText.getText().toString();
}
#Override
public void afterTextChanged(Editable s)
{
if(!weightEditText.getText().toString().equals("")) {
Pattern mPattern = Pattern.compile("^([1-9][0-9]{0,2}(\\.[0-9]{0,2}?)?)?$");
Matcher matcher = mPattern.matcher(s.toString());
if (!matcher.find()) {
weightEditText.setText(m_currentWeight);
weightEditText.setSelection(weightEditText.getText().length());
}
}
}
});
To avoid recursion here you need to unregister your textWatcher before setting the text and then reregister it.
Declare the TextWatcher outside the addTextChangedListener(...) method. Then you can do weightEditText.removeTextChangedListener(mWatcher) and weightEditText.addTextChangedListener(mWatcher)
You are trying to call setText() inside of the text watcher which will produce an infinite loop. You can use a flag variable to avoid this.
status variable is set as false by defaut.
status variable indicates whether the TextChange is made by App itself or by the user himself. if it is true, then the TextChange is made by App itself and vice versa.
Try this code. Cheers ! :)
public class MainActivity extends AppCompatActivity {
boolean status=false;//global variable
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
weightEditText.addTextChangedListener(new TextWatcher()
{
#Override
public void onTextChanged(CharSequence s, int start, int before, int count){
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
m_currentWeight = weightEditText.getText().toString();
}
#Override
public void afterTextChanged(Editable s)
{
if(status){
status=false;
return;
}else{
status=true;
if(!weightEditText.getText().toString().equals("")) {
Pattern mPattern = Pattern.compile("^([1-9][0-9]{0,2}(\\.[0-9]{0,2}?)?)?$");
Matcher matcher = mPattern.matcher(s.toString());
if (!matcher.find()) {
weightEditText.setText(m_currentWeight);
weightEditText.setSelection(weightEditText.getText().length());
}
}
}
}
});
}
}
I want to restrict the user to put more than 4 period(.) in a edit text.
how to do this. please any body help
Please make use of following code.
public class Help extends Activity {
public static int count = 0;//use this to check is there are more that 4 '.' char
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((EditText)findViewById(R.id.EditText01)).addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
if(count>=4){
//don't allow to right text
}
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
//check here if entered text contains more than 4 '.' character
}
#Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
}
Please check for logic i have not tested
Edittext e = (editText)Findviewbyid.....
String t= e.geteditable().gettext(); // check methods
if(s.equals(".") || s.equals("..") || s.equals("...")
{
throw some exception and reset it in the catch block
}
I could understand this from your question. is this what u wanted?
Following script counts all periods, but multiple periods are counted once: ... = ., and preriods at the beginning aren't counted.
String text = ((EditText)findViewById(R.id.yourEditText)).getText().toString();
if(text.matches("\\.*[^\\.]+\\.+[^\\.]+\\.+[^\\.]+\\.+[^\\.]+\\.+.+")){
// 4 or more '.', multiple '..' are counted once
}