AutocompleteTextView is not updated dynamically - android

I am getting data (List) from an API and I am trying to update my AutcompleteTextView with this data.
This is how I currently do :
I have a TextWatcher which calls a the method to get the data in afterTextChanged, so every time the user stops typing the method is called, and the adapter is notified with ``notifyDataSetChanged :
//in onCreate
addressAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,suggestions_address);
at_address.setAdapter(addressAdapter);
...
#Override
public void afterTextChanged(Editable s) {
autoComplete(s);
addressAdapter.notifyDataSetChanged();
//suggestions_address is the updated list, and when I print it I can see the
//results so it is not empty
Log.i("addresses",suggestions_address.toString());
}
...
class SuggestionQueryListener implements ResultListener<List<String>> {
#Override
public void onCompleted(List<String> data, ErrorCode error) {
if (error != ErrorCode.NONE) {
Toast.makeText(MainActivity2.this,error.toString(),Toast.LENGTH_LONG).show();
} else {
suggestions_address.clear();
for(int i = 0;i<data.size();i++){
suggestions_address.add(data.get(i));
}
}
}
}
public void autoComplete(CharSequence s) {
try {
String term = s.toString();
TextSuggestionRequest request = null;
request = new TextSuggestionRequest(term).setSearchCenter(new GeoCoordinate(48.844900, 2.395658));
request.execute(new SuggestionQueryListener());
if (request.execute(new SuggestionQueryListener()) != ErrorCode.NONE) {
//Handle request error
//...
}
} catch (IllegalArgumentException ex) {
//
}
}
But it seems that the adapter is not really updated because it doesn't show the suggestions when I type something.
Also, before doing this with an AutoCompleteTextView I did it with a listView, with the same process, and everything worked well.
Any ideas or solutions would be really appreciated
EDIT : I noticed something really strange : the data is not binded to the adapter, because adapter#getCount always returns 0, even if the list is not empty. But when I remove at_address.setAdapter(addressAdapter), the data adapter is updated and adapter#getCount returns the right number of elements.
I am really confused right now, please help !

Instead of this:
for(int i = 0;i<data.size();i++){
suggestions_address.add(data.get(i));
}
you can use just this:
suggestions_address.addAll(data);
you are calling notifyDataSetChanged after you start the request, you should call it after you get the result and update the suggestions_address, so call notifyDataSetChanged inside onCompleted

Related

Why Textview is not updating data everytime?

I'm trying to get text from db then update text in my textView of recyclerView adapter class . Although I'm getting text from db without any problem but my textview is not updating text everytime . Sometimes it's updating and sometimes it's not I wonder what's the problem . I tried to refer a lot of SO questions but none of them could solve my issue . I even tried to use textView.invalidate() but it was of no use . Could anyone please help me to solve this issue.
Code:
#Override
public void onBindViewHolder( CustomRecyclerViewHolder holder, int position) {
JSONObject ov=new JSONObject();
try {
ov.put("prof_email",timelineData.getEmail());
socket.disconnect();
socket.connect();
socket.emit("data",ov);
socket.on("name_full", new Emitter.Listener() {
#Override
public void call(Object... args) {
final JSONObject ob = (JSONObject)args[0];
try {
final String st = ob.getString("fullname");
Needle.onMainThread().execute(new Runnable() {
#Override
public void run() {
if (st.length() > 0) {
//I'm toasting just to test that text is alright or not but it's alright
Toast.makeText(context,st,Toast.LENGTH_SHORT).show();
holder.userName.invalidate();//here not useful
holder.userName.setText(st);
holder.userName.invalidate();//even here also not useful
socket.disconnect();
}
}
});
}catch (Exception e){
e.printStackTrace();
}
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
OnBindViewHolder will be called every time when user scroll the recyclerview.
So corresponding to your source code, socket connection and disconnection is done many times when user scroll the list. (This seems not a good way)
So I recommend to remove socket related code from onBindViewHolder.
After that just listening to the socket. When data changed, replace old data with new one from your collection and call Adapter#notifyDatasetChanged().

RecyclerView doesn't update the UI after data changed

I am new in android development, after make a network request trying to update item view in the RecyclerView control without scrolling it. As far as I understand items gets refreshed during scroll via onBindViewHolder event.here is the code. Using notifyItemChanged method to update UI but it doesn't work until user scroll.
Note : favoriteMatches is not my data source. It is another list of objects which stores user favorites,
inside onBindViewHolder event I am cheking if item is favoriteMatches.contains(match) then render as fav item.
call.enqueue(new Callback<AddRemoveFavoriteRequest.Response>() {
#Override
public void onResponse(Call<AddRemoveFavoriteRequest.Response> call, Response<AddRemoveFavoriteRequest.Response> response) {
AddRemoveFavoriteRequest.Response body = response.body();
Utilities.dismissProgressDialog(getActivity(),progressBar);
if(body.error == null){
if(add){
favoriteMatches.add(matchId);
}
else {
favoriteMatches.remove(matchId);
}
adapter.notifyItemChanged(absolutePosition);
Preferences.getDefaultPreferences().edit()
.putStringSet(Preferences.PREF_FAVORITES,favoriteMatches)
.apply();
}else{
Utilities.showSnackBar(getActivity(),recyclerView,body.error);
}
}
#Override
public void onFailure(Call<AddRemoveFavoriteRequest.Response> call, Throwable t) {
t.printStackTrace();
Utilities.dismissProgressDialog(getActivity(),progressBar);
}
});
notifyItemChanged takes the position at which the item changed.
You are adding and removing elements, so that position is going to move around. Instead, you can individually notify at positions.
int changedPosition = 0;
if(add){
changedPosition = favoritesMatches.size();
favoriteMatches.add(matchId);
adapter.notifyItemInserted(changedPosition);
}
else {
changedPosition = favoriteMatches.indexOf(matchId); // might not work
favoriteMatches.remove(matchId);
adapter.notifyItemRemoved(changedPosition);
}
Or, instead update the entire list
adapter.notifyDataSetChanged();
Read more about notifying the adapter, but note
a RecyclerView adapter should not rely on notifyDataSetChanged() since the more granular actions should be used.

Using popBackStack() in Android does not update android-listview with Firebase data

At the beginning of the chat app user see a list off groups (listview group) available and the user have the possibility to create a new group or click on some off the available groups and then start to write messages (listview messages). The functions CreateNewMessage and CreateNewGroup pushes information to firebase correctly
Above scenarios works finne problems arise when user navigates backwards (popBackStack()) from listview with messages to GroupFragment, here should user be presented a list off available groups but the listview is empty. The ReadGroupData() function is not reading the already created groups from firebase and inserts them in the group listview. How to make this happen?
GroupFragment:
public void ReadGroupData() {
Firebase firebaserootRef = new Firebase("https://000.firebaseio.com");
firebaserootRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot snapshot, String s) {
if (snapshot.getValue() != null) {
Group newGroup = new Group((String)snapshot.child("name").getValue(),
(String) snapshot.child("id").getValue());
if(!groupKeyValues.contains(newGroup.GetId())) {
groupKeyValues.add(newGroup.GetId());
AddToLstViewGroup(newGroup);
System.out.println("Read group data from firebase and
inserted in listView");
}
}
}
});
}
public void AddToLstViewGroup(Group newGroup) {
groupNameList.add(newGroup);
if(groupAdapter == null) {
groupAdapter = new GroupAdapter(getActivity(), groupNameList);
}
if (lstViewGroup == null) {
lstViewGroup = (ListView) getView().
findViewById(R.id.listView_group);
}
lstViewGroup.setOnItemClickListener(onItemClickListener);
lstViewGroup.setOnItemLongClickListener(onItemLongClickListener);
groupAdapter.notifyDataSetChanged();
lstViewGroup.setAdapter(groupAdapter);
}
ChatFragment:
public void ReadChatMessages(Firebase firebaseRootRef) {
firebaseRootRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot snapshot, String s) {
if (snapshot.child(GetGroupId()).child("messages").
getChildren() != null) {
for (DataSnapshot c :
snapshot.child(GetGroupId()).child("messages").getChildren()) {
String key = c.getKey();
Message newMessage = new Message();
newMessage.SetFrom((String) c.child("from").getValue());
newMessage.SetMsg((String)
c.child("message").getValue());
newMessage.SetTime((String) c.child("time").getValue());
newMessage.SetId((String) c.child("id").getValue());
if ((!msgKeyValues.contains(key)) ||
newMessage.GetFrom() != "") {
msgKeyValues.add(key);
AddToLstViewChat(newMessage);
//Automatic scrolls to last line in listView.
lstViewChat.setSelection(chatAdapter.getCount() -1);
}
}
}
}
public void AddToLstViewChat(Message newMessage) {
chatMsgList.add(newMessage);
if (chatAdapter == null) {
chatAdapter = new ChatAdapter(getActivity(), chatMsgList);
}
if(IsMsgFromMe(newMessage)) {
lstViewChat = (ListView)
getView().findViewById(R.id.listView_chat_message_me);
} else {
lstViewChat =
(ListView)getView().findViewById(R.id.listView_chat_message_others);
}
chatAdapter.notifyDataSetChanged();
lstViewChat.setAdapter(chatAdapter);
}
ChatActivity:
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
finish();
}
}
For all the code click on the link: "http://pastebin.com/97nR68Rm"
SOLUTION!
Kato thank you for you patience and help. I have now found a solution for the problem. I'm calling ReadGroupData() and ReadChatMessages() at the end (before return) in my onCreateView methods. As Kato pointed out onCreate() is not getting called on popBackStack()
In my AddToLStViewGroup the if statement for lstViewGroup is deleted so now it always sets the listView otherwise it will throw an exception for not finding the correct view, To clarifying:
Deleted this line:
if (lstViewGroup == null) {
lstViewGroup = (ListView)getView().findViewById(R.id.listView_group);
}
And replaced with:
ListView lstViewGroup=(ListView)getView().findViewById(R.id.listView_group);
Kato thank you for you patience and help. I have now found a solution for the problem. I'm calling ReadGroupData() and ReadChatMessages() at the end (before return) in my onCreateView methods. As Kato pointed out onCreate() is not getting called on popBackStack()
In my AddToLStViewGroup the if statement for listViewGroup is deleted so now it always sets the listView otherwise it will throw an exception for not finding the correct view.
To clarify:
I deleted this line:
if (lstViewGroup == null) {
lstViewGroup = (ListView)getView().findViewById(R.id.listView_group);
}
And replaced it with:
ListView lstViewGroup =(ListView)getView().findViewById(R.id.listView_group);
(The original asker posted the answer as part of the question. I'm copying it here as a matter of housekeeping.)

clearCachedResult() not working as expected

I have this query located in my ParseQueryBuilder object:
public ParseQuery<Event> eventsTypes() {
ParseQuery<Event> query = Event.getQuery();
query.setCachePolicy(ParseQuery.CachePolicy.CACHE_ELSE_NETWORK);
query.setMaxCacheAge(TimeUnit.DAYS.toMillis(1));
query.whereEqualTo(Event.owner, parse.getParseUser());
query.orderByDescending(Event.timesUsed);
return query;
}
I use it to populate a ParseQueryAdapter
and at some point I would like to add an Event and immediately show it:
#OnClick(R.id.add)
public void add(Button button) {
final Event new_type = new Event();
new_type.setOwner(parse.getParseUser());
new_type.setName("atest");
new_type.saveEventually(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
// on successfull save, clear cache
parseQueryBuilder.eventsTypes().clearCachedResult();
// and show newly added object
mAdapter.loadObjects();
Toast.makeText(getActivity(), new_type.getName(), Toast.LENGTH_SHORT).show();
}
}
});
}
I expected clearing the cache would result in a new network query, revealing the newly added item but no matter what I try, it seems it will only show the initially cached result.
Even if I try to restart my app, it shows the result from the first cache.

Android not waiting for DB response before finishing statement

I have an interesting problem that I've never run into in programming before. I have an onClickListener that does a lot of username and password checks (makes sure the username is proper length, not taken, etc). I'm using MobDB, and I was using a conditional statement that would return a row if the username already existed. The problem is that the Listener skips the DB and goes to the final check that, if everything works, posts a new username and password to my DB. How can I make it wait for a response from the DB before skipping to the last check?
Here is the relevant code:
usernamecheck3 = true;
MobDB.getInstance().execute(APP_KEY, null, rd, null, false, new MobDBResponseListener() {
#Override public void mobDBSuccessResponse() {
usernamecheck3 = false;
Log.e("mobdbSuccess:", "success");
}
#Override public void mobDBResponse(Vector<HashMap<String, Object[]>> row) {
}
#Override public void mobDBResponse(String jsonObj) {
/*Log.e("mobdbSuccess:", "jsonObj");
Log.e("mobdbSuccess:", jsonObj);
JSONObject mainObject;
try {
mainObject = new JSONObject(jsonObj);
// need to parse the json object.
} catch (JSONException e1) {
e1.printStackTrace();
} */
}
#Override public void mobDBFileResponse(String fileName, byte[] fileData) {
//get file name with extension and file byte array
}
#Override public void mobDBErrorResponse(Integer errValue, String errMsg) {
usernamecheck3 = false;
Log.e("doesnt", "work");
}
});
if(usernamecheck3 == false){
Toast.makeText(getApplicationContext(), "Username is taken, please choose another", Toast.LENGTH_SHORT).show();
}
Basically the check always returns true, and then logcat will say mobdbSuccess: success, which should have set the Bool to false.
Thanks.
MobDBResponseListener is executing on a different thread. What happens here is that the processing is split, while a thread is doing the query, the main thread on which you added the listener, skips right ahead to the validation. Your best bet is to place the validation inside the MobDBResponseListener, on the mobDBResponse method.
Try to debug your code and calls, the Listener may be using an async task. If so, you may do anything you please from the response method, as it will be executing in the main thread again. Otherwise, you should look at solutions that handle threaded execution like Handlers

Categories

Resources