问题
The problem is,onCheckedChange() methods get called repeatedly and the phone runs out of memory. When I take the calls to the AsyncTask out of the checkedChange method it works fine. Or if I take the setChecked() calls out it works fine as well. But I have to have those methods in there for this portion of the application to make sense. The WebService calls are super short but have to be toggled from the Toggle button.
I would like you to share some of your thoughts and opinions.
private class ItemAdapter extends ArrayAdapter<FavItem> {
private final ArrayList<FavItem> cats;
public int count;
// private Context m;
public ItemAdapter(Context context, int textViewResourceId,
ArrayList<FavItem> myItems) {
super(context, textViewResourceId, myItems);
this.cats = myItems;
// this.m = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// LayoutInflater vi = getLayoutInflater();
v = vi.inflate(R.layout.favitem, null);
}
final FavItem o = cats.get(position);
if (o != null) {
TextView title = (TextView) v.findViewById(R.id.textViewNear1);
TextView sub = (TextView) v.findViewById(R.id.textViewNear2);
final ToggleButton text = (ToggleButton) v
.findViewById(R.id.texttoggle);
final ToggleButton email = (ToggleButton) v
.findViewById(R.id.emailtoggle);
text.setChecked(o.getFav_sms() == 1 ? true : false);
email.setChecked(o.getFav_email() == 1 ? true : false);
title.setText(o.getBusiness_name());
sub.setText(o.getDeal_name());
text.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton cText,
boolean textCheck) {
count++;
int uText = text.isChecked() ? 1 : 0;
int uEmail = email.isChecked() ? 1 : 2;
int id = o.getObject_id();
String catURL = "https://example.com/?fn=myfavs&a=add&ot=2&oid="
+ id + "&f1=" + uText + "&f2=" + uEmail;
UpdateFavs u = new UpdateFavs();
u.execute(catURL);
log("URL" + catURL);
log("count: " + count);
}
});
email.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton cEmail,
boolean emailChecked) {
int id = o.getObject_id();
count++;
int uText = text.isChecked() ? 1 : 0;
int uEmail = email.isChecked() ? 1 : 2;
String catURL = "https://example.com/?fn=myfavs&a=add&ot=2&oid="
+ id + "&f1=" + uText + "&f2=" + uEmail;
UpdateFavs u = new UpdateFavs();
u.execute(catURL);
log("URL" + catURL);
log("count: " + count);
}
});
}
return v;
}
}
private class UpdateFavs extends AsyncTask<String, Void, String> {
InputStream is;
String result;
@Override
protected void onPreExecute() {
pBar.setVisibility(View.VISIBLE);
}
@Override
protected String doInBackground(String... id) {
try {
// final String catURL =
// "https://example.com/?fn=myfavs&a=add&ot=2&oid="
// + "&f1=" + uText + "&f2=" + uEmail;
String catURL = id[0];
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(catURL);
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("ID",
getCookie()));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
httpclient.execute(httppost);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
@Override
protected void onPostExecute(String result) {
pBar.setVisibility(View.GONE);
}
}
回答1:
First of all let your ItemAdapter class implement OnCheckedChangeListener. In your code, a new listener will be instantiated every time the list is scrolled. Also, since the views have a listener set on them, the listener's onCheckedChanged() method will be called every time you scroll. I suggest trying this :
private class ItemAdapter extends ArrayAdapter<FavItem> implements OnCheckedChangeListener {
private final ArrayList<FavItem> cats;
public int count;
// private Context m;
private Holder holder;
public ItemAdapter(Context context, int textViewResourceId, ArrayList myItems) { super(context, textViewResourceId, myItems); this.cats = myItems; // this.m = context; } @Override public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// LayoutInflater vi = getLayoutInflater();
v = vi.inflate(R.layout.favitem, null);
holder=new Holder();
holder.title= (TextView) v.findViewById(R.id.textViewNear1);
holder.text= (ToggleButton) v.findViewById(R.id.texttoggle);
holder.sub= (TextView) v.findViewById(R.id.textViewNear2);
holder.email= (ToggleButton) v .findViewById(R.id.emailtoggle);
convertView.setTag(holder)
}else{
holder=convertView.getTag();
}
final FavItem o = cats.get(position);
if (o != null) {
holder.text.setTag(position);
holder.email.setTag(position);
//first remove any listener already present
holder. text..setOnCheckedChangeListener(null);
holder. email.setOnCheckedChangeListener(null);
//you can now set checked state. we already removed the listener, so it will not trigger the checkd change call
holder. text.setChecked(o.getFav_sms() == 1 ? true : false);
holder.email.setChecked(o.getFav_email() == 1 ? true : false);
holder.title.setText(o.getBusiness_name());
holder.sub.setText(o.getDeal_name());
//set the listener to the views now. ( so that check events will only be triggerde manually by user and not by scrolling the lsit
holder. text.setOnCheckedChangeListener(this);
holder.email.setOnCheckedChangeListener(this);
return convertView;
}
class Holder{
TextView title ,sub ;
ToggleButton text,email;
}
@Override
public void onCheckedChanged(CompoundButton b,boolean emailChecked) {
int position=(Integer)b.getTag(); //now you know position of button in list.
switch(b.getId(){
case R.id.texttoggle: //toggle button
//do whatever you want
break;
case R.id.emailtoggle:
//do whatever you want
break;
}
}
removing listener every time before setting the item checked will do the trick. Do notice the way holder class is used. This reduces the number of times findViewById() is called from getView() method. Hope this helps
来源:https://stackoverflow.com/questions/8236603/android-listview-with-toggle-button-web-service