Reputation: 2058
I'm creating a listview by using a Json data. I'm populating some Images, text fields and a button. When user clicks on the button buttons caption is changes.
Problem is that if button is modified and user scrolled the listview button resets to first status. Please check this video it is better to explain : https://www.youtube.com/watch?v=57ZraP7ED2E&feature=youtu.be
Adapter
public class FilmRequestAdapter extends ArrayAdapter<FilmRequest>{
Context context;
List<FilmRequest> data;
public FilmRequestAdapter(Context context, int resource, List<FilmRequest> objects) {
super(context, resource, objects);
// TODO Auto-generated constructor stub
this.context=context;
this.data=objects;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row=convertView;
if (row==null) {
LayoutInflater inflater=((Activity)context).getLayoutInflater();
row=inflater.inflate(R.layout.film_request_list,null);
}
((TextView)row.findViewById(R.id.FilmRequestFilmTitle)).setText(((FilmRequest)data.get(position)).title);
((TextView)row.findViewById(R.id.FilmRequestRating)).setText("Imdb Puanı : "+((FilmRequest)data.get(position)).rating);
((TextView)row.findViewById(R.id.FilmRequestOrder)).setText("Sıra : "+((FilmRequest)data.get(position)).order);
((TextView)row.findViewById(R.id.FilmRequestVoteCount)).setText("Oya adeti : "+((FilmRequest)data.get(position)).voteCount);
Button button=(Button)row.findViewById(R.id.FilmRequestActionButton);
String status=((FilmRequest)data.get(position)).status;
boolean requested=((FilmRequest)data.get(position)).requested;
boolean voted=((FilmRequest)data.get(position)).voted;
if (status.equalsIgnoreCase("A") || status.equalsIgnoreCase("")) {
if (requested) {
if (voted) {
button.setText("Oylanmış");
button.setEnabled(false);
}else {
button.setText("+ Oyla");
button.setEnabled(true);
button.setTag(R.string.film_request_action, "VOTEABLE");
button.setTag(R.string.film_request_id,((FilmRequest)data.get(position)).id);
}
} else {
button.setText("Filmi İste");
button.setEnabled(true);
button.setTag(R.string.film_request_action, "REQUESTABLE");
button.setTag(R.string.film_request_id,((FilmRequest)data.get(position)).imdbId);
}
} else {
button.setText("Eklenmiş");
button.setEnabled(false);
}
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
FilmRequestActivity.ButtonClickFunction(context,(Button)v);
}
});
((ImageView)row.findViewById(R.id.FilmRequestPoster)).setImageBitmap(((FilmRequest)data.get(position)).bm);
return row;
}
}
Async Class
public class FilmRequestAsync extends AsyncTask<String, Void, List<FilmRequest>>{
Context context;
ListView listView;
private ProgressDialog progressDialog;
public FilmRequestAsync (Context context) {
this.context=context;
this.listView=(ListView) ((Activity)context).findViewById(R.id.FilmRequestList);
}
protected void onPreExecute() {
this.progressDialog = ProgressDialog.show(context, "Lütfen Bekleyin...", "Fimler Yükleniyor...",true);
}
@Override
protected List<FilmRequest> doInBackground(String... params) {
Log.d("debug","FilmRequestAsync param[0]"+params[0]);
List<FilmRequest> filmRequests=null;
String jsonString;
try {
jsonString=GeneralFunctions.getUrl(params[0]);
if (jsonString!=null) {
filmRequests=this.getFilmRequestListFromJsonString(jsonString);
}
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return filmRequests;
}
private List<FilmRequest> getFilmRequestListFromJsonString(String jsonString){
List<FilmRequest> filmRequests=new ArrayList<FilmRequest>();
try {
Log.d("debug","Json Verisi oluşturuluyor.");
JSONArray json=new JSONArray(jsonString);
Log.d("debug","Json Verisi Oluşturuldu");
int i;
for (i=0;i<json.length();i++) {
JSONObject tmpJson=(JSONObject)json.get(i);
filmRequests.add(
new FilmRequest(
tmpJson.getString("id"),
tmpJson.getString("imdb_id"),
tmpJson.getString("poster"),
tmpJson.getString("title"),
tmpJson.getString("rating"),
tmpJson.getString("order"),
tmpJson.getString("status"),
tmpJson.getString("vote_count"),
tmpJson.getBoolean("requested"),
tmpJson.getBoolean("voted")
)
);
tmpJson=null;
}
} catch (JSONException e) {
Log.d("debug","Json Verisi HATASI:");
filmRequests=null;
e.printStackTrace();
}
return filmRequests;
}
@Override
protected void onPostExecute(List<FilmRequest> result) {
this.progressDialog.dismiss();
if (result==null) return;
// TODO Auto-generated method stub
super.onPostExecute(result);
Log.d("debug", "FilmRequestAsync onPostExecute Başı");
FilmRequestAdapter filmRequestAdapter=new FilmRequestAdapter(context, R.layout.film_request_list, result);
Log.d("debug","FilmRequestAsync:Adapter set ediliyor.");
listView.setAdapter(filmRequestAdapter);
Log.d("debug", "onPostExecute Sonu");
}
}
List Xml File
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/film_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:background="@drawable/film_list_style"
android:orientation="horizontal"
android:padding="3dp" >
<!-- ListRow Left sied Thumbnail image -->
<!-- Title Of Song-->
<!-- Artist Name -->
<!-- Rightend Duration -->
<ImageView
android:id="@+id/FilmRequestPoster"
android:layout_width="83dp"
android:layout_height="106dp" />
<Button
android:id="@+id/FilmRequestActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:text="+ Oyla" />
<TextView
android:id="@+id/FilmRequestRating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/FilmRequestFilmTitle"
android:layout_below="@+id/FilmRequestFilmTitle"
android:text="Rating" />
<TextView
android:id="@+id/FilmRequestVoteCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/FilmRequestOrder"
android:layout_below="@+id/FilmRequestOrder"
android:text="VoteCount" />
<TextView
android:id="@+id/FilmRequestFilmTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/FilmRequestActionButton"
android:layout_toRightOf="@+id/FilmRequestPoster"
android:text="Rihanna Love the way lie"
android:textColor="#040404"
android:textSize="15dip"
android:textStyle="bold"
android:typeface="sans" />
<TextView
android:id="@+id/FilmRequestOrder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/FilmRequestRating"
android:layout_toRightOf="@+id/FilmRequestPoster"
android:text="Order" />
</RelativeLayout>
Click Functions
public static void ButtonClickFunction(Context context, Button button){
//Burası Ne işlem yapabileceğimizi gösteriyor.
//REQUESTABLE veya VOTABLE değerleri alabilir.
String action=(String)button.getTag(R.string.film_request_action);
String id=(String)button.getTag(R.string.film_request_id);
Log.d("debug", "String action="+action);
if (action.equalsIgnoreCase("VOTEABLE")) {
VoteFilm(context, button,id);
} else if (action.equalsIgnoreCase("REQUESTABLE")) {
RequestFilm(context, button, id);
}
}
public static void VoteFilm(Context context, final Button button, final String id){
final String callUrl=context.getString(R.string.api_url)+"?request=vote_film&user_id=1&id="+id;
Log.d("debug", "FilmRequestActivity->VoteFilm->callUrl:"+callUrl);
new Thread(new Runnable() {
@Override
public void run() {
try {
GeneralFunctions.getUrl(callUrl);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
button.post(new Runnable() {
@Override
public void run() {
button.setText("Oylanmış");
button.setEnabled(false);
}
});
}
}).start();
Toast.makeText(context, "Film Oylandı", Toast.LENGTH_SHORT).show();
}
public static void RequestFilm(Context context, final Button button,final String id){
final String callUrl=context.getString(R.string.api_url)+"?request=request_film&user_id=1&id="+id;
Log.d("debug", "FilmRequestActivity->RequestFilm->callUrl:"+callUrl);
new Thread(new Runnable() {
@Override
public void run() {
String jsonString;
final JSONObject jsonObject;
try {
jsonString = GeneralFunctions.getUrl(callUrl);
jsonObject=GeneralFunctions.StringToJSONObject(jsonString);
if (jsonObject!=null) {
button.post(new Runnable() {
@Override
public void run() {
try {
Log.d("debug","Inside Thread");
JSONObject data=(JSONObject) jsonObject.get("data");
String new_id=data.getString("id");
button.setTag(R.string.film_request_action,"VOTEABLE");
button.setTag(R.string.film_request_id,new_id);
button.setText("+Oyla");
button.setEnabled(true);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
Upvotes: 2
Views: 849
Reputation: 411
In my opinion you're using the views to store its state, so when the view is recycled in the scroll, the original element loses the state, even the state could be assigned to other elements that obtains the recycled view. Try to store the state of an element not in the view but in an different structure in the adapter.
Upvotes: 0
Reputation: 2049
I was same issue but I solve by this code
public class CustomizeListView extends ListActivity {
LayoutInflater inflater;
static int index = 0;
// AutoCompleteTextView autoCompleteTextView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_order);
inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, arrayList_Category);
dataAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
final CustomAdapter adapter = new CustomAdapter(this,
R.layout.activity_orderitem, arrayListItems);
setListAdapter(adapter);
}
private class CustomAdapter extends ArrayAdapter<HashMap<String, Object>>
implements OnItemSelectedListener {
boolean[] checkBoxState;
ViewHolder viewHolder;
public CustomAdapter(Context context, int textViewResourceId,
ArrayList<HashMap<String, Object>> arrayListItems) {
// let android do the initializing :)
super(context, textViewResourceId, arrayListItems);
checkBoxState = new boolean[arrayListItems.size()];
}
// class for caching the views in a row
private class ViewHolder {
CheckBox checkBox;
}
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
Log.d("getView", "getView");
if (convertView == null) {
convertView = inflater.inflate(R.layout.activity_orderitem,
null);
viewHolder = new ViewHolder();
// cache the views
convertView.setTag(viewHolder);
} else
viewHolder = (ViewHolder) convertView.getTag();
viewHolder.checkBox.setChecked(checkBoxState[position]);
viewHolder.checkBox.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (((CheckBox) v).isChecked()) {
checkBoxState[position] = true;
} else {
checkBoxState[position] = false;
}
}
});
return convertView;
}
}
}
Upvotes: 0
Reputation: 157457
The problem is that you never modify the content of your adapter when you call ButtonClickFunction
. This way when you scroll, the hold state is met and the old string is set to your button. I suggest you to think better about your design. As quick fix, you can set another tag to your Button, adding the FilmRequest object at position, for instance:
final FilmRequest filmRequest = (FilmRequest)data.get(position);
String status = filmRequest.status;
boolean requested = filmRequest.requested;
boolean voted = filmRequest.voted;
then, inside the ButtonClickFunction
, retrieve this tag and change its status
accordingly
Upvotes: 2
Reputation: 1683
You aren't using the ViewHolder pattern correctly. You have to create a ViewHolder and use the setTag and getTag to store the state of your item:
if (convertView == null) {
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Upvotes: 0