#android #android-listview
#Android #android-listview
Вопрос:
Я получаю данные из своей базы данных и помещаю их в ListView для просмотра всех данных.
Внутри моего ListView у меня также есть TextView с текстом «Like» в нем. Теперь, когда я нажимаю на текст «Нравится», он изменится на «Понравилось», и я обновляю свой статус «нравится» в своей базе данных.
Теперь моя проблема в том, что когда я нажимаю на текст «Нравится», текст меняется на «Понравилось», а также обновляется в БД. Но также, когда я прокручиваю просмотр списка, я могу заметить, что текст других списков «Нравится» также изменяется на «Нравится». Я не уверен, что происходит не так.
Я пытался обойти эту проблему в течение нескольких дней, но безуспешно.
Это мой код адаптера. Внизу вы можете увидеть мой OnClickListener для textview
package com.mytestapp.myapp;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class ForumAdapter extends ArrayAdapter<DiscussionList> {
private static List<DiscussionList> items = null;
public ForumAdapter(Context context, List<DiscussionList> items) {
super(context, R.layout.custom_list, items);
this.items = items;
}
@Override
public int getCount() {
return items.size();
}
public static DiscussionList getModelPosition(int position) {
return items.get(position);
}
public void refill(List<DiscussionList> items) {
items.clear();
items.addAll(items);
notifyDataSetChanged();
}
public static class ViewHolder {
WebView mywebviewholder;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View v = convertView;
if (v == null) {
LayoutInflater li = LayoutInflater.from(getContext());
v = li.inflate(R.layout.custom_list, null);
} else {
holder = (ViewHolder) convertView.getTag();
}
DiscussionList app = items.get(position);
if (app != null) {
TextView titleText = (TextView) v.findViewById(R.id.dscTitle);
TextView categoryText = (TextView) v.findViewById(R.id.dscCategory);
TextView descriptionText = (TextView) v
.findViewById(R.id.dscDescription);
TextView timeText = (TextView) v.findViewById(R.id.dscTime);
TextView idText = (TextView) v.findViewById(R.id.dscDiscId);
final TextView likeText = (TextView) v.findViewById(R.id.likeText1);
String like_Status = app.getLikeStatus();
titleText.setText(app.getTitle());
categoryText.setText(app.getCategory());
descriptionText.setText(app.getDescription());
timeText.setText(app.getTime());
idText.setText(app.getDiscId());
if (like_Status == "null") {
likeText.setText("Like");
} else {
likeText.setText("Liked");
}
final String dId = app.getDiscId();
// onClick for image button inside list view
likeText.setTag(new Integer(position));
likeText.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final Integer myposition = (Integer) view.getTag();
// Toast.makeText(getContext(), "" dId,
// Toast.LENGTH_SHORT)
// .show();
likeText.setText("Liked");
MainActivity val = new MainActivity();
val.updateLikeTable(dId);
}
});
}
return v;
}
}
А также это мой MainActivity.java файл, в котором я обновляю лайки в базе данных
package com.mytestapp.myapp;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends ListActivity implements FetchDataListener {
public static String strTitle = "0", strCategory = "0",
strDescription = "0", strTime = "0", strDid = "0";
Collegemate_DB db = new Collegemate_DB(this);
int likeStatus = 1;
private ProgressDialog dialog;
public static String usId=null;
ImageButton imgButton;
List<DiscussionList> items = new ArrayList<DiscussionList>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_forum_topics);
usId = db.getCurrentuserId();
initView();
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
}
/*
* On click listener to get values from DiscussionList class and send it
* to another activity when clicking on the list item
*/
ListView forumList = getListView();
forumList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// Get position of the clicked list item from adapter
String dTitle, dCategory, dDescription, dTime, dDid;
DiscussionList accessVar = ForumAdapter
.getModelPosition(position);
dTitle = accessVar.getTitle();
dCategory = accessVar.getCategory();
dDescription = accessVar.getDescription();
dTime = accessVar.getTime();
dDid = accessVar.getDiscId();
/*
* Storing the forum values in string and passing it to another
* activity
*/
String values[] = { dTitle, dCategory, dDescription, dTime,
dDid };
Intent i = new Intent(MainActivity.this, ForumFullView.class);
i.putExtra("sendData", values);
startActivity(i);
}
});
}
private void initView() {
// show progress dialog
Log.i("j","Inside Init");
dialog = ProgressDialog.show(this, "", "Loading...");
String url = "http://example.com/mypath/listData.php?currentUser_id="
usId;
Log.i("Fetch Url : ", url);
FetchDataTask task = new FetchDataTask(this);
task.execute(url);
}
@Override
public void onFetchComplete(List<DiscussionList> data) {
// dismiss the progress dialog
if (dialog != null)
dialog.dismiss();
// create new adapter
ListView forumList = getListView();
// set the adapter to list
ForumAdapter adapter = new ForumAdapter(this, data);
if (forumList.getAdapter() == null) {
//final ForumAdapter adapter = new ForumAdapter(this, data);
forumList.setAdapter(adapter);
} else {
((ForumAdapter) forumList.getAdapter()).refill(items);
}
// setListAdapter(adapter);
}
@Override
public void onFetchFailure(String msg) {
// dismiss the progress dialog
if (dialog != null)
dialog.dismiss();
// show failure message
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
public void updateLikeTable(String dId,List<DiscussionList> items) {
try {
String likeUrl = "http://example.com/mypath/createlike.php?discId="
dId "amp;userId=" usId "amp;like_status=" likeStatus;
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet();
request.setURI(new URI(likeUrl));
client.execute(request);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Любая помощь приветствуется.
Заранее спасибо
Ответ №1:
Проблема, с которой вы столкнулись, заключается в том, что ListView
виджет перерабатывает свои представления, если может. Как только вид исчезает с экрана при прокрутке, он попадает в мусорную кучу, так что, когда новый вид прокручивается на место, его можно использовать повторно, вместо того, чтобы создавать новый с нуля. Это переработанное представление является convertView
параметром в getView()
методе. При ListView
первом заполнении convertView
всегда будет null, поскольку в куче мусора ничего нет, поэтому вы вынуждены раздувать новые представления, но последующие вызовы, скорее всего, будут иметь этот параметр как ненулевой.
Практическим результатом этого является то, что когда просмотр по щелчку, для которого было установлено значение «Нравится», перерабатывается, TextView
он все еще существует и по-прежнему заполняется «Нравится», а не предполагаемое значение по умолчанию «Нравится». Поэтому, если вы нажмете на представление, затем прокрутите вниз, чтобы оно исчезло с экрана, оно вернется и вызовет ошибку, которую вы видите.
Что вы, вероятно, захотите сделать, чтобы исправить это likeText
getView()
, так это каждый раз устанавливать текст внутри, основываясь на том, что он есть в вашей базе данных. Если сообщение понравилось, установите для него значение «Понравилось», а если нет, установите для него значение «Нравится». Это должна быть просто еще одна строка, при условии, что у вас есть легкий доступ к тому, нравится ли сообщение вашему DiscussionList
объекту.
PS В качестве примечания, жестко закодированные строки обычно не одобряются в Android, поэтому вы можете захотеть переместить «понравившуюся» строку в файлы ресурсов. На самом деле в этом нет необходимости, если вы не планируете выполнять переводы, но это все равно хорошая практика.
Комментарии:
1. Да, спасибо за этот отличный ответ. Да, я могу установить текст liketext из самой базы данных при создании списка. Но что, когда пользователь хочет нажать «Нравится» для публикации, которая ему еще не понравилась? Теперь мой OnClickListener также находится только внутри моего getView(). Есть ли способ, которым я могу установить для текста значение «Понравилось» только для текущего элемента списка, на который я нажимаю? Или есть способ сообщить Android, чтобы он запоминал позицию listview, даже если он прокручивается?
2. Насколько я вижу, ваш прослушиватель кликов должен быть в полном порядке как есть.
position
Переменная ingetView()
будет абсолютной в наборе данных, и вы получаете / используете правильноеlikeText
значение anddId
. Ведет ли он себя не так, как ожидалось, и если да, то каково его текущее поведение?3. Привет, извините за поздний ответ. Мой текст «Нравится» и «Понравилось» теперь остается правильным после получения его из базы данных и отображения в текстовом представлении. Но теперь моя проблема в том, что когда я нажимаю на любой список, текст которого похож на «Нравится», он обновляется до «Нравится», но когда я прокручиваю вниз и возвращаюсь, он снова меняется на «Нравится». Я не знаю, что здесь не так.
4. Я также обновил свой файл адаптера в своем вопросе для вашей справки.
5. Ваш текст не обновляется должным образом, потому что вы обновляете не базовые данные вашего адаптера, а только базу данных. Если вы вызываете что-то с эффектом
app.setLikeStatus()
(независимо от того, что вы на самом деле назвали) в своем прослушивателе кликов, чтобы объект обновлялся одновременно с базой данных, это должно устранить проблему.