Android 片段内的音乐播放器

Android Music Player inside a fragment

我正在实现一个音乐播放器应用程序。我能够从 SD 卡中获取歌曲。但是几个小时后卡住了,即我无法让歌曲在片段中播放。

这里是 MainActivity class,它有 3 个选项卡片段。

public class MainActivity extends AppCompatActivity {

private final String[] TITLES = {"Now playing", "Library", "Groups"};
private static boolean isInForeground = false;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //if (savedInstanceState == null) {}

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    // Initialize the ViewPager and set an adapter
    ViewPager pager = (ViewPager) findViewById(R.id.pager);
    pager.setAdapter(new PagerAdapter(getSupportFragmentManager(), getBaseContext()));

    // Bind the tabs to the ViewPager
    PagerSlidingTabStrip tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
    tabs.setShouldExpand(true);
    tabs.setViewPager(pager);

    //Whenever the user changes tab, we want the title to change too
    tabs.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageScrollStateChanged(int arg0) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onPageSelected(int position) {
            setTitle(TITLES[position]);
        }

    });

    //We want to have the library as default view
    pager.setCurrentItem(1);
    setTitle(TITLES[1]);

}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

/**
 * A placeholder fragment containing a simple view.
 */
public static class MainFragment extends Fragment {

    public MainFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_song_library, container, false);

        return view;
    }
}

public class PagerAdapter extends FragmentPagerAdapter
        implements PagerSlidingTabStrip.CustomTabProvider {

    private ArrayList<Integer> tab_icon = new ArrayList<Integer>();

    Context myContext;

    public PagerAdapter(FragmentManager fm, Context context) {
        super(fm);

        myContext = context;
        tab_icon.add(context.getResources().getIdentifier("ic_play_arrow_white_36dp", "drawable", context.getPackageName()));
        tab_icon.add(context.getResources().getIdentifier("ic_list_white_36dp", "drawable", context.getPackageName()));
        tab_icon.add(context.getResources().getIdentifier("ic_group_white_36dp", "drawable", context.getPackageName()));
    }



    @Override
    public CharSequence getPageTitle(int position) {
        return TITLES[position];
    }

    @Override
    public int getCount() {
        return TITLES.length;
    }

    @Override
    public Fragment getItem(int position) {

        if(position == 0){
            return SongNowPlayingFragment.newInstance();
        } else if (position == 1){
            return SongLibraryFragment.newInstance();
        } else if(position == 2){
            return GroupFragment.newInstance();
        }

        System.err.println("Invalid tab fragment!");
        return new Fragment();
    }

    @Override
    public View getCustomTabView(ViewGroup viewGroup, int position) {

        LinearLayout imageView = (LinearLayout) LayoutInflater.from(myContext)
                .inflate(R.layout.tab_layout, null, false);

        ImageView tabImage = (ImageView) imageView.findViewById(R.id.tabImage);
        tabImage.setImageResource(tab_icon.get(position));

        return imageView;
    }
}

@Override
protected void onResume()
{
    super.onResume();
    isInForeground = true;
}


@Override
protected void onPause()
{
    super.onPause();
    isInForeground  = false;
}

static boolean isInForeground(){
    return isInForeground;
}
}

这是我从用户设备添加歌曲的 SongLibraryFragment。现在我想播放那些歌曲。

public class SongLibraryFragment extends Fragment implements MediaPlayerControl {

private ArrayList<SongItem> songList;
private ListView songView;

private MusicService musicSrv;
private Intent playIntent;
private boolean musicBound=false;

private MusicController controller;
private boolean paused=false, playbackPaused=false;
private MainActivity mainActivity = null;

public static SongLibraryFragment newInstance() {
    SongLibraryFragment f = new SongLibraryFragment();
    Bundle b = new Bundle();
    f.setArguments(b);
    return f;
}



@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_song_library, container, false);

    return rootView;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mainActivity = (MainActivity) SongLibraryFragment.this.getActivity();
    songView = (ListView) getView().findViewById(R.id.library_song_list);
    songList = new ArrayList<SongItem>();
    getSongList();
    SongAdapter songAdt = new SongAdapter(getActivity(), songList);
    songView.setAdapter(songAdt);

    Collections.sort(songList, new Comparator<SongItem>() {
        public int compare(SongItem a, SongItem b) {
            return a.getTitle().compareTo(b.getTitle());
        }
    });

    setController();
}
    //connect to the service
    private ServiceConnection musicConnection = new ServiceConnection(){

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            MusicBinder binder = (MusicBinder)service;
            //get service
            musicSrv = binder.getService();
            //pass list
            musicSrv.setList(songList);
            musicBound = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            musicBound = false;
        }
    };



@Override
public void onStart() {
    super.onStart();
    if(playIntent==null){
        playIntent = new Intent(getActivity(), MusicService.class);
        this.getActivity().bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
        this.getActivity().startService(playIntent);
    }
}

public void songPicked(View view){
    musicSrv.setSong(Integer.parseInt(view.getTag().toString()));
    musicSrv.playSong();
    if(playbackPaused){
        setController();
        playbackPaused=false;
    }
    controller.show(0);
}

public void getSongList() {
    //retrieve song info
    ContentResolver musicResolver = getActivity().getContentResolver();
    Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
    Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);

    if(musicCursor!=null && musicCursor.moveToFirst()){
        //get columns
        int titleColumn = musicCursor.getColumnIndex
                (android.provider.MediaStore.Audio.Media.TITLE);
        int idColumn = musicCursor.getColumnIndex
                (android.provider.MediaStore.Audio.Media._ID);
        int artistColumn = musicCursor.getColumnIndex
                (android.provider.MediaStore.Audio.Media.ARTIST);
        //add songs to list
        do {
            long thisId = musicCursor.getLong(idColumn);
            String thisTitle = musicCursor.getString(titleColumn);
            String thisArtist = musicCursor.getString(artistColumn);
            songList.add(new SongItem(thisId, thisTitle, thisArtist));
        }
        while (musicCursor.moveToNext());
    }

}

@Override
public boolean canPause() {
    return true;
}

@Override
public boolean canSeekBackward() {
    return true;
}

@Override
public boolean canSeekForward() {
    return true;
}

@Override
public int getAudioSessionId() {
    return 0;
}

@Override
public int getBufferPercentage() {
    return 0;
}

@Override
public int getCurrentPosition() {
    if(musicSrv!=null && musicBound && musicSrv.isPng())
        return musicSrv.getPosn();
    else return 0;

}

@Override
public int getDuration() {
    if(musicSrv!=null && musicBound && musicSrv.isPng())
        return musicSrv.getDur();
    else return 0;

}


@Override
public boolean isPlaying() {
    if(musicSrv!=null && musicBound)
        return musicSrv.isPng();
    return false;

}

@Override
public void pause() {
    playbackPaused=true;
    musicSrv.pausePlayer();
}


@Override
public void seekTo(int pos) {
    musicSrv.seek(pos);
}

@Override
public void start() {
    musicSrv.go();

}

private void setController(){
    //set the controller up
    controller = new MusicController(getActivity());
    controller.setPrevNextListeners(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            playNext();
        }
    }, new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            playPrev();
        }
    });
    controller.setMediaPlayer(this);
    controller.setAnchorView(getActivity().findViewById(R.id.library_song_list));
    controller.setEnabled(true);

}
//play next
private void playNext(){
    musicSrv.playNext();
    if(playbackPaused){
        setController();
        playbackPaused=false;
    }
    controller.show(0);
}

//play previous
private void playPrev(){
    musicSrv.playPrev();
    if(playbackPaused){
        setController();
        playbackPaused=false;
    }
    controller.show(0);
}

@Override
public void onPause(){
    super.onPause();
    paused=true;
}

@Override
public void onResume(){
    super.onResume();
    if(paused){
        setController();
        paused=false;
    }
}

@Override
public void onStop() {
    controller.hide();
    super.onStop();
}


@Override
public void onDestroy() {
    this.getActivity().stopService(playIntent);
    musicSrv=null;
    super.onDestroy();
}

歌曲适配器 class

public class SongAdapter extends BaseAdapter {

private ArrayList<SongItem> songs;
private LayoutInflater songInf;


public SongAdapter(Context c, ArrayList<SongItem> 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;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    //map to song layout
    LinearLayout songLay = (LinearLayout)songInf.inflate
            (R.layout.song, parent, false);
    //get title and artist views
    TextView songView = (TextView)songLay.findViewById(R.id.song_title);
    TextView artistView = (TextView)songLay.findViewById(R.id.song_artist);
    //ImageView imageView = (ImageView)songLay.findViewById(R.id.song_image);
    //get song using position
    SongItem currSong = songs.get(position);
    //get title and artist strings
    songView.setText(currSong.getTitle());
    artistView.setText(currSong.getArtist());
    //imageView.setImage(currSong.getImage());
    //set position as tag
    songLay.setTag(position);
    return songLay;
}

Song.xml 文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="5dp"
    android:onClick="songPicked">

    <TextView
        android:id="@+id/song_title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        style="@style/Base.TextAppearance.AppCompat.Title"
        android:textColor="@color/primary_text_default_material_light"/>
    <TextView
        android:id="@+id/song_artist"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        style="@style/Base.TextAppearance.AppCompat.Subhead"
        android:textColor="@color/secondary_text_default_material_light"/>

</LinearLayout>

错误

java.lang.IllegalStateException: Could not find a method songPicked(View) in the activity class co.adrianblan.noraoke.MainActivity for onClick handler on view class android.widget.LinearLayout

所以主要问题出在 SongFragmentLibrary 中的 songPicked 方法。我在 song.xml 文件中添加了 onClick: songPicked 但它正在 MainActivity 中搜索 songPicked 方法。我不明白是什么问题。

谁能帮我解决这个问题?

您正在尝试从您的片段 xml android:onClick="songPicked" 设置 onclick 侦听器,您无法在 getView() setOnClickListener 中为属于片段的视图设置 onclick 侦听器:

LinearLayout songLay = (LinearLayout)songInf.inflate
            (R.layout.song, parent, false);
songLay.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
        //Handle click event
        }
}) 

您只需在列表视图上设置 OnItemClickListener

list.setOnItemClickListener(this);// implement OnItemClickListener in your fragment class