Текущая позиция просмотра списка Android не работает должным образом

#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 Переменная in getView() будет абсолютной в наборе данных, и вы получаете / используете правильное likeText значение and dId . Ведет ли он себя не так, как ожидалось, и если да, то каково его текущее поведение?

3. Привет, извините за поздний ответ. Мой текст «Нравится» и «Понравилось» теперь остается правильным после получения его из базы данных и отображения в текстовом представлении. Но теперь моя проблема в том, что когда я нажимаю на любой список, текст которого похож на «Нравится», он обновляется до «Нравится», но когда я прокручиваю вниз и возвращаюсь, он снова меняется на «Нравится». Я не знаю, что здесь не так.

4. Я также обновил свой файл адаптера в своем вопросе для вашей справки.

5. Ваш текст не обновляется должным образом, потому что вы обновляете не базовые данные вашего адаптера, а только базу данных. Если вы вызываете что-то с эффектом app.setLikeStatus() (независимо от того, что вы на самом деле назвали) в своем прослушивателе кликов, чтобы объект обновлялся одновременно с базой данных, это должно устранить проблему.