Android: Edittext- get current line - android

In an edittext is there a method for getting the current line of the cursor? If not I will write my own method, but just wanted to check. If I do write my own method would the best method be to go through every character in the edittext until selectionstart and count the number of \n's using a For loop, or is there a better way? Thanks!

Just to let people know:
There is a better way to do this then Doug Paul has suggested by using the getLineForOffset(selection):
public int getCurrentCursorLine(EditText editText)
{
int selectionStart = Selection.getSelectionStart(editText.getText());
Layout layout = editText.getLayout();
if (!(selectionStart == -1)) {
return layout.getLineForOffset(selectionStart);
}
return -1;
}

I can't find a simple way to get this information either, so your approach seems about right. Don't forget to check for the case where getSelectionStart() returns 0. You can make the code reusable by putting it in a static utility method, like this:
private int getCurrentCursorLine(Editable editable) {
int selectionStartPos = Selection.getSelectionStart(editable);
if (selectionStartPos < 0) {
// There is no selection, so return -1 like getSelectionStart() does when there is no seleciton.
return -1;
}
String preSelectionStartText = editable.toString().substring(0, selectionStartPos);
return countOccurrences(preSelectionStartText, '\n');
}
The countOccurrences() method is from this question, but you should use one of the better answers to that question (e.g. StringUtils.countMatches() from commons lang) if feasible.
I have a full working example that demonstrates this method, so let me know if you need more help.
Hope this helps!

find the last index of "\n"using method lastindex=String.lastindexof("\n") then get a substring using method String.substring(lstindex,string.length).and you will get the last line
in two lines of code.

Related

ArrayList Remove Object

I'm working on an app in android studio. The part of the app I'm having issues with is where the user can favourite and remove their favourite item. I do this by adding and removing the item from a list.
The thing is the add functionality works which is:
public void addFavorite(Context context, NewSubject subject) {
List<NewSubject> favorites = getFavorites(context);
if (favorites == null)
favorites = new ArrayList<NewSubject>();
favorites.add(subject);
saveFavorites(context, favorites);
}
I am passing in an object of type "NewSubject" which is just a class of getters and setters for name and id.
The problem arises when I try to remove an item from this list. Code below:
public void removeFavorite(Context context, NewSubject subject) {
ArrayList<NewSubject> favorites = getFavorites(context);
if (favorites != null) {
favorites.remove(subject);
saveFavorites(context, favorites);
}
}
I've even tried something like:
for(int i = 0; i < favorites.size(); i++){
if(favorites.get(i).getSubject_name() == subject.getSubject_name())
favorites.remove(i);
}
Even though both subject names match, the if statement never triggers as true. By changing it to ID it does remove the item but I was wondering why it doesn't work the other way. MeetTitan suggested to use "equals" operator to compare Strings and this has fixed that issue. But I'm still wondering as to why removing the item by "subject" without the FOR loop and IF statement doesn't work.
I have cleared the app's data multiple times whilst trying to debug the source of the problem.
Thank you for your time and help, it is much appreciated.
This applies if you are re-creating NewSubject twice... If you are trying to remove the exact same instance of NewSubject that you got from the collection, then I guessed wrong and this isn't the answer you are looking for.
Is it possible you haven't defined equals and hashCode in your Favorites object? Without those remove will only work with the EXACT same object instance in the collection. If you haven't, try defining them and see if remove() works the way you expect.
Without those methods defined, collections will respond this way:
Obj x=new Obj("data")
Obj y=new Obj("data")
collection.put(x)
collection.remove(y)
assert( collection.size() == 1) // was not removed because .equals didn't exist--remove reverted to == instead which failed, x != y
collection.remove(x)
assert( collection.size() == 0) // NOW it worked because you used the same instance.
if you define .equals and hashCode to compare the strings inside obj, then this will work:
collection.put(x)
collection.remove(y)
assert( collection.size() == 0) // worked because x.equals(y)!
Try
String.equalsIgnoreCase(value1,value2)
This might do your work.
From your example, it's evident that name is a String object. In java, you have to use ".equals()" or comparing two strings.
You can do this:
if(favorites.get(i).getSubject_name().equals(subject.getSubject_name())){
...
}
Or, you can override the equals() method in your NewSubject class to make this work:
favorites.remove(subject);
You can use something like this as your equals() method in the NewSubject class (considering you are only matching two NewSubject objects based on their names):
#Override
public boolean equals(Object other){
if (other == null) return false;
if (other == this) return true;
NewSubject otherSubject = (NewSubject) other;
if(this.getSubject_name().equals(otherSubject.getSubject_name()))
return true;
else
return false;
}
Update:
You may want to override hashcode() as well. If your NewSubject class ever gets used in a hash-based collection such as HashMap, overriding only equals() method will not be sufficient. For reference, this is from Effective Java by Joshua Bloch:
You must override hashCode() in every class that overrides equals().
Failure to do so will result in a violation of the general contract
for Object.hashCode(), which will prevent your class from functioning
properly in conjunction with all hash-based collections, including
HashMap, HashSet, and Hashtable.

Android validation is not a number from EditText

mail_xml is this:
EditText android:inputType="numberDecimal|numberSigned`
onTextChanged implemented on this and other edittexts and calls relative methods.
//and one method example:
if (editTextNumber.getText().toString().equals("") ||
editTextNumber.getText().toString().equals("-") ||
editTextNumber.getText().toString().equals(".")) {
//say its bad or reset interface so the user knows;
else {
//do stuff;
}
Should I create a class to do the validation and instantiate it, then use an if/else statement returning a boolean?
It's difficult because a - is valid as the user types, so is a .. But a . and - crashes. I'm thinking a class would be best?
I don't remember a function in java to do this, unless the api has been updated and I haven't seen it yet. I've created the classes i need and can instantiate them call their getter methods no problem. just stuck on the basic validation.
You can simply put the cast in a block try/catch...
This way if the text inserted is not a number, an exception is fired...
For exemple:
if(editTextNumber.getText()!=null && !editTextNumber.getText().toString().equals("")){
try{
// int value
Integer.parseInt(editTextNumber.getText().toString());
// double value
Double.parseDouble(editTextNumber.getText().toString());
}catch(Exception e){
//prints the exception that you got
//if number format exception then your input is not a number
e.printStackTrace();
}
}
Hope it helped...

Basics ---> Checking strings using if else to set value of an int, possible wrong use of onResume

So I'm still working on my first little app here, new to Android and Java, so I'm stuck on a basic little problem here. Answers to my first questions were really helpful, so after researching and not coming up with anything, I thought I'd ask for some more help!
The idea is that on another screen the user makes a choice A, B, C, or D, and that choices is passed as a string through the intent. OnResume checks if the choice is not null and sets an integer that corresponds to that string. Later when the user pushes another button, some if else logic checks that int and performs and action based on which was chosen. The problem is that the App crashed at onResume.
I learned that I have to use equals(string) to compare string reference, but maybe the problem is that I am trying to compare a string in reference to a literal string? Any help would be greatly appreciated.
Thanks!
protected void onResume() {
super.onResume();
// Get the message from the intent
Intent intent = getIntent();
String choice = intent
.getStringExtra(ExtensionSetupSlector.TORQUE_SETUP);
// Create the text view
TextView displayChoice = (TextView) findViewById(R.id.displayChoice);
if (!choice.equals("")){
displayChoice.setText(choice);
if (choice.equals("A")) {
myChoice = 1;
}
if (choice.equals("B")) {
myChoice = 2;
}
if (choice.equals("C")) {
myChoice = 3;
}
if (choice.equals("D")) {
myChoice = 4;
}
}
}
myChoice is declare right after ...extends Activity{ Also I'm not quite sure If this should really be in onResume, but it was working before I started try to set myChoice in the onResume (when I was just displaying the choice). Thanks again!
Change if (!choice.equals("")) to check for null instead. Otherwise your app attempts to access an empty reference and crashes.

Android ArrayList unpredictable behavior

I am experiencing a strange issue with ArrayList on Android
If I do this
for(int kk=0;kk<mReadRowIds.size();kk++)
{
if(mRealRowId==mReadRowIds.get(kk))
{
if(kk<mRowNumTimes.size())
{
mArrayNumberPortions.add(mRowNumTimes.get(kk));
bFoundIt=true;
break;
}
else
{
break;
}
}
}
The item is not found, but if I do this
int readrowidforcmp;
for(int kk=0;kk<mReadRowIds.size();kk++)
{
readrowidforcmp = mReadRowIds.get(kk);
if(mRealRowId==readrowidforcmp)
{
if(kk<mRowNumTimes.size())
{
mArrayNumberPortions.add(mRowNumTimes.get(kk));
bFoundIt=true;
break;
}
else
{
break;
}
}
}
The item is found , can someone explain what the difference between these is to me as I have not got a clue. NOTE: Array has to be over 200 items for it to go wrong.
It looks like maybe when you call the ArrayList's get(index) method, it's returning a generic object. In the first example, you're comparing an integer to that generic object, but in the second you're casting the generic object to an integer (by assignment) and then comparing them.
It looks like a typical auto-boxing issue. In your first solution, you wrote "mRealRowId==mReadRowIds.get(kk)". The value in the ArrayList is returned as an Integer and compared to an int auto-cast to an Integer. By comparing the values with == you are performing an identity comparison. The trick is that there is a cache of Integer values between -128 and 127, which is why your code starts breaking around 200.
A simple solution would be to make sure you use only ints and not Integers like in your second solution.

What does an EditText.getText() in android return if it is empty?

I've tried null and empty string, any other ideas?
No other possibility.
getText, infact, will never return null. It returns CharSequence whose contents may be empty.
Instead of doing getText().toString().equals("") or vice-versa, it may be faster to do getText().length() == 0
If it's empty, this will work:
if(mEditText.getText().toString().equals("")) {
// stuff to run when it's empty
}
Even if it's empty, getText() will still return an Editable, so if you were trying to do this:
if(mEditText.getText().equals("")) {
// stuff
}
It most certainly wasn't working.
You can use TextUtils.isEmpty( mEditText.getText().toString() ). It will return true if its empty/null.
The best way I found to check it is to stock the value in a var like:
String text = mEditText.getText().toString();
and then to use boolean operator isEmpty like:
if (text.isEmpty){
// stuff
}
After looking at several questions and since it's already possible to get a null I've found the answer to avoid a
method invocation toString may produce NPE
warning all over the place:
String theText = String.valueOf(mEditText.getText());

Categories

Resources