【问题标题】:android - identify items in a ListViewandroid - 识别 ListView 中的项目
【发布时间】:2013-03-01 15:18:19
【问题描述】:

我在正确识别 ListView 中的项目时遇到了一些问题。

有 4 个类很重要,代码量很大,所以我先解释一下这些类的逻辑。

  • 输入ListActivity并初始化其ListView
  • 执行一个AsyncTask,从服务器下载JSON响应,解析它,用对象填充ListView并设置适配器,同时显示ProgressDialog
  • PlaylistItem 类包括简单地从单个 JSONObject 获取数据的方法。它用于参数化 ArrayList 及其对象
    • AsyncTask 完成后,列表中充满了项目,看起来像 |Button|艺术家(TextView) - 标题(TextView)

更新

解决了第一个问题,但仍然无法弄清楚按钮出了什么问题

2)。我在适配器的 getView() 方法中为我的按钮设置了一个OnClickListener。为了确定按钮是否被正确识别,我什么也没做,只是改变了它的背景。但是单击某个按钮会强制更改每 11 个或第 12 个按钮的背景。目前还想不通。

在这些问题得到解决之前,我无法继续获取 url 和流式音频,因此非常感谢任何帮助。我的课在下面,如果有不清楚的地方请询问。

音频列表

         public class AudioList extends ListActivity {
private ListView lv;
private PlaylistLoader loader;
private AudioListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_audio_list);
    init(); // initialize the ListView

    /*--- populate the list with user's audio in case network connection is available ---*/
    loader = new PlaylistLoader(this, lv, adapter);
    if (Utils.isNetworkAvailable(this)) {
        loader.execute();
    } else {
        APP_CONSTANTS.NO_DATA_CONNECTION(this);
    }

}

@Override
protected void onResume() {
    super.onResume();
    lv.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                long arg3) {

            Toast.makeText(getApplicationContext(), Integer.toString(arg2),
                    Toast.LENGTH_SHORT).show();
            }
    });

}

private void init() {
    lv = getListView();
    lv.setTranscriptMode(0x00000000);
    lv.setDividerHeight(1);
    lv.setSmoothScrollbarEnabled(true);
    lv.setVerticalFadingEdgeEnabled(true);

}

播放列表加载器

      public class PlaylistLoader extends AsyncTask<Void, Void, Void> {

private JSONObject usersPlaylist, singleJSONItem;
private JSONArray responseJSONArray;
private ListView lv;
private ArrayList<PlaylistItem> playlist;
private Activity a;
private PlaylistItem audioList;
private SharedPreferences prefs;
private ProgressDialog pd;
AudioListAdapter adapter;

public PlaylistLoader(Activity a, ListView lv, AudioListAdapter adapter) {
    this.lv = lv;
    this.a = a;
    this.adapter = adapter;
}

@Override
protected Void doInBackground(Void... arg0) {
    /*--- create new ArrayList of PlaylistItem Objects ---*/
    playlist = new ArrayList<PlaylistItem>();
    /*--- get the preferences using context of calling activity ---*/
    prefs = PreferenceManager.getDefaultSharedPreferences(a);
    try {
        /*--- download the response JSONObject from server // access_token and 
         * user_id come from activity's defaultSharedPreferences ---*/
        usersPlaylist = Utils.retrieveJsonObjectFromUrl(new URL(
                APP_CONSTANTS.REQUEST_AUDIO_LIST(prefs)), a);
        /*--- get the response array from received object ---*/
        responseJSONArray = usersPlaylist.getJSONArray("response");
        /*--- populate the ArrayList with Objects from the response array ---*/
        for (int i = 0; i < responseJSONArray.length(); i++) {
            singleJSONItem = responseJSONArray.getJSONObject(i);
            audioList = new PlaylistItem(singleJSONItem);
            playlist.add(audioList);

        }

    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (JSONException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

@Override
protected void onPreExecute() {
    super.onPreExecute();
    pd = new ProgressDialog(a);
    pd.setTitle("Please wait");
    pd.setMessage("Retrieving audio list...");
    pd.show();

}

@Override
protected void onPostExecute(Void result) {
    super.onPostExecute(result);
    lv.setVisibility(View.VISIBLE);
    pd.dismiss();
    /*--- set the adapter passed in constructor as an adapter for passed ListView ---*/
    adapter = new AudioListAdapter(a, R.layout.playlist_item, playlist);
    lv.setAdapter(adapter);

}
    }

AudioListAdapter

           public class AudioListAdapter extends ArrayAdapter<PlaylistItem> {
private PlaylistItem pl;
private Context context;
private int layoutResourceId;
private PlaylistItem aud;
private ArrayList<PlaylistItem> data = null;

public AudioListAdapter(Context context, int layoutResourceId,
        ArrayList<PlaylistItem> data) {
    super(context, layoutResourceId, data);
    this.layoutResourceId = layoutResourceId;
    this.context = context;
    this.data = data;

}

@Override
public PlaylistItem getItem(int position) {
    return super.getItem(position);
}

@Override
public int getCount() {
    return data.size();
}

@Override
public int getPosition(PlaylistItem item) {
    return super.getPosition(item);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    pl = new PlaylistItem();
    aud = getItem(position);

    if (convertView == null) {
        LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        convertView = inflater.inflate(layoutResourceId, parent, false);
        pl.btnPlay = (Button) convertView.findViewById(R.id.btn_list_play);
        pl.imgSaved = (ImageView) convertView
                .findViewById(R.id.img_list_audio_saved);
        pl.tvArtist = (TextView) convertView
                .findViewById(R.id.tvListItemArtist);
        pl.tvTitle = (TextView) convertView
                .findViewById(R.id.tvListItemSong);

        convertView.setTag(pl);
    } else {
        pl = (PlaylistItem) convertView.getTag();
        pl.btnPlay.setBackgroundResource(R.drawable.list_button_play);
    }

    pl.tvArtist.setText(aud.getArtist() + " " + "-");
    pl.tvTitle.setText(aud.getTitle());

    pl.btnPlay.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            /*--- vibrate if this option is enabled in the preferences ---*/
            if (APP_CONSTANTS.isHapticFeedbackEnabled(getContext())) {
                APP_CONSTANTS.doVibrate(getContext());

            }
         pl.btnPlay.setBackgroundResource(R.drawable.list_button_pause);

        }
    });

    return convertView;
}

播放列表项

     public class PlaylistItem {

private String artist, title;
private JSONObject obj;
public Button btnPlay;
public TextView tvArtist, tvTitle;
public ImageView imgSaved;
public int duration;
public int audio_id;
public String url;

/*--- the constructor takes a single JSONObject from the response array ---*/
public PlaylistItem(JSONObject obj) {
    this.obj = obj;
}

public PlaylistItem() {
    // default constructor
}

/*--- the methods below return values by key from the passed JSONObject ---*/

public String getArtist() {
    try {
        artist = obj.getString("artist");
    } catch (JSONException e) {

        e.printStackTrace();
    }
    return artist;

}

public String getTitle() {
    try {
        title = obj.getString("title");
    } catch (JSONException e) {

        e.printStackTrace();
    }
    return title;
}

public int getID() {
    try {
        audio_id = obj.getInt("aid");
    } catch (JSONException e) {

        e.printStackTrace();
    }
    return audio_id;
}

public String getURL() {
    try {
        url = obj.getString("url");
    } catch (JSONException e) {

        e.printStackTrace();
    }
    return url;
}
    }

【问题讨论】:

  • 1) 你有没有对此做过任何研究......它只是在 ListView 行中有 Clickable 元素时发生......问了很多次...... 2) 也问了很多次...... ListView是一个智能控制......你必须理解它......youtube.com/watch?v=wDBM6wVEO70(如果你在getView中得到convertView - 你会有答案......)......无论如何......问题写得很好:)
  • 是的,我做到了。我看了这个视频。仍然找不到任何适合我的解决方案
  • heh 在 PlaylistItem 对象中存储播放列表状态(暂停/播放),然后根据 getView 中的此状态设置此可绘制对象 ...并且在 onClick 中仅在选定的 PlayListItem 中设置此状态
  • @Selvin 谢谢你的建议,我试试看
  • 无论如何你确定你使用同一个类PlaylistItem作为适配器数据和视图持有者?

标签: android android-listview android-asynctask


【解决方案1】:

编辑

试试这个

在您的可绘制对象中使用自定义选择器 button_play.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/pause_button"
          android:state_selected="true" />
    <item android:drawable="@drawable/play_button" />
</selector>

像这样修改你的适配器

 public class AudioListAdapter extends ArrayAdapter<PlaylistItem> {
private PlaylistItem pl;
private Context context;
private int layoutResourceId;
private PlaylistItem aud;
private ArrayList<PlaylistItem> data = null;
Button previous;

public AudioListAdapter(Context context, int layoutResourceId,
        ArrayList<PlaylistItem> data) {
    super(context, layoutResourceId, data);
    this.layoutResourceId = layoutResourceId;
    previous=new Button(context);
    this.context = context;
    this.data = data;

}

....
....

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    pl = new PlaylistItem();
    aud = getItem(position);

    if (convertView == null) {
        LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        convertView = inflater.inflate(layoutResourceId, parent, false);
        pl.btnPlay = (Button) convertView.findViewById(R.id.btn_list_play);
pl.btnPlay.setBackGroundResouce(R.drawable.button_play); //you can set here or in xml

        pl.imgSaved = (ImageView) convertView
                .findViewById(R.id.img_list_audio_saved);
        pl.tvArtist = (TextView) convertView
                .findViewById(R.id.tvListItemArtist);
        pl.tvTitle = (TextView) convertView
                .findViewById(R.id.tvListItemSong);

        convertView.setTag(pl);
    } else {
        pl = (PlaylistItem) convertView.getTag();
    }


    pl.tvArtist.setText(aud.getArtist() + " " + "-");
    pl.tvTitle.setText(aud.getTitle());

    pl.btnPlay.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            /*--- vibrate if this option is enabled in the preferences ---*/
            if (APP_CONSTANTS.isHapticFeedbackEnabled(getContext())) {
                APP_CONSTANTS.doVibrate(getContext());
            }
                //for some reason, the background gets changed for every 11th or 12th button in the list
             Button current=((Button)v);
              current.setSelected(true);
              previous.setSelected(false);
              previous=current;
        }
    });

    return convertView;
}

    }

您的按钮和列表项不可点击的原因是因为您的列表有一个焦点项目按钮,因此您需要为您的按钮设置setFocusable=false。 尝试在 xml 中为您的按钮设置 focusable=false。如果它不适合你,那就这样做

在你的行 xml 文件中

1.为您的按钮设置 focusable=true。 2.在同一组android:descendantFocusability="blocksDescendants" 中为您的父项。(即您的视图所在的父布局)。

在getView()方法中设置按钮的onclickListener后,为按钮设置focusable false。 它肯定会起作用。我希望这会对你有所帮助..

【讨论】:

  • 它在previous.setSelected(false) 行崩溃;我猜这是因为按钮没有初始化
  • 你必须在构造函数中初始化它... previous=new Button(context);
【解决方案2】:

但是单击某个按钮会强制每 11 个或第 12 个按钮更改背景。目前还想不通。

您正在与 ListView 回收行布局的方式作斗争。
这样想:如果你有一个有 10,000 行的 ListView,但屏幕上只能容纳其中的 9 个,那么创建 10,000 个独特的布局是没有意义的。这只是浪费资源,而 ListView 只创建约 10 个布局并重用它们。

解决方案:重复使用时将每一行恢复为默认状态。在getView() 添加:

} else {
    pl = (PlaylistItem) convertView.getTag();
    pl.btnPlay.setBackgroundResource(R.drawable.list_button_play);
    // I guessed at the resource's name         ^^^^^^^^^^^^^^^^
}

(你也可以做一些小的改动来加速你的代码。例如,你只需要一个 OnClickListener 因为它们都包含相同的代码,让它成为一个类变量并将它传递给每个播放按钮。还有更多.)

【讨论】:

  • 刚刚添加了。现在列表的行为非常奇怪,当我单击一个按钮时,它会更改列表中其他按钮的背景或根本没有任何操作。我想我需要一种方法将每个按钮连接到相应位置的 PlaylistItem 对象。由于单击按钮应导致从相应的 PlaylistItem 对象获取 url 并开始播放。虽然没有单击其他按钮,但即使用户向上或向下滚动,当前按钮也应该具有可绘制的暂停。..
  • 请使用getView() 中的当前代码更新您的问题,以便我查看发生了什么。
  • 这张截图显示了我需要的几乎相同的东西cs407217.vk.me/v407217837/7b9b/H9d7TKat74M.jpg
  • onClick() 内部你仍然需要使用v.setBackgroundResource(R.drawable.list_button_pause);(也许你误解了我回答中的最后一条评论。)
  • 我这样做了,请检查更新后的 getView();现在它将其他按钮的背景设置为暂停,并在该按钮因滚动而变得不可见时将其设置为播放
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多