Syed Sehu Mujammil A
Syed Sehu Mujammil A

Reputation: 875

Android list view current position doesn't work properly

I'm Getting data from my database and pushing them into ListView to view all the data.

Inside my ListView I also have a TextView with the text "Like" in it. Now when I click the like text it will change to "Liked" and I'm updating my like status in my database.

Now my problem is that when i click the "Like" text, the text changes to "Liked" and also it is updated in DB. But also when I scroll through the List View, I can notice other lists' Like text is also changed to Liked. I'm not sure what's going wrong.

I've been trying to get around this problem for quite some days but had no success.

This is my adapter code. At the bottom you can see my onClickListener for the 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;
    }
}

And also this is my MainActivity.java file where i update the likes in database

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 + "&userId=" + usId + "&like_status=" + likeStatus;
            HttpClient client = new DefaultHttpClient();
            HttpGet request = new HttpGet();
            request.setURI(new URI(likeUrl));
            client.execute(request);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Any help is appreciated.

Thanks in advance

Upvotes: 0

Views: 820

Answers (1)

Alex
Alex

Reputation: 990

The problem you're having is that the ListView widget recycles its views if it can. Once a view is off the screen from scrolling, it goes onto a garbage heap so that when a new view scrolls into place it can be reused, rather than requiring a fresh one to be inflated from scratch. That recycled view is the convertView parameter in the getView() method. When your ListView is first populating, convertView will always be null, since the garbage pile has nothing in it, so you're forced to inflate new views, but subsequent calls will likely have that parameter as non-null.

The practical result of this is that when a clicked view that's been set to "Liked" gets recycled, the TextView is still there and still populated with "Liked" rather than the presumed default of "Like". So if you click a view, then scroll down so it goes off the screen, it'll come back around and cause the bug you're seeing.

What you'll probably want to do to fix this is to set the text of likeText within getView() every time, based on what it is in your database. If the post has been liked, set it to "Liked", and if it hasn't, set it to "Like". It should just be one more line, assuming you have easy access to whether or not the post is liked from your DiscussionList object.

P.S. As a side note, hard-coded strings are typically frowned upon in Android, so you may want to move your "Liked" string into the resource files. It's not really necessary unless you're planning to do translations, but it's still good practice.

Upvotes: 1

Related Questions