Reputation: 6606
I have a list adapter using a viewholder pattern, my problem is I need to update a TextView from the viewholder in onpostexecute() of an AsyncTask contained within the same class, but this always returns a nullpointer on the TextView, how can give my textviews from the viewholder enough scope that I can change them in teh AsyncTask? I will include a code example below, thanks in adcvance
public class ListAdapter extends BaseAdapter {
TextView tvA1, tvA2;
Integer submitId;
String submitQuestion;
public ListAdapter() {
....
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
friendsViewHolder holder = null;
if (convertView == null) {
holder = new friendsViewHolder();
convertView = inflater.inflate(R.layout.list_item_status, null);
holder.tvA1 = (TextView) convertView
.findViewById(R.id.tvA1);
holder.tvA2 = (TextView) convertView
.findViewById(R.id.tvA2);
holder.btQ1 = (LinearLayout) convertView
.findViewById(R.id.btConfirm);
holder.btQ2 = (LinearLayout) convertView
.findViewById(R.id.btDeny);
convertView.setTag(holder);
} else {
holder = (friendsViewHolder) convertView.getTag();
}
tvA1 = holder.tvA1;
tvA2 = holder.tvA2;
holder.btQ1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
submitId = id;
submitQuestion = q1;
new UpdateAnswer().execute();
}
});
holder.btQ2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
submitId = id;
submitQuestion = q2;
new UpdateAnswer().execute();
}
});
return convertView;
}
static class friendsViewHolder {
TextView tvA1, tvA2;
LinearLayout btQ1, btQ2;
}
private class UpdateAnswer extends AsyncTask<Void, Void, ArrayList<Object>> {
@Override
protected ArrayList<Object> doInBackground(Void... params) {
return apiHelper.submitAnswer(submitId, submitQuestion);
}
@Override
protected void onPostExecute(ArrayList<Object> answers) {
super.onPostExecute(answers);
if (answers != null) {
Integer a1 = (Integer) answers.get(1);
Integer a2 = (Integer) answers.get(2);
//Error here
tvA1.setText(a1);
tvA1.setVisibility(View.VISIBLE);
//error here
tvA2.setText(a2);
tvA2.setVisibility(View.VISIBLE);
}
}
}
}
Upvotes: 1
Views: 186
Reputation: 1496
Lets change few things here and there :)
Lets make friendsViewHolder public, also i need to add that in java it is somehow custom to name classes with names starting with cammel case simply put FirstLetterOfEeachWordIsBig :)
Lets add constructor to Update task :)
private class UpdateAnswer extends AsyncTask<Void, Void, ArrayList<Object>> {
int submitId;
String submitQuestion;
friendsViewHolder holder;
public UpdateAnswer (int submitId, String submitQuestion, friendsViewHolder holder) {
this.submitId = submitId;
this.submitQuestion = submitQuestion;
this.holder = holder;
}
On click lets change to
final frendsViewHolder finalHolder = holder;
holder.btQ1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new UpdateAnswer(id, q1, finalHolder).execute();
}
});
We are no longer in need of global TvA1, tvA2, submitId, submitQuestion;
And lastly we need to edit onPostExecute, hovewer i think that want be so hard since you have holder value forwarded :)
holder.tvA1.setText(a1);
holder.tvA1.setVisibility(View.VISIBLE);
holder.tvA2.setText(a2);
holder.tvA2.setVisibility(View.VISIBLE);
In java you can create constructor to allow passing additional data to object, we use this to set id, question and holder for our task, and for passing that information to other object we should'nt be using global values (they can be changed by every process), think about situation when your call "apiHelper.submitAnswer(submitId, submitQuestion)" would take long to proceed (half a second for example), then user click within half a second on answer in first and answer c on 3 question, by passing values globally you cant determine wich answer to accept :)
Cheers :)
Upvotes: 1
Reputation: 2130
Java is pass by value, but you can send reference of an Object in the value. I have used the above, and sent reference of holder to AsyncTask.
public class ListAdapter extends BaseAdapter {
TextView tvA1, tvA2;
Integer submitId;
String submitQuestion;
public ListAdapter() {
....
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
friendsViewHolder holder = null;
if (convertView == null) {
holder = new friendsViewHolder();
convertView = inflater.inflate(R.layout.list_item_status, null);
holder.tvA1 = (TextView) convertView
.findViewById(R.id.tvA1);
holder.tvA2 = (TextView) convertView
.findViewById(R.id.tvA2);
holder.btQ1 = (LinearLayout) convertView
.findViewById(R.id.btConfirm);
holder.btQ2 = (LinearLayout) convertView
.findViewById(R.id.btDeny);
convertView.setTag(holder);
} else {
holder = (friendsViewHolder) convertView.getTag();
}
holder.btQ1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
submitId = id;
submitQuestion = q1;
new UpdateAnswer(holder).execute();
}
});
holder.btQ2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
submitId = id;
submitQuestion = q2;
new UpdateAnswer().execute();
}
});
return convertView;
}
static class friendsViewHolder {
TextView tvA1, tvA2;
LinearLayout btQ1, btQ2;
}
private class UpdateAnswer extends AsyncTask<Void, Void, ArrayList<Object>> {
friendsViewHolder holder;
UpdateAnswer(friendsViewHolder holder)
{
this.holder = holder;
}
@Override
protected ArrayList<Object> doInBackground(Void... params) {
return apiHelper.submitAnswer(submitId, submitQuestion);
}
@Override
protected void onPostExecute(ArrayList<Object> answers) {
super.onPostExecute(answers);
if (answers != null) {
Integer a1 = (Integer) answers.get(1);
Integer a2 = (Integer) answers.get(2);
//Error here
holder.tva1.setText(a1);
holder.tva1.setVisibility(View.VISIBLE);
//error here
holder.tva2.setText(a2);
holder.tva2.setVisibility(View.VISIBLE);
}
}
}
}
Upvotes: 1