Java 对getTag()感到困惑

Java 对getTag()感到困惑,java,android,listview,Java,Android,Listview,我刚刚开始学习Java和编程。我在这里学习了一个教程: 但现在我已经被困了几个小时!!!请帮忙 它工作得很好,我还通过使用ViewHolder模式优化了ListView,这是一个额外的挑战 public class SongAdapter extends BaseAdapter { private ArrayList<Song> songs; private LayoutInflater songInf; public SongAdapter(Contex

我刚刚开始学习Java和编程。我在这里学习了一个教程: 但现在我已经被困了几个小时!!!请帮忙

它工作得很好,我还通过使用ViewHolder模式优化了ListView,这是一个额外的挑战

public class SongAdapter extends BaseAdapter {

    private ArrayList<Song> songs;
    private LayoutInflater songInf;

    public SongAdapter(Context c, ArrayList<Song> theSongs) {
        songs = theSongs;
        songInf = LayoutInflater.from(c);
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return songs.size();
    }

    @Override
    public Object getItem(int arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public long getItemId(int arg0) {
        // TODO Auto-generated method stub
        return 0;
    }

    class ViewHolder{

        TextView songView;
        TextView artistView;

    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        LinearLayout songLay = (LinearLayout)convertView;

        if (songLay == null) {

            songLay = (LinearLayout) songInf.inflate
                    (R.layout.song, parent, false);
            //get view holder instance
            holder = new ViewHolder();

            //populate viewholder with artist and text views

            holder.songView = (TextView) songLay.findViewById(R.id.song_title);
            holder.artistView = (TextView) songLay.findViewById(R.id.song_artist);

            songLay.setTag(R.string.TAG1,holder);
        }
        else {
           holder = (ViewHolder) songLay.getTag(R.string.TAG1);
        }

        //get song using position
        Song currSong = songs.get(position);

        //get title and artist strings
        holder.songView.setText(currSong.getSongTitle());
        holder.artistView.setText(currSong.getArtist());

        return songLay;
    }
}
这是MusicService.java中的相关代码

public void setSong(int songIndex){
    songPosn = songIndex;
}

public void playSong(){
    //play a song
    player.reset();
    //get song
    MainActivity.Song playSong = songs.get(songPosn);
    //get ID
    long currSong = playSong.getID();
    //set uri
    Uri trackUri = ContentUris.withAppendedId(
            MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,currSong);
    try{
        player.setDataSource(getApplicationContext(), trackUri);
    }
    catch(Exception e){
        Log.e("MUSIC SERVICE", "Error setting data source", e);
    }

    player.prepareAsync();
}
我得到一个例外:

03-15 01:49:21.065  14179-14179/com.example.mediaplayertut E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.IllegalStateException: Could not execute method of the activity
            at android.view.View$1.onClick(View.java:3838)
            at android.view.View.performClick(View.java:4475)
            at android.view.View$PerformClick.run(View.java:18786)
            at android.os.Handler.handleCallback(Handler.java:730)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:176)
            at android.app.ActivityThread.main(ActivityThread.java:5419)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.reflect.InvocationTargetException
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at android.view.View$1.onClick(View.java:3833)
            at android.view.View.performClick(View.java:4475)
            at android.view.View$PerformClick.run(View.java:18786)
            at android.os.Handler.handleCallback(Handler.java:730)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:176)
            at android.app.ActivityThread.main(ActivityThread.java:5419)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.NullPointerException
            at com.example.mediaplayertut.MainActivity.songPicked(MainActivity.java:152)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at android.view.View$1.onClick(View.java:3833)
            at android.view.View.performClick(View.java:4475)
            at android.view.View$PerformClick.run(View.java:18786)
            at android.os.Handler.handleCallback(Handler.java:730)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:176)
            at android.app.ActivityThread.main(ActivityThread.java:5419)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
            at dalvik.system.NativeStart.main(Native Method)

我曾经发现自己想要使用标记属性作为视图的一种方便方法。从那以后,我决定,如果您使用标记属性作为一种方便的方法,那么您没有做错,但是通常有一种更优雅的解决方法

在您的例子中,我将使用静态视图数组,并引用数组中视图的索引来访问该视图的索引。如果您使用
适配器使用
ListView
或其衍生产品,那么使用
ArrayAdapter
就更容易了,而且使用
ArrayAdapter
几乎是可笑的简单,因为视图是为您存储的,您可以使用
yourArrayAdapter.getPosition(T项)获取索引


最好明确声明并知道您将接收到什么,并利用java使用的类型系统。

多亏了krishnas的评论,我意识到我已经从原始教程中的getView方法中删除了以下内容:

songLay.setTag(position);
  return songLay;
}

真烦人,我花了3个小时在上面。但是这些论坛的反应非常快,非常棒

在适配器中,有一个函数getItem(position)当前返回null。使用该函数返回单击的列表项详细信息。例如,getItem函数应该是这样的

@Override
public Object getItem(int arg0) {
    // TODO Auto-generated method stub
    return songs.get(arg0);
}
标记的概念是,如果在每个项目列表中都有一个按钮,并将onclicklistener添加到该按钮,那么您就可以这样做

yourButton.setTag(position);
在点击该按钮时,您可以按如下方式检索位置:

yourButton.getTag();
返回的位置将是列表中单击其按钮的行的位置


看看它是否对你有帮助

因此setTag是所有视图用来保存任意引用的一种方便方法:事实上,您可以保存任意数量的引用,只要您使用重载方法,并使用额外的参数为标记分配id

mView.setTag(mFirstObject)
使用隐式标记id和
mView.setTag(R.id.tag1,mSecondObject)使用显式的
R.id.tag1
标记id

要检索
mFirstObject
,首先使用语句
Object=mView.getTag()
和要检索
mSecondObject
,则调用将是
objectsecond=mView.getTag(R.id.tag1)(注意这里我假设这两个都是对象,因此不需要强制转换它们)

代码正在崩溃,因为没有使用隐式id分配标记的位置。对于分配的任何视图,您都必须执行以下操作:


@凌驾
公共视图getView(int位置、视图转换视图、视图组父视图){
视窗座;
LinearLayout songLay=(LinearLayout)convertView;
if(songLay==null){
songLay=(LinearLayout)songInf.充气(R.layout.song,父项,false);
//获取视图持有者实例
holder=新的ViewHolder();
//使用艺术家视图和文本视图填充viewholder
holder.songView=(TextView)songLay.findViewById(R.id.song\u title);
holder.artistView=(TextView)songLay.findViewById(R.id.song\u艺术家);
songLay.setTag(R.string.TAG1,支架);
}
否则{
holder=(ViewHolder)songLay.getTag(R.string.TAG1);
}
//使用位置获取歌曲
Song currSong=songs.get(位置);
//获取标题和艺术家字符串
holder.songView.setText(currSong.getSongTitle());
holder.artistView.setText(currSong.getArtist());
/*VVVVVVVVVVVV*/
holder.viewWithOnClick=songPickedInXml.setTag(currSong.getId());
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
返回宋雷;
}
}

其中
holder.viewWithOnClick=songPickedInXml
是具有相应onClick属性的视图引用。
void(视图视图)
中的
View视图
参数是定义了
onClick
的视图。例如,如果它是一个按钮,您可以将
视图
投射到按钮,而不会使其崩溃;如果您试图将其强制转换为imageview,它将崩溃

但是,我强烈建议您不要特别针对listview项使用onClick。假设用户可以单击整行播放歌曲,只需在listview上使用ItemClickListener,然后在LinearLayout songLay do setTag(currSong.getId())上使用ItemClickListener即可;它应该会起作用。不使用onClick的原因——特别是在本例中——是因为它在运行时引用的视图完全不明确

Doh——每个人都比我先到,但仅供参考,你可以随意推,不只是位置,而是整个uri,如果你喜欢的话


至于使用setTag,请随意使用它!这是一个方便的方法,正是这样的东西。请记住,视图将保留对您放入标记桶中的任何内容的引用,因此不要在其中放入任何超出父活动生命周期的内容,以免泄漏内存

getTag()你在哪里设置了该视图的标记?据我所知,我没有。这是一件让我困惑的事情。它是通过XMLOnClick自动设置的吗?据我所知,如果不在视图上设置标记。盖塔格会还给你的null@CarsonH你能告诉我你是怎么称呼歌曲精选法的吗?谢谢你帮我找到了答案!!!我试试这个。我读了一些其他的评论,标签很容易被忽略。@CarsonH,没错。最好明确声明并知道将接收到什么,并利用java使用的系统类型。
yourButton.getTag();