Im making an ecommerce app, and on my wall i have many products (which i call items). So all these items are seen through a custom ListView
called ListViewAdapter
. each row of the customListView has various View
elements like TextView
, Button
, Image
, etc. The Button
that i have is a follow button (meaning that if the user is following a certain item this button should be seen gray saying followed, if the user is not following it then it should be green saying follow).
So when i load the data in the ListView
for the first time i need to do this check to see if an item is beeing followed or not (and this function is done by doing a server call in background and based on the response i know if its beeing followed or not). Plus i need to implement a function that when i click on the follow button of a certain item it does the server call in background (getting a result = 0 if the operation succeded), changes color and text.
I've made an ItemView class that manages the View
s of an item, and my question arrises here:
How do i manage the fact that i need to dynamically manage the follow
Button
(obviously i need to use AsyncTask), but where do i manage it? in the ItemView class or in ListViewAdapter for each row?I need to manage these 3 server calls all together: get all the items, see which one is followed or not, and if i select an item follow it.
I read a lot that i should use adapter.notifyDataSetChanged()
but where and how ?
Im sure im not the first person to ask such a question. I imagine that most ecommerce apps have the same behaviour. Could you please show me how this is done efficiently. Thanks!
Here is my code:
ListViewAdapter class
public class ListViewAdapter extends ArrayAdapter<String> {
private LayoutInflater inflater = null;
public Context context;
public int layoutResourceId;
public ArrayList<Item> items;
public Bitmap icon;
public ListViewAdapter(Context context, int listviewItemRow, ArrayList<Item> items, Bitmap icon) {
// TODO Auto-generated constructor stub
super(context, listviewItemRow);
this.items = items;
this.context = context;
this.icon = icon;
}
@Override
public void remove(String object) {
// TODO Auto-generated method stub
super.remove(object);
}
@Override
public int getCount() {
return items.size();
}
public Item getItem(Item position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ItemView view;
if (convertView == null) {
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (ItemView) inflater.inflate(R.layout.listview_item_row, null);
} else {
view = (ItemView) convertView;
}
Item item = items.get(position);
view.showItems(item);
view.setOnClickListener(new OnItemClickListener(position));
return view;
}
private class OnItemClickListener implements OnClickListener {
private int mPosition;
private OnItemClickListener(int position){
mPosition = position;
}
@Override
public void onClick(View v) {
Log.i("onListItemClickList", "Item clicked: " + mPosition);
Toast.makeText(context, "Message " + Integer.toString(mPosition), Toast.LENGTH_SHORT).show();
Intent intent = new Intent(context, DettagliActivity.class);
Bundle bundle = new Bundle();
bundle.putInt("id", mPosition);
intent.putExtras(bundle);
context.startActivity(intent);
}
}
ItemView class
public class ItemView extends LinearLayout implements AsyncResponse{
public TextView prezzo;
public TextView scadenza;
public TextView followers;
public ImageView ic_thumbnail;
public ProgressBar hProgressBar;
public ToggleButton followButton;
public String nextFollowAction = "";
public Integer result1 = 77;
public int statusCode;
public Item item;
public BackgroundTask mBackgroundTask = null;
public ItemView(Context context, AttributeSet attrs) {
super(context, attrs);
//mBackgroundTask.delegate = this;
// TODO Auto-generated constructor stub
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
prezzo = (TextView)findViewById(R.id.tvPrezzo);
scadenza = (TextView)findViewById(R.id.tvScadenza);
followers = (TextView)findViewById(R.id.tvFollowers);
ic_thumbnail = (ImageView)findViewById(R.id.ic_thumbnail);
hProgressBar = (ProgressBar)findViewById(R.id.hProgressBar);
followButton = (ToggleButton)findViewById(R.id.btnFollow);
}
public void showItems(final Item item) {
prezzo.setText(item.getPrezzo());
ic_thumbnail.setImageBitmap(item.getIcon());
scadenza.setText(item.getScadenza());
followers.setText("Followers: " + item.getFollowers());
hProgressBar.setProgress(item.getCoefficient());
askForFollowing("kCheckFollowAction", item, 3);
mBackgroundTask = new BackgroundTask(this);
mBackgroundTask.execute(item.getId(), (long)3);
followButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// The toggle is enabled
Log.i("followButton", "toggle enabled");
followButton.getTextOn();
mBackgroundTask = new BackgroundTask(ItemView.this);
mBackgroundTask.execute(item.getId(), (long)1);
//askForFollowing(result1, nextFollowAction, item);
//askForFollowing(statusCode, nextFollowAction, item);
increaseFollowers(item);
followButton.setBackgroundResource(R.drawable.action_object_button_gray);
} else {
// The toggle is disabled
Log.i("followButton", "toggle disabled");
mBackgroundTask = new BackgroundTask(ItemView.this);
mBackgroundTask.execute(item.getId(), (long)2);
//askForFollowing(result1, nextFollowAction, item);
followButton.getTextOff();
followButton.setBackgroundResource(R.drawable.action_object_button_green);
decreaseFollowers(item);
}
}
});
}
public void setStatusCode(int statusCode){
this.statusCode = statusCode;
}
public int getStatusCode(Item item, int follow){
//add thread that waits untill you have the statusCode
mBackgroundTask = new BackgroundTask(ItemView.this);
mBackgroundTask.execute(item.getId(), (long) follow);
return statusCode;
}
public void askForFollowing(String nextFollowAction, Item item, int follow){
Log.i("The statusCode is", Integer.toString(statusCode));
Log.i("The nextFollowAction is", nextFollowAction);
int statusCode = getStatusCode(item, follow);
//Status code: 0 --> OK
if(statusCode == 0) {
Log.i("changeFollowStatus(nextFollowAction);", "changeFollowStatus(nextFollowAction);");
nextFollowAction = "kCheckFollowAction";
changeFollowStatus(nextFollowAction, item);
}
// Status code 108 --> Oggetto già seguito
else if ((statusCode == 108) && (nextFollowAction.contains("kCheckFollowAction"))) {
Log.i("statusCode == 108", "statusCode == 108");
nextFollowAction = "kUnfollowAction";
followButton.setEnabled(true);
followButton.setBackgroundResource(R.drawable.action_object_button_gray);
followButton.setText("seguito");
}
// Status code 122 --> Oggetto non ancora seguito
else if ((statusCode == 122) && (nextFollowAction.contains("kCheckFollowAction"))) {
Log.i("statusCode == 122", "statusCode == 122");
nextFollowAction = "kFollowAction";
followButton.setEnabled(false);
followButton.setBackgroundResource(R.drawable.action_object_button_green);
followButton.setText("segui");
}
}
public void changeFollowStatus(String action, Item item){
Log.i("changeFollowStatus action", action);
if(action.contains("kFollowAction")) {
Log.i("changeFollowStatus", "1");
nextFollowAction = "kUnfollowAction";
followButton.setBackgroundResource(R.drawable.action_object_button_gray);
followButton.setText("seguito");
followButton.getTextOn();
increaseFollowers(item);
}
else if(action.contains("kUnfollowAction")){
Log.i("changeFollowStatus", "2");
nextFollowAction = "kFollowAction";
followButton.setBackgroundResource(R.drawable.action_object_button_green);
followButton.setText("segui");
followButton.getTextOff();
decreaseFollowers(item);
}
}
public void increaseFollowers(Item item){
int updatedFollowers = Integer.parseInt(item.getFollowers()) + 1;
item.setFollowers(Integer.toString(updatedFollowers));
followers.setText("Followers: " + item.getFollowers());
}
public void decreaseFollowers(Item item){
int updatedFollowers = Integer.parseInt(item.getFollowers()) - 1;
item.setFollowers(Integer.toString(updatedFollowers));
followers.setText("Followers: " + item.getFollowers());
}
@Override
public Integer processFinish(Integer result) {
return result;
}
/**
* Represents an asynchronous task used to download
* information from the webserver and display the results
*/
public class BackgroundTask extends AsyncTask<Long, Void, Integer> {
//public AsyncResponse delegate;
private AsyncResponse listener;
public BackgroundTask(AsyncResponse listener){
this.listener = listener;
}
@Override
protected Integer doInBackground(Long... params) {
// TODO: attempt authentication against a network service.
int i = MVPFunctions.getInstance().followItem(SessionManager.getUserDetails().get("login"), SessionManager.getUserDetails().get("password"), params[0], params[1].intValue());
return i;
}
@Override
protected void onPreExecute(){
/*
* This is executed on UI thread before doInBackground(). It is
* the perfect place to show the progress dialog.
*/
}
@Override
protected void onPostExecute(Integer result) {
mBackgroundTask = null;
result1 = listener.processFinish(result);
setStatusCode(result);
//delegate.processFinish(result);
//ItemView
//Log.i("onPostExecute statusCode", Integer.toString(success) + " = " + Integer.toString(statusCode));
}
@Override
protected void onCancelled() {
mBackgroundTask = null;
//showProgress(false);
}
}
}
CompraFragment class
public class CompraFragment extends ListFragment {
public ListView listView;
public ListViewAdapter adapter;
public boolean loading = false;
public boolean get_all_items = false;
//public PullToRefreshScrollView mPullRefreshScrollView;
/**
* Keep track of the login task to ensure we can cancel it if requested.
*/
private DownloadTask mDownloadTask = null;
private Boolean firstTime = true;
//public ArrayList<HashMap<String, Object>> items = new ArrayList<HashMap<String, Object>>();
public ArrayList<Item> items = new ArrayList<Item>();
public static ArrayList<Long> ids = new ArrayList<Long>();
public Bitmap icon;
public int currentItemId = 0;
public Boolean noItems = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//View rootView = inflater.inflate(R.layout.fragment_compra, false);
View rootView = inflater.inflate(R.layout.fragment_compra, container, false);
// now you must initialize your list view
listView = (ListView) rootView.findViewById(android.R.id.list);
//mDownloadTask.execute((Void) null);
mDownloadTask = new DownloadTask();
mDownloadTask.execute(currentItemId);
return rootView;
}
/**
* Represents an asynchronous task used to download
* information from the webserver and display the results
*/
public class DownloadTask extends AsyncTask<Integer, Void, Boolean> {
private ProgressDialog progressDialog;
@Override
protected Boolean doInBackground(Integer... params) {
// TODO: attempt authentication against a network service.
if (firstTime){
ids = MVPFunctions.getInstance().search();
firstTime = false;
}
if (ids.isEmpty()){
noItems = true;
return false;
}
int current_id = params[0];
// 5 elements at a time
int counter = 0;
int size = ids.size();
while (counter <= 5 && (current_id < size)) {
items.add(MVPFunctions.getInstance().getItem(ids.get(current_id)));
current_id++;
counter++;
currentItemId = current_id;
}
if(current_id == size){
get_all_items = true;
}
Log.i("current_id 2", Integer.toString(current_id));
return true;
}
@Override
protected void onPreExecute(){
/*
* This is executed on UI thread before doInBackground(). It is
* the perfect place to show the progress dialog.
*/
progressDialog = ProgressDialog.show(getActivity(), "", "Downloading Content...");
}
@Override
protected void onPostExecute(final Boolean success) {
//mDownloadTask = null;
// dismiss the dialog after getting all products
progressDialog.dismiss();
loading = false;
//showProgress(false);
Log.i("onPostExecute", "onPostExecute");
if (noItems){
Log.i("doInBackground2", "items null");
Toast.makeText(getActivity(), "Non ci sono elementi da caricare", Toast.LENGTH_LONG).show();
} else {
// updating UI from Background Thread
ListViewAdapter adapter = new ListViewAdapter(getActivity(),R.layout.listview_item_row, items, icon);
// updating listview
listView.setAdapter(adapter);
listView.setOnScrollListener(new EndlessScrollListener());
}
}
@Override
protected void onCancelled() {
mDownloadTask = null;
//showProgress(false);
}
}
public class EndlessScrollListener implements OnScrollListener {
private int visibleThreshold = 6;
private int previousTotal = 0;
public EndlessScrollListener() {
}
public EndlessScrollListener(int visibleThreshold) {
this.visibleThreshold = visibleThreshold;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (loading) {
if (totalItemCount > previousTotal) {
loading = false;
previousTotal = totalItemCount;
}
}
if (!loading && visibleItemCount != 0 && ((firstVisibleItem + visibleItemCount) >= (totalItemCount))) {
if ((currentItemId <= ids.size()) && !get_all_items){
loading = true;
mDownloadTask = new DownloadTask();
mDownloadTask.execute(currentItemId);
}
}
/*
if (visibleItemCount != 0 && ((firstVisibleItem + visibleItemCount) >= (totalItemCount))) {
if (currentItemId <= ids.size()){
Log.i("3333 if", "3333 if");
mDownloadTask = new DownloadTask();
mDownloadTask.execute(currentItemId);
}
}
*/
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
}
}