I'm using ListFragment with ParseQueryAdapter in order to show list of leagues (custom model).
I managed to get my desired state except that the loading animation is not showing at all.
It seems like the animation is hidden when the listsAdapter is set (by setListAdapter method), so I set the adapter only after my list is fetched, but the parseQueryAdapter fetches the list only after setting the adapter to a list.
So I found that I can use the setListShown method in order to hide/show the animation, but in my current implementation it doesn't work.
My code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
// Create query factory
ParseQueryAdapter.QueryFactory<League> factory = new ParseQueryAdapter.QueryFactory<League>() {
public ParseQuery<League> create() {
ParseQuery<League> query = League.getQuery();
query.whereEqualTo(League.FIELD_USER, ParseUser.getCurrentUser());
query.orderByDescending(League.FIELD_CREATED_AT);
return query;
}
};
// Create adapter
leagueListAdapter = new LeagueAdapter(getActivity(), factory);
// Loading listener
leagueListAdapter.addOnQueryLoadListener(new ParseQueryAdapter.OnQueryLoadListener<League>() {
#Override
public void onLoading() {
// Show ListFragment's loading animation while loading
setListShown(false);
}
#Override
public void onLoaded(List<League> leagues, Exception e) {
if(e == null){
// Hide loading animation and show the list
setListShown(true);
// Put leagues in the cache
LeaguesCache.getInstance().setCachedLeagues(leagues);
} else {
Toast.makeText(getActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
}
}
});
// Set fragment's adapter
setListAdapter(leagueListAdapter);
// Dialogs
addLeagueDialog = new addLeagueDialog(this);
}
Related
Okay, I think I have understood it, but I just want to make sure of it. I have got a ListViewAdapter that contains a List.What I wanna do is search thinks in the database and show in a ListView. This piece of code adds an item to my listView.
list.addAll(sqh.DisplayRecords(sqdb));
listViewAdapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,list);
listview.setAdapter(listViewAdapter);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listViewAdapter.clear();
list.clear();
list.addAll(sqh.DisplayRecords(sqdb));
list.add("another one");
}
});
Whit this other piece of code, only clearing the listviewAdapter and adding another item to the list, just, adds the last item, instead of all the items of the list, which should be there.
list.addAll(sqh.DisplayRecords(sqdb));
listViewAdapter = new ArrayAdapter( this,android.R.layout.simple_list_item_1,list);
listview.setAdapter(listViewAdapter);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listViewAdapter.clear();
list.add("another one");
}
});
Well, I think I understood it while I was writing this. The third one and the first one are pretty the same.
list.addAll(sqh.DisplayRecords(sqdb));
listViewAdapter = new ArrayAdapter( this,android.R.layout.simple_list_item_1,list);
listview.setAdapter(listViewAdapter);
search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listViewAdapter.clear();
list.addAll(sqh.DisplayRecords(sqdb));
list.add("another one");
}
});
The listViewAdapter.clear(); would be clearing the list of the adapter, right? Why, when I do just list.clear(), the list view is not cleared?
When you calling list.clear();, you'are removing all of the elements from the list. The list will be empty after this call returns. But your Adapter view isn't change yet. You need to call adapter.notifyDataSetChanged() to refresh the adapter.
In the other case, when you calling listViewAdapter.clear();, the list will be cleared first then the notifyDataSetChanged() called.
You can see the details in ArrayAdapter.clear() source code:
/**
* Remove all elements from the list.
*/
public void clear() {
synchronized (mLock) {
if (mOriginalValues != null) {
mOriginalValues.clear();
} else {
mObjects.clear();
}
mObjectsFromResources = false;
}
if (mNotifyOnChange) notifyDataSetChanged();
}
listViewAdapter.clear()
void clear ()
Remove all elements from the list.
And list.clear();
/**
* Removes all of the elements from this list. The list will
* be empty after this call returns.
*/
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
If you use in this , it was the same .It used to Removes all of the elements from this list .
I have a ListView that represents an order list, and a listAdapter that sets recieved data from DB to the listView, and I want to dynamically do:
paint white if item is not selected or started
paint green if item is selected (but not started)
paint orange if item selected is started (button pressed)
delete item if finish button is pressed
*(with paint I mean setBackground color of item)
**(Order have an atribute "state" to know if they are Started or not)
Currently I'm doing this only when buttons are pressed, and I want to also update UI and repaint items when orders are received and if one order is started paint it
some code of OrdersActivity:
private void updateOrders() {
if (!listItemIsSelected) {
orderAdapter.clear();
orderAdapter.notifyDataSetChanged();
populateListView();
} else {
debugLog("item is selected, list not updated");
}
}
private void populateListView() {
try {
// Read items from server
Log.d("LSO", "Reading from Database");
ListObtainer listObtainer = new ListObtainer(this);
listObtainer.getTmOfsDTOList(user, orderAdapter); // this method returns list of objects from DB and populates adapter
} catch (Exception e) {
e.printStackTrace();
}
configureAdapter();
}
private void configureAdapter() {
// Configure listview
listView = (ListView) findViewById(R.id.lvOrdenes);
listView.setAdapter(orderAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
try {
OrderRO orderRO = (OrderRO) parent.getItemAtPosition(position);
listItemIsSelected = true;
lastChildSelected = currentChildSelected;
currentChildSelected = (View) listView.getChildAt(position);
uptadteUI();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void uptadteUI() {
try {
if (lastChildSelected != null) {
lastChildSelected.setBackgroundColor(getResources().getColor(R.color.transparent));
}
if (orderIsStarted) { // Block scroll, disable start, paint item
disableIniciarOrden();
disableBotonSalir();
enableTerinarOrden();
currentChildSelected.setBackgroundColor(getResources().getColor(R.color.light_orange));
listView.setEnabled(false);
} else {// if there is no started order
listView.setEnabled(true);
enableBotonSalir();
disableTerminarOrden();
if (listItemIsSelected) { // enable start, paint item
enableIniciarOrden();
currentChildSelected.setBackgroundColor(getResources().getColor(R.color.light_green));
}
}
} catch (Exception e) {
Log.e("error", "error updating UI" + e);
}
}
public class UpdateOrdersAsync extends AsyncTask {
#Override
protected Object doInBackground(Object[] params) {
while (updateService == true) {
try {
Thread.sleep(180000);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress();
}
return null;
}
#Override
protected void onProgressUpdate(Object[] values) {
//super.onProgressUpdate(values);
debugLog(". . . calling list update");
updateOrders();
}
}
This looks to me very dirty and I have a problem: if the DB changed and Adapter is updated I can receive an Order already started and I don't know how to paint it from activity, I'm new using custom adapters and I'm confused on what I should do, I can paint the started orders directly in adapter but this breaks the logic I already did in activity(posted code) because I don't know from the activity wich orders are started(check the atribute of one item from activity).
Sorry if the question is difficult to understand or poorly explained, It's difficult to me to transmit my problem
So, you want to update the list of items on a ListView when you receive more information, correct?
I have modified your code a bit to enhance readability.
Lets say you have a list with the items :
List<Items> listItems = new List<Items>;
listItems.add(item1);
listItems.add(item2);
listItems.add(item3);
with an adapter associated to it. Then you just associated the adapter to your listView like :
ArrayAdapter<String> orderAdapter = new ArrayAdapter<String>(this,android.R.layout.listem_item, listItems);
listView.setAdapter(orderAdapter);
Now you have all your items. Lets say those items change like this :
listItems.remove(item1); // you remove item1
listItems.add(item4); // and you add item4
Now you want to inform the adapter that you have changed the base data.
You can do it like :
listView.getAdapter().notifyDataSetChanged();
What I strongly recommend is that you associate the background color to the Model instace of the row instead of the its view. This way, if the view gets re-drawn, the information will still be store inside the Model.
public class OrderRo
...
String color = "red";
boolean isOrderStarted = false;
...
...
public boolean isOrderStarted(){
return isOrderStarted;
}
public void setIsOrderStarted(boolean isOrderStarted){
this.isOrderStarted = isOrderStarted;
}
public String getColor(){
return this.color;
}
public void setColor(String color){
this.color = color;
}
....
and
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
try {
OrderRO orderRO = listView.getAdapter().getItem(position);
orderRO.setColor("orange");
orderRO.setIsOrderStarted(true);
uptadteUI(orderRO, (View) listView.getChildAt(position));
} catch (Exception e) {
e.printStackTrace();
}
}
});
private void uptadteUI(OrderRO order, View selectChild) {
try {
if (selectChild != null) {
selectChild.setBackgroundColor(getResources().getColor(R.color.transparent));
}
if (order.isOrderStarted()) { // Block scroll, disable start, paint item
disableIniciarOrden();
disableBotonSalir();
enableTerminarOrden();
selectChild.setBackgroundColor(getResources().getColor(R.color.light_orange));
listView.setEnabled(false);
} else {// if there is no started order
listView.setEnabled(true);
enableBotonSalir();
disableTerminarOrden();
if (listItemIsSelected) { // enable start, paint item
enableIniciarOrden();
selectChild.setBackgroundColor(getResources().getColor(R.color.light_green));
}
}
} catch (Exception e) {
Log.e("error", "error updating UI" + e);
}
}
I think you should keep state in your OrderRO class.And when state is changed,call notifyDataSetChanged.In getView method,paint view with different colors according to the state in OrderRO.
Add status attribute to OrderRO class like started, pressed etc. In your adapter, where inflate the listview items check this status and set view color. On onItemClick method change item status and call adapter.notifyDataSetChanged().
first, you have to fill the data source that ListView gets the data from, and then, call the method:
listView.getAdapter().notifyDataSetChanged();
then the list will get all the new data filled in the data source
I have a code where I add all TODOs to the adapter, like this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_todo);
adapter = new TODOAdapter(this, TODO.listAll(TODO.class));
listView = (ListView) findViewById(R.id.listView);
listView.setAdapter(adapter);
}
When add I new TODO, I do this
private void createTodo(String s) {
TODOWorker.createTodo(s);
adapter.notifyDataSetChanged();
Toast.makeText(getApplicationContext(), "Your TODO was saved!", Toast.LENGTH_LONG).show();
}
but my listview is not beign updated...what am I missing?
My best guess after looking at your code is before calling notifyDatasetChanged() on your adapter you need to set the new list on the adapter. So when a new TODO is created add it to the list and update the list that the adapter is working with. Then call the notifyDatasetChanged()
So let's say your adapter has a List<TODO> mDataList then you need to have a function like this
public void setData(List<TODO> updatedList) {
mDataList = new ArrayList<>(updatedList);
notifyDataSetChanged();
}
and change your createToDo() to this
private void createToDo(String s) {
TODOWorker.createTodo(s);
adapter.setData(TODO.listAll(TODO.class));
Toast.makeText(getApplicationContext(), "Your TODO was saved!", Toast.LENGTH_LONG).show();
}
Hope this helps. I am assuming of course that your TODOWorker is not updating the list that the adapter is working with.
When you create Adapter, it is backed by List, which you create by TODO.listAll(TODO.class)
You have to make sure that new item is inserted into this List before adapter.notifyDataSetChanged() called.
Fairly new to android programming and having trouble changing the string value "channel" when a button is clicked. Having issues trying to close the onCreate but it only seems to let me close it at the end of the activity. I get an error of 'token "}". please delete' if i try to close it elsewhere. I'm having a hard time trying to wrap my head around this even though it's probably very simple.
public class MainActivity extends Activity {
String channel = "bbc1";
// This method creates main application view
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set view
setContentView(R.layout.main);
final ViewSwitcher switcher = (ViewSwitcher)findViewById(R.id.ViewSwitcher1);
Button bbcButton = (Button) findViewById(R.id.bbcButton);
Button bbc2Button = (Button) findViewById(R.id.bbc2Button);
bbcButton.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
channel = "bbc1";
switcher.showNext();
}
});
bbc2Button.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
channel = "bbc2";
switcher.showNext();
}
});
try{
// This line creates RSS reader
RssReader rssReader = new RssReader("http://bleb.org/tv/data/rss.php?ch="+channel+"&day=0");
// This line gets a ListView from main view
ListView tvItems = (ListView) findViewById(R.id.listMainView);
// This line creates a list adapter
ArrayAdapter<RssItem> adapter = new ArrayAdapter<RssItem>(this,android.R.layout.simple_list_item_1, rssReader.getItems());
// This line sets list adapter for the ListView
tvItems.setAdapter(adapter);
} catch (Exception e) {
Log.e("Tv RSS Reader", e.getMessage());
}
}
}
I'm guessing that you want to change the RSS feed when you press the button. But since you are fetching the RSS info in the onCreate, you won't update the data, even though you are pressing the buttons. But you are changing the value of the string channel.
onCreate is only called once when you create the activity!
Try moving the try-statement into a seperate method and call this method in your two onClickListeners.
bbc2Button.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
channel = "bbc2";
updateRSS();
switcher.showNext();
}
});
public void updateRSS(){
try{
// This line creates RSS reader
RssReader rssReader = new RssReader("http://bleb.org/tv/data/rss.php?ch="+channel+"&day=0");
// This line gets a ListView from main view
ListView tvItems = (ListView) findViewById(R.id.listMainView);
// This line creates a list adapter
ArrayAdapter<RssItem> adapter = new ArrayAdapter<RssItem>(this,android.R.layout.simple_list_item_1, rssReader.getItems());
// This line sets list adapter for the ListView
tvItems.setAdapter(adapter);
} catch (Exception e) {
Log.e("Tv RSS Reader", e.getMessage());
}
I use the same activity for save and edit purpose. I have a list view.
In List fragment I have
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
if(dbHelper != null){
Item item = (Item) this.getListAdapter().getItem(position);
Intent intent = new Intent(getActivity(), SaveEditActivity.class);
intent.putExtra("Update_Item", item);
startActivity(intent);
}
}
Now in SaveEditActivity I have
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(....);
Intent intent = getIntent();
if(intent.hasExtra("Update_Item")){
Item item = (Item) intent.getSerializableExtra("Update_Item");
if(item != null){
this.isEdit = true;
this.editedItem = item;
setItemData(item); // set the data in activity
}
}
}
Now when user clicks on save button I check for isEdit flag
if(isEdit == true){
updateItem();//update
}else{
saveItem(); // add
}
}
In Update method I update the item in database using editedItem Object
private void updateItem(){
if(this.editedItem != null){
dbHelper.updateItem(editedItem);
}
}
But my list view is not refreshed with new data.
I am using customAdapter which extends BaseAdapter.
In ListFragmet I load the data into adapter in onResume() method
#Override
public void onResume() {
super.onResume();
dbHelper = new DatabaseHandler(getActivity());
List<Item> existingItems = dbHelper.getItemData();
adapter = new CustomAdapter(getActivity().getApplicationContext(), existingItems);
if(adapter != null){
this.setListAdapter(adapter);
adapter.notifyDataSetChanged();
}
}
Now when returning from activity this method should be called and adapter should be notified of the change? Isnt that right?
Can anyone help please?
Somehow you have to notify your ListView that the data set changed/updated so that it should refresh itself. In one of my app I used the Observer interface & Observable class to observe data changed or not. This helps me to solve the case.
The idea you can use is on every update/save the data set changed, so after doing so you should call a method named notifyDataSetChanged()
/* don't be confuse with this method's name, Its a custom method. I
used this name. You may use another like myAbcdMethod() :) */
private void notifyDataSetChanged() {
setChanged();
notifyObservers(new Boolean(true));
}
notifyDataSetChanged() is a private method, & you should implement this in your DbHelper. After every edit.save you can call this.
And in your activity you should use the following to refresh the list:
#Override
public void update(Observable observable, Object data) {
isDataChanged = (Boolean) data;
}
#Override
protected void onRestart() {
super.onRestart();
if (isDataChanged) {
adapter.clear();
adapter.refresh(screenNames.toArrayList());
adapter.notifyDataSetChanged();
isDataChanged = false;
}
}
This works in single activity app to multiple activity app.