Im使用cwac-endless
EndlessAdapter
與自定義ListViewAdapter
。通過一個AsyncTask,我可以分兩個階段獲取webserver的數據表單。 1)我得到使用,我想加載EndlessAdapter元素 2)的所有ID說,在同一時間(我從服務器獲取4件4個元素通過其ID)EndlessAdapter無法正確添加項目到自定義ListView
的問題,即時通訊面臨的是,當我創建我的custom ListViewAdapter
時,我調用MyEndlessAdapter的構造函數創建項目的第一個項目的列表。當我加載下一批元素我的自定義ListViewAdapter
它從服務器獲取正確的項目,但我回收getView(圖形/視覺的東西)。我究竟做錯了什麼!
我認爲可能的解決方案是使用的add
方法,但我不知道如何從CompraFragment
類中調用它。
我該如何解決這個問題? 由於
ListViewAdapter代碼:
public class ListViewAdapter extends ArrayAdapter<Item> {
private LayoutInflater inflater = null;
private final String TAG = "ListViewAdapter";
public Context context;
public int layoutResourceId;
public ArrayList<Item> items;
public ListViewAdapter(Context context, int listviewItemRow, ArrayList<Item> items) {
// TODO Auto-generated constructor stub
super(context, listviewItemRow);
this.context = context;
this.items = items;
}
public ListViewAdapter(Context context, int listviewItemRow) {
super(context, listviewItemRow);
this.context = context;
}
@Override
public void add(Item object) {
Log.i(TAG, "---ADD---");
items.add(object);
//super.add(object);
}
@Override
public void clear() {
super.clear();
}
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
}
@Override
public void remove(Item object) {
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) {
Item item = items.get(position);
Log.w(TAG, "view of Item " + item.getId() + " at position " + position);
ItemView view;
if (convertView == null) {
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (ItemView) inflater.inflate(R.layout.listview_item_row, null);
view.checkFollowing(item, this, 3);
view.setTag(Long.toString(item.getId()));
Log.e(TAG, "CREATED ITEM " + item.getId() + " at position " + position);
} else {
view = (ItemView) convertView;
Log.i(TAG, "RECYCLED ITEM " + item.getId() + " at position " + position);
}
view.setOnClickListener(new OnItemClickListener(position));
view.showItems(item);
return view;
}
private class OnItemClickListener implements OnClickListener {
private int mPosition;
private OnItemClickListener(int position){
mPosition = position;
}
@Override
public void onClick(View v) {
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);
}
}
}
CompraFragment代碼:
public class CompraFragment extends ListFragment {
private static final String TAG = "CompraFragment";
public ListView listView;
public MyEndlessAdapter adapter = null;
public ListViewAdapter mListViewAdapter;
private DownloadTask mDownloadTask = null;
public ArrayList<Item> items;
public ArrayList<Long> ids;
public Bitmap icon;
public int currentItemId = 0;
public String category = "";
public String latitude = "";
public String longitude = "";
public String radius = "";
public String keywords = "";
public String order = "";
public String state = "2";
//numero di elementi caricabili sulla wall all volta
public final int BATCH_SIZE = 4;
public ProgressDialog progressDialog;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
progressDialog = new ProgressDialog(this.getActivity());
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar actions click
switch (item.getItemId()) {
case R.id.action_aggiorna:
items = new ArrayList<Item>();
ids = new ArrayList<Long>();
mDownloadTask = new DownloadTask();
mDownloadTask.execute();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// TODO Auto-generated method stub
inflater.inflate(R.menu.compra, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i(TAG, "onCreateView");
Bundle extras = getActivity().getIntent().getExtras();
if (extras != null){
category = (String) extras.get("category");
latitude = (String) extras.get("latitude");
longitude = (String) extras.get("radius");
radius = (String) extras.get("radius");
keywords = (String) extras.get("keywords");
order = (String) extras.get("order");
state = (String) extras.get("state");
}
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 = new DownloadTask();
mDownloadTask.execute();
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> {
@Override
protected Boolean doInBackground(Integer... params) {
ids = new ArrayList<Long>();
ids = MVPFunctions.getInstance().search(category, latitude, longitude, radius, keywords, order, state);
if (ids.isEmpty()){
return false;
} else {
Log.i(TAG, "ids size = " + ids.size());
}
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...");
progressDialog.setMessage("Downloading Content...");
progressDialog.show();
}
@Override
protected void onPostExecute(final Boolean success) {
mDownloadTask = null;
if (!success){
Log.i("onPostExecute", "items null");
Toast.makeText(getActivity(), "Non ci sono elementi da caricare", Toast.LENGTH_LONG).show();
} else {
items = new ArrayList<Item>();
adapter = new MyEndlessAdapter(items);
adapter.setRunInBackground(false);
listView.setAdapter(adapter);
}
}
@Override
protected void onCancelled() {
mDownloadTask = null;
}
}
class MyEndlessAdapter extends EndlessAdapter implements IItemsReadyListener {
private RotateAnimation rotate = null;
MyEndlessAdapter(ArrayList<Item> list) {
super(new ListViewAdapter(getActivity(),R.layout.listview_item_row, list));
rotate = new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(600);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);
Log.i(TAG, "CONSTRUCTER CALLED");
}
@Override
protected View getPendingView(ViewGroup parent) {
View row = getActivity().getLayoutInflater().inflate(R.layout.listview_item_row, null);
View child;
child = row.findViewById(R.id.relativeLayout);
child.setVisibility(View.GONE);
child = row.findViewById(R.id.throbber);
child.setVisibility(View.VISIBLE);
child.startAnimation(rotate);
return (row);
}
@Override
protected boolean cacheInBackground() throws Exception {
//Log.i(TAG, "cacheInBackground - items.size(): " + items.size());
new FetchDataTask(this, items.size()).execute();
if (items.size() < ids.size()){
return true;
} else {
return false;
}
}
@Override
public void onItemsReady(ArrayList<Item> data) {
Log.e(TAG, "onItemsReady");
items.addAll(data);
// Tell the EndlessAdapter to remove it's pending view and call notifyDataSetChanged()
adapter.onDataReady();
progressDialog.dismiss();
}
@Override
protected void appendCachedData() {
// TODO Auto-generated method stub
}
}
interface IItemsReadyListener {
public void onItemsReady(ArrayList<Item> data);
}
class FetchDataTask extends AsyncTask<Void, Void, ArrayList<Item>> {
private static final String TAG = "FetchDataTask";
IItemsReadyListener listener;
//The point from where to start counting.
int startPoint;
protected FetchDataTask(IItemsReadyListener listener, int startPoint) {
this.listener = listener;
this.startPoint = startPoint;
}
@Override
protected ArrayList<Item> doInBackground(Void... params) {
ArrayList<Item> result = new ArrayList<Item>();
Item item;
for (int i = startPoint; ((i < ids.size()) && (i < startPoint + BATCH_SIZE)); i++) {
Log.i(TAG, "i = " + i);
item = MVPFunctions.getInstance().getItem(ids.get(i));
result.add(item);
}
return (result);
}
@Override
protected void onPostExecute(ArrayList<Item> result) {
listener.onItemsReady(result);
}
}
}
ItemView控件代碼:
public class ItemView extends LinearLayout {
public TextView prezzo;
public TextView scadenza;
public TextView followers;
public ImageView ic_thumbnail;
public ProgressBar hProgressBar;
public ToggleButton followButton;
public String nextFollowAction = "";
public ListViewAdapter lva;
public String mLogin;
public String mPassword;
public int statusCode;
public Item item;
public BackgroundTask mBackgroundTask = null;
public ItemView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@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());
followButton.setTag(item.getId());
}
public void askForFollowing(String nextFollowAction, final Item item, final int statusCode){
//Log.e("status code fo item is", Integer.toString(statusCode) + " " + item.getId());
//Status code: 0 --> OK
if(statusCode == 0) {
//Log.i("statusCode == 0", "richiesta evasa correttamente");
changeFollowStatus(nextFollowAction, item);
}
// Status code 108 --> Oggetto già seguito
else if ((statusCode == 108) && (nextFollowAction.contains("kCheckFollowAction"))) {
//Log.i("statusCode == 108", "gray");
nextFollowAction = "kUnfollowAction";
followButton.setEnabled(true);
followButton.setBackgroundResource(R.drawable.action_object_button_gray);
followButton.setText("seguito");
lva.notifyDataSetChanged();
followButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
view.setEnabled(false);
setFollowing("kUnfollowAction", item, (long) 2);
}
});
}
// Status code 122 --> Oggetto non ancora seguito
else if ((statusCode == 122) && (nextFollowAction.contains("kCheckFollowAction"))) {
//Log.i("statusCode == 122", "green");
nextFollowAction = "kFollowAction";
followButton.setEnabled(true);
followButton.setBackgroundResource(R.drawable.action_object_button_green);
followButton.setText("segui");
lva.notifyDataSetChanged();
followButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
view.setEnabled(false);
setFollowing("kFollowAction", item, (long) 1);
}
});
} else {
Log.e("error", "error non e ne 0 ne 108 ne 122");
Log.e("error", nextFollowAction);
Log.e("error", Long.toString(item.getId()));
Log.e("error", Integer.toString(statusCode));
}
}
public void changeFollowStatus(String nextFollowAction, Item item){
//Log.i("changeFollowStatus action", nextFollowAction);
if(nextFollowAction.contains("kFollowAction")) {
//Log.w("changeFollowStatus increase", "+1");
nextFollowAction = "kUnfollowAction";
followButton.setBackgroundResource(R.drawable.action_object_button_gray);
followButton.setText("seguito");
followButton.getTextOn();
increaseFollowers(item);
}
else if(nextFollowAction.contains("kUnfollowAction")){
//Log.w("changeFollowStatus decrease", "-1");
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());
}
public void checkFollowing(Item item, ListViewAdapter listViewAdapter, long follow) {
this.lva = listViewAdapter;
mBackgroundTask = new BackgroundTask();
try {
int statusCode = mBackgroundTask.execute(item.getId(), follow).get();
askForFollowing("kCheckFollowAction", item, statusCode);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
public void setFollowing(String nextFollowAction, Item item, Long follow){
mBackgroundTask = new BackgroundTask();
try {
int statusCode = mBackgroundTask.execute(item.getId(), follow).get();
/*
Log.i("setFollowing p1", Long.toString(follow));
Log.i("setFollowing p1", nextFollowAction);
Log.i("setFollowing p2", Long.toString(item.getId()));
Log.i("setFollowing p3", Integer.toString(statusCode));
*/
askForFollowing(nextFollowAction, item, statusCode);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Represents an asynchronous task used to download
* information from the webserver and display the results
*/
public class BackgroundTask extends AsyncTask<Long, Void, Integer> {
private int statusCode;
@Override
protected Integer doInBackground(Long... params) {
// TODO: attempt authentication against a network service.
statusCode = MVPFunctions.getInstance().followItem(mLogin, mPassword, params[0], params[1].intValue());
return statusCode;
}
@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;
//askForFollowing("kCheckFollowAction", item, statusCode);
//listViewAdapter.notifyDataSetChanged();
//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;
}
}
}
問題是checkFollowing(params)方法會對服務器進行調用,因此是時間成本高昂的方法。如果我把它放在if(然後在回收對象中),那麼每當我向下移動listView時它就會被調用,這使得它真的很慢。 – Pheonix7
但是當視圖被回收時,它仍然會有它原來的狀態,這可能是你最初的問題。也許你可以將你已經計算好的狀態緩存在單獨的內存集合中,這樣你最多隻需要計算一次項目的狀態。 – cybersam
不,你只需要一個狀態對象的集合(因爲它看起來像你的每個項目都有多個狀態屬性)。說一個HashMap,其中Integer是該項目的位置,ItemState封裝了該項目在該位置的狀態。儘管如此,請注意ItemState - 您不希望它引用任何視圖,因爲這會導致內存泄漏,並使其更有可能會耗盡內存。 –
cybersam