对 getTag() 感到困惑
Confused about getTag()
我才刚刚开始学习 Java 和编程。我在这里学习了一个教程:http://code.tutsplus.com/tutorials/create-a-music-player-on-android-song-playback--mobile-22778
但是现在我已经被困了几个小时!!!请帮助
它运行良好,我还通过使用 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;
}
}
现在唯一的问题是当我点击要播放的歌曲时,它崩溃了。我认为是由于 setTag() 弄乱了我的这部分代码。 songPicked 是在 xml 布局 song.xml 中使用 onClick 标记创建的方法。
public void songPicked(View view){
musicSrv.setSong(Integer.parseInt(view.getTag().toString()));
musicSrv.playSong();
}
这是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.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.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.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
或其派生词使用 Adapters
,它会更容易,而使用 ArrayAdapter
几乎可笑地容易,因为视图是为您存储的,并且可以获取索引yourArrayAdapter.getPosition(T item);
.
最好明确声明并知道您将收到什么,并利用 java 使用的类型系统。
感谢 krishnas 的评论,我意识到我已经从原始教程的 getView 方法中删除了它:
songLay.setTag(position);
return songLay;
}
Uggg 太烦人了,我花了 3 个小时。但是这些论坛非常棒,回复速度超快!
在您的适配器中,有一个函数 getItem(position) 当前 returning null。使用该功能 return 您点击的列表项的详细信息。例如你的 getItem 函数应该是这样的。
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return songs.get(arg0);
}
标签的概念是,如果您在每个项目列表中都有一个按钮,并且您将 onclicklistener 添加到该按钮,那么您就可以做到
yourButton.setTag(position);
并且在您点击该按钮时,您可以将位置检索为
yourButton.getTag();
此 returned 位置将是列表中按钮被单击的行的位置。
看看对你有没有帮助!!!
所以 setTag 是一种方便的方法,所有视图都可以保存任意引用:实际上,您可以保存任意数量,前提是您使用重载方法,并为标签分配一个 id 的额外参数。
即 mView.setTag(mFirstObject);
使用隐式标签 ID,而 mView.setTag(R.id.tag1, mSecondObject);
使用显式 R.id.tag1
标签 ID。
要检索 mFirstObject
然后使用语句 Object first = mView.getTag();
并检索 mSecondObject
然后调用将是 Object second = mView.getTag(R.id.tag1);
(注意这里我假设它们都是对象,因此不需要投射它们)。
代码正在崩溃,因为您没有在哪里使用隐式 ID 分配标签。你必须做一些事情,比如,对于你分配的任何视图 android:onClick='songPicked'
你必须做的:
@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());
/* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
holder.viewWithOnClick=songPickedInXml.setTag(currSong.getId());
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
return songLay;
}
}
其中 holder.viewWithOnClick=songPickedInXml
是具有相应 onClick 属性的视图引用。 void songPicked(View view)
中的 View view
参数是为其定义了 onClick
的视图。例如,如果它是一个按钮,您可以将 view
转换为按钮而不会崩溃;如果你试图将它投射到图像视图,它会崩溃。
但是,我强烈建议您不要将 onClick 特别用于列表视图项目。假设用户可以单击整行来播放歌曲,只需在列表视图上使用 ItemClickListener,然后在 LinearLayout songLay 上执行 setTag(currSong.getId());它应该工作。不使用 onClick 的原因——特别是在这种情况下——是因为它在 运行 时间引用哪个视图是完全不明确的。
Doh--每个人都比我先到达那里,但仅供参考,你可以随心所欲地推,而不仅仅是位置,如果你愿意,还可以推整个 uri!
至于setTag,想怎么用就怎么用!对于这样的事情,这是一种方便的方法。请记住,该视图将保留对您放入标签桶中的任何内容的引用,因此不要在其中放置任何会超过父 activity 生命周期的内容,以免泄漏内存!
我才刚刚开始学习 Java 和编程。我在这里学习了一个教程:http://code.tutsplus.com/tutorials/create-a-music-player-on-android-song-playback--mobile-22778 但是现在我已经被困了几个小时!!!请帮助
它运行良好,我还通过使用 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;
}
}
现在唯一的问题是当我点击要播放的歌曲时,它崩溃了。我认为是由于 setTag() 弄乱了我的这部分代码。 songPicked 是在 xml 布局 song.xml 中使用 onClick 标记创建的方法。
public void songPicked(View view){
musicSrv.setSong(Integer.parseInt(view.getTag().toString()));
musicSrv.playSong();
}
这是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.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.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.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
或其派生词使用 Adapters
,它会更容易,而使用 ArrayAdapter
几乎可笑地容易,因为视图是为您存储的,并且可以获取索引yourArrayAdapter.getPosition(T item);
.
最好明确声明并知道您将收到什么,并利用 java 使用的类型系统。
感谢 krishnas 的评论,我意识到我已经从原始教程的 getView 方法中删除了它:
songLay.setTag(position);
return songLay;
}
Uggg 太烦人了,我花了 3 个小时。但是这些论坛非常棒,回复速度超快!
在您的适配器中,有一个函数 getItem(position) 当前 returning null。使用该功能 return 您点击的列表项的详细信息。例如你的 getItem 函数应该是这样的。
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return songs.get(arg0);
}
标签的概念是,如果您在每个项目列表中都有一个按钮,并且您将 onclicklistener 添加到该按钮,那么您就可以做到
yourButton.setTag(position);
并且在您点击该按钮时,您可以将位置检索为
yourButton.getTag();
此 returned 位置将是列表中按钮被单击的行的位置。
看看对你有没有帮助!!!
所以 setTag 是一种方便的方法,所有视图都可以保存任意引用:实际上,您可以保存任意数量,前提是您使用重载方法,并为标签分配一个 id 的额外参数。
即 mView.setTag(mFirstObject);
使用隐式标签 ID,而 mView.setTag(R.id.tag1, mSecondObject);
使用显式 R.id.tag1
标签 ID。
要检索 mFirstObject
然后使用语句 Object first = mView.getTag();
并检索 mSecondObject
然后调用将是 Object second = mView.getTag(R.id.tag1);
(注意这里我假设它们都是对象,因此不需要投射它们)。
代码正在崩溃,因为您没有在哪里使用隐式 ID 分配标签。你必须做一些事情,比如,对于你分配的任何视图 android:onClick='songPicked'
你必须做的:
@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());
/* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
holder.viewWithOnClick=songPickedInXml.setTag(currSong.getId());
/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
return songLay;
}
}
其中 holder.viewWithOnClick=songPickedInXml
是具有相应 onClick 属性的视图引用。 void songPicked(View view)
中的 View view
参数是为其定义了 onClick
的视图。例如,如果它是一个按钮,您可以将 view
转换为按钮而不会崩溃;如果你试图将它投射到图像视图,它会崩溃。
但是,我强烈建议您不要将 onClick 特别用于列表视图项目。假设用户可以单击整行来播放歌曲,只需在列表视图上使用 ItemClickListener,然后在 LinearLayout songLay 上执行 setTag(currSong.getId());它应该工作。不使用 onClick 的原因——特别是在这种情况下——是因为它在 运行 时间引用哪个视图是完全不明确的。
Doh--每个人都比我先到达那里,但仅供参考,你可以随心所欲地推,而不仅仅是位置,如果你愿意,还可以推整个 uri!
至于setTag,想怎么用就怎么用!对于这样的事情,这是一种方便的方法。请记住,该视图将保留对您放入标签桶中的任何内容的引用,因此不要在其中放置任何会超过父 activity 生命周期的内容,以免泄漏内存!