Why does adapter.add() create an infinite loop and crash? - java

I'm making an Android app and my implementation of adapter.add() seems to crash the app. I had to use Log tags to find that my code strangely becomes stuck in a loop. Here's the code:
int i =0;
if(cards.size()>0){
Log.i("KOOL","Checked arraylist size =" + cards.size());
while(i < cards.size()){
Log.i("KOOL","Inside while loop");
adapter.add(cards.get(i));
i++;
}
Log.i("KOOL","Added data to adapter");
adapter.notifyDataSetChanged();
Log.i("KOOL","Finished OnActivityResult");
}
The app gets up to the Log tag "Inside while loop" and repeats it until the app crashes. I know that cards.size() is 2 right before the while loop so i see no reason for the app to crash. Am I using the adapter correctly? Please help!

Your question is missing some context. Luckily I know that your adapter is of type ArrayAdapter and its being initialized with cards. When your loop starts, cards.size() is 2. But then you add something to it, making cards.size() be 3. And then... I guess you get the point. You either add something to your adapter/list pair through the adapters add, or through your list add. If you add it to both, then you are adding it two times.
Here is the code for ArrayAdapter::add:
public void add(T object) {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.add(object);
} else {
mObjects.add(object);
}
}
if (mNotifyOnChange) notifyDataSetChanged();
}
where mOriginalValues is the very same list you used to construct the adapter. mObjects is a filtered version of them.

Related

Why is notifyDataSetChanged() working like that?

I have the following situation:
In my MatchActivity there is a method called executeBustConsequences() which is updating attributes that are included in lists that are the base of my custom RecyclerView.Adapter MatchRecyclerViewAdapter.
After updating the values executeBustConsequences() looks like that:
updateAverages(playerDarts, playerPoints, playerAverage);
// reset boolean, update match view and go to next player
resetMultiplier();
getAdapter().notifyDataSetChanged();
nextPlayer();
Right before getAdapter().notifyDataSetChanged() is executed, getCurrentDart() == 2 and getPlayerIndex() == 0.
Inside the adapter then I see the following attribute values:
getCurrentDart() == 1 and getPlayerIndex() == 1.
At first I didn't understand why that happened, but now I think I do.
This is the method nextPlayer():
private void nextPlayer() {
if (getPlayerIndex() == getMatchParticipants().size()-1) {
setPlayerIndex(0);
} else {
setPlayerIndex(getPlayerIndex() + 1);
}
setCurrentDart(1);
}
To me it looks like nextPlayer() was executed before notifyDataSetChanged() even though nextPlayer() should be executed after notifyDataSetChanged().
Can anybody explain to me why that is the case? Am I missing something obvious?

Finding duplicates in an ArrayList(JFrame)

I'm trying to do a swing application which adds names to an ArrayList and then displays it in Jcombobox.I already did the window and everything but I can't seem to get the hang off detecting duplicate names.
I tried
btnnext.addActionListener(new ActionListener() {
Override
public void actionPerformed(ActionEvent e) {
if(checkDuplicate(names)==true)
{
names.add(txtname.getText());
txtname.setText("");
}
else {
JOptionPane.showMessageDialog(null,"DUPLICATE! do not add");
}
}
});
public static boolean checkDuplicate(ArrayList<String> list) {
HashSet set = new HashSet();
for (int i = 0; i < list.size(); i++) {
boolean val = set.add(list.get(i));
if (val == false) {
return val;
}
}
return true;
}
It only says that I have duplicate when I already add it to the ArrayList and when I get the message I can't add anything else.
input example:
test
test
and then it stops accepting new Strings and only displays the message DUPLICATE! do not add
As I said in my comment:
This happens because you are basically creating a Set view of your ArrayList every time you call checkDuplicate rather than comparing the item you're trying to add with the existing list. In other words your checkDuplicate is written such that it only returns true when a duplicate already exists within the list. You need to compare the new item with the list instead. Step through your logic carefully either with a debugger or by manually writing down the values of your variables and you will see the problem.
You could simply change this line:
if(checkDuplicate(names)==true)
to this:
if(!names.contains(txtname.getText()))
You don't really need checkDuplicate since it's "reinventing the wheel" so to speak. ArrayList already provides a contains method that you can use to your advantage.

Add a missing record into the arraylist if it is not in it

Pardon me as I'm quite a beginner in coding. I have tried researching for ways to add some missing record into the lists but still can't seem to fit it correctly into my code.
I have two ArrayLists with different resultsets. Say, the first one is derived in other method and stored in abcList. This list is then used in my current fixChartStats method as a param.
In my code, I will check for the corresponding record in abcList with the second list I derive from the hql query in fixChartStats method.
If the record corresponds, then I'll do the necessary action as shown below to update the ApprovedCount number etc, else i set it to 0.
How do I go about adding the records that are missing in second list I got into the first arraylist (i.e. abcList)? Can anyone here shed some light? Do let me know if my questions are unclear. Thanks in advance, guys!
private void fixChartStats(List<TAbcModel> abcList, Map<String, Object> param, List<IssueModel> issueList, List<DestModel> destList) throws Exception {
//initialize the hql query
//translate all fields from Object[] into individual variable
firstRow = true;
for (TAbcModel abc : abcList) {
if (abc.getId().getAbcYear() = abcYear &&
abc.getId().getAbcMonthId() = abcMonthId &&
abc.getId().getAbcApplAccnId().getAccnId().equalsIgnoreCase(abcApplAccnId.getAccnId()) {
if (firstRow) {
abc.setApprovedCount(abcApprovedCount);
abc.setCancelledCount(abcCancelledCount);
firstRow = false;
} else {
abc.setApprovedCount(0);
abc.setCancelledCount(0);
}
}else{
// How to do the necessary here
// Below is what I've tried
abcList.add(abc);
}
}
}
When I debug, I noticed that it was added into the list. But soon after it was added, ConcurrentModificationException was thrown.
Create a local list and add missing records to it then add all elements from the local list to the abcList
List<TAbcModel> temp = new ArrayList<>();
in your loop:
} else {
temp.add(abc);
}
after loop
abcList.addAll(temp);

Clear the list in do-while loop

I am using a do-while loop.In that loop I am having a condition check,whenever the condition fails, the list must get cleared. I am trying but I am not getting the expected result.
List<Date> myDateList=new ArrayList<Date>();
int zTmp=0;
do
{
if(condition true)
{
//do task
}else{
myDateList.clear();
//I wish to clear this list when condition fails
}
zTmp++;
}while(zTmp<myList.size());
I wonder how you can call clear() on ListView.Rather you should consider calling clear on Adapter which is set on ListView.
Below snippet will help you.
adapter.clear();
adapter.notifyDataSetChanged();
Not sure why clear is not working... But work around for this is to assign a new Object to list. So instead using myDateList.clear() you can use myDateList = new ArrayList<T>() or myDateList = new LinkedList<T>().
Just a doubt: Is your condition failing even once?

For-loop inside a For-loop - ListArrays - Android, Java!

This is a noob question but I have to ask it anyway because I think I'll go crazy soon.
What I want to achieve is a ListView that populates by twitter and this I have implemented, the two ListArrays gets populated by the tweet and the picture URL.
This is successful, but when I refresh twitter the new pile of twitter gets below the old ones.
I could simply clear the ListArrays but then all the twitter disappears in the list which is not desirable, I simply want to add only the new tweets, and make the new tweets get on top of the list.
So I guess this is a two fold question
How do I make the list only to add
which is not there?, and
How do I make the latest tweet
appear on top?
Could really use some great input, the code below is the most essential part of the (messy) code, which is the refresh method.
public void updateTwitter(){
twitter = new TwitterFactory().getInstance();
try {
QueryResult result = twitter.search(new Query(TWEETQUERY));
tweets = result.getTweets();
for (Tweet tweet : tweets) {
String tweetProfile = tweet.getProfileImageUrl();
String twwwwww = tweet.getText();
for(String tww : tweetString){
if(tww.equals(twwwwww)){
System.out.println("Not added");
} else {
tweetString.add(twwwwww);
urlArray.add(tweetProfile);
}
}
}
if(adapter != null) {
tweetList.setAdapter(adapter);
System.out.println("adapter sets, not created");
} else {
adapter = new LazyAdapter(this, urlArray, tweetString);
tweetList.setAdapter(adapter);
}
} catch (TwitterException te) {
te.printStackTrace();
System.out.println("Failed to search tweets: " + te.getMessage());
}
}
Make an Adapter that extends from BaseAdapter and call notifyDataSetChanged().
Presumably, the LazyAdapter derives from BaseAdapter and is backed by urlArray. If so, to have tweets appear on top, you need to add them to the beginning of the array.
Use add(0, newEntry) to add to the beginning of the array and notifyDataSetChanged() to tell the adapter to post the updates.
A couple of other notes:
1) Its unclear to me what you intend, especially seeing code like twww.equals(twwwwwww). It seems like you're maintaining the old tweets and trying to only add new ones, but with unclear variable names like twww, twwwwww, and tweetString, I can only guess.
2) You shouldn't have to keep setting the adapter. Once the relationship between the listview, adapter, and backing array is set, you should only have to update the array and notify the adapter.
It sounds like you really want a set, not a list, and be able to traverse it according to some criteria (time added, in this case).
Perhaps a SortedSet would be appropriate?
The implementation would be something like this:
/* SortedSet<Tweet> tweets defined somewhere above, possibly with a custom Comparator */
public void updateTwitter()
{
try
{
tweets.addAll(TwitterFactory.getInstance().search(query).getTweets());
} catch (TwitterException te) {
te.printStackTrace();
System.out.println("Failed to search tweets: " + te.getMessage());
}
}

Categories

Resources