1. 程式人生 > >基於android的網路音樂播放器-播放音樂及收藏音樂的效果展示(四)

基於android的網路音樂播放器-播放音樂及收藏音樂的效果展示(四)

作為android初學者,最近把瘋狂android講義和瘋狂Java講義看了一遍,看到書中介紹的知識點非常多,很難全部記住,為了更好的掌握基礎知識點,我將開發一個網路音樂播放器-EasyMusic來鞏固下,也當作是練練手。感興趣的朋友可以看看,有設計不足的地方也歡迎指出。

開發之前首先介紹下該音樂播放器將要開發的功能(需求):

1.本地音樂的載入和播放;

2.網路音樂的搜尋,試聽和下載;

3.音樂的斷點下載;

4.點選播放圖示載入專輯圖片,點選歌詞載入歌詞並滾動顯示(支援滑動歌詞改變音樂播放進度);

5.支援基於popupWindow的彈出式選單;

6.支援後臺工作列顯示和控制。

該篇主要是貼上一些關鍵類的程式碼以及音樂播放器的展示效果圖:
首先看下效果圖:
1>收藏音樂:
收藏音樂
2>取消收藏:
取消收藏
然後主要程式碼如下:

1.MainActivity.java

package com.sprd.easymusic;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import com.sprd.easymusic.fragment.DownloadFragment;
import
com.sprd.easymusic.fragment.MusicListFragment; import com.sprd.easymusic.fragment.NetFragment; import com.sprd.easymusic.fragment.StoredSongFragment; import com.sprd.easymusic.mysql.MyDBHelper; import com.sprd.easymusic.service.PlayMusicService; import android.app.Activity; import android.app.Service; import
android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.database.Cursor; import android.os.Bundle; import android.os.IBinder; import android.provider.MediaStore; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.util.DisplayMetrics; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends FragmentActivity implements MusicListFragment.CallBack, StoredSongFragment.CallBack, View.OnClickListener { private String TAG = "MainActivity"; private final int FRAGMENT_COUNT = 4; // dbMusic儲存媒體庫中的所有音樂 private ViewPager mViewPager; private SectionsPagerAdapter mSectionsPagerAdapter; private List<Map<String, Object>> allMusic = new ArrayList<>(); private List<Map<String, Object>> storedMusic = new ArrayList<>(); private Context mContext; private TextView fragmentTitle1, fragmentTitle2, fragmentTitle3, fragmentTitle4, titleBottomLine; private int screenWidth, bottomLineWidth; private PlayMusicService playService; private MyDBHelper myHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; myHelper = new MyDBHelper(mContext, "easyMusic.db3", null, 1); getAllMusicFromDb(); getStoredMusic(storedMusic, myHelper); getBottomLineWidth(); mSectionsPagerAdapter = new SectionsPagerAdapter( getSupportFragmentManager()); mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); fragmentTitle1 = (TextView) findViewById(R.id.fragment1); fragmentTitle1.setOnClickListener(this); fragmentTitle2 = (TextView) findViewById(R.id.fragment2); fragmentTitle2.setOnClickListener(this); fragmentTitle3 = (TextView) findViewById(R.id.fragment3); fragmentTitle3.setOnClickListener(this); fragmentTitle4 = (TextView) findViewById(R.id.fragment4); fragmentTitle4.setOnClickListener(this); titleBottomLine = (TextView) findViewById(R.id.fragmentTitle); bindToService(); mViewPager.setOnPageChangeListener(new OnPageChangeListener() { public void onPageSelected(int position) { } public void onPageScrolled(int item, float percent, int offset) { titleBottomLine.setX(item * bottomLineWidth + offset / FRAGMENT_COUNT); } public void onPageScrollStateChanged(int position) { } }); } private void getBottomLineWidth() { DisplayMetrics dm = new DisplayMetrics(); this.getWindowManager().getDefaultDisplay().getMetrics(dm); screenWidth = dm.widthPixels; bottomLineWidth = screenWidth / FRAGMENT_COUNT; } // 繫結服務時的ServiceConnection引數 private ServiceConnection conn = new ServiceConnection() { // 繫結成功後該方法回撥,並獲得服務端IBinder的引用 public void onServiceConnected(ComponentName name, IBinder service) { // 通過獲得的IBinder獲取PlayMusicService的引用 playService = ((PlayMusicService.MusicBinder) service).getService(); Toast.makeText(mContext, "onServiceConnected", Toast.LENGTH_LONG) .show(); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected"); } }; // 繫結服務PlayMusicService private void bindToService() { bindService(new Intent(mContext, com.sprd.easymusic.service.PlayMusicService.class), conn, Service.BIND_AUTO_CREATE); } // 通過獲得的PlayMusicService引用呼叫播放音樂的方法,方法傳進去的引數為音樂url protected void playMusic(String url) { if (playService != null) { playService.play(url); } } // 從媒體庫中查詢音樂 private void getAllMusicFromDb() { if (allMusic.size() > 0) allMusic.clear(); Cursor musicCursor1 = this .getContentResolver() .query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); // 從外部儲存獲取 getMusic(musicCursor1); Cursor musicCursor2 = this .getContentResolver() .query(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); // 從內部儲存獲取 getMusic(musicCursor2); } // 檢查當前歌曲是否在收藏列表中,在收藏列表返回true,否則返回false protected boolean checkIfStored(String url) { for (Map<String, Object> map : storedMusic) { if (url.equals((String) map.get("url"))) { return true; } } return false; } // 獲取到的音樂以Map的形式儲存在dbMusic中 private void getMusic(Cursor musicCursor) { while (musicCursor.moveToNext()) { Map<String, Object> item = new HashMap<String, Object>(); long id = musicCursor.getLong(musicCursor .getColumnIndex(MediaStore.Audio.Media._ID)); String title = musicCursor.getString(musicCursor .getColumnIndex(MediaStore.Audio.Media.TITLE)); String artist = musicCursor.getString(musicCursor .getColumnIndex(MediaStore.Audio.Media.ARTIST)); if (artist != null && artist.equals("<unknown>")) { continue; } long duration = musicCursor.getLong(musicCursor .getColumnIndex(MediaStore.Audio.Media.DURATION)); long size = musicCursor.getLong(musicCursor .getColumnIndex(MediaStore.Audio.Media.SIZE)); String url = musicCursor.getString(musicCursor .getColumnIndex(MediaStore.Audio.Media.DATA)); int isMusic = musicCursor.getInt(musicCursor .getColumnIndex(MediaStore.Audio.Media.IS_MUSIC)); if (isMusic != 0) { item.put("id", id); item.put("title", title); item.put("artist", artist); item.put("duration", formatDuration(duration)); item.put("size", size); item.put("url", url); Log.d("MainActivity", "MusicTitle = " + title); Log.d("MainActivity", "MusicArtist = " + artist); Log.d("MainActivity", "MusicUrl = " + url); allMusic.add(item); } } } // 將音樂時長轉換為00:00格式 public static String formatDuration(long dur) { long totalSecond = dur / 1000; String minute = totalSecond / 60 + ""; if (minute.length() < 2) minute = "0" + minute; String second = totalSecond % 60 + ""; if (second.length() < 2) second = "0" + second; return minute + ":" + second; } // 從資料庫中查詢已收藏音樂 private void getStoredMusic(List<Map<String, Object>> storedMusic, MyDBHelper myHelper) { if (storedMusic.size() > 0) storedMusic.clear(); Cursor cursor = myHelper.getReadableDatabase().rawQuery( "select * from stored_music", null); while (cursor.moveToNext()) { Map<String, Object> item = new HashMap<>(); item.put("title", cursor.getString(1)); item.put("artist", cursor.getString(2)); item.put("duration", cursor.getString(3)); item.put("url", cursor.getString(4)); storedMusic.add(item); } } public class SectionsPagerAdapter extends FragmentPagerAdapter { public SectionsPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { Fragment fragment = null; switch (position) { case 0: fragment = new MusicListFragment(); break; case 1: fragment = new StoredSongFragment(); break; case 2: fragment = new NetFragment(); break; case 3: fragment = new DownloadFragment(); break; } return fragment; } @Override public int getCount() { return FRAGMENT_COUNT; } @Override public CharSequence getPageTitle(int position) { Locale l = Locale.getDefault(); switch (position) { case 0: return getString(R.string.title_section1).toUpperCase(l); case 1: return getString(R.string.title_section2).toUpperCase(l); case 2: return getString(R.string.title_section3).toUpperCase(l); case 3: return getString(R.string.title_section4).toUpperCase(l); } return null; } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.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(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public void onItemSelected(String url) { playMusic(url); } @Override public List<Map<String, Object>> getAllMusic() { return allMusic; } @Override public List<Map<String, Object>> getStoredMusic() { return storedMusic; } @Override public void onClick(View v) { if (v == fragmentTitle1) { mViewPager.setCurrentItem(0); } else if (v == fragmentTitle2) { mViewPager.setCurrentItem(1); } else if (v == fragmentTitle3) { mViewPager.setCurrentItem(2); } else if (v == fragmentTitle4) { mViewPager.setCurrentItem(3); } } }

MainActivity主要負責管理整個音樂播放器應用,像資料庫查詢,服務啟動等都是該類負責。其佈局為:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.sprd.easymusic.MainActivity" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:background="#18f" >

        <TextView
            android:id="@+id/fragment1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:text="@string/title_section1"/>

        <TextView
            android:id="@+id/fragment2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:text="@string/title_section2"/>

        <TextView
            android:id="@+id/fragment3"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:text="@string/title_section3"/>

        <TextView
            android:id="@+id/fragment4"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:text="@string/title_section4"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="3dp"
        android:gravity="center" >

        <!-- 該textview作為紅線移動到當前fragment下 -->

        <TextView
            android:id="@+id/fragmentTitle"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#f00" />

        <TextView
            android:id="@+id/textView6"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3" />
    </LinearLayout>

    <android.support.v4.view.ViewPager
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="20"
        android:alpha="0.8"
        android:background="#afeeee"
        tools:context=".MainActivity" >
    </android.support.v4.view.ViewPager>

</LinearLayout>

2.MusicListFragment.java

package com.sprd.easymusic.fragment;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.sprd.easymusic.R;
import com.sprd.easymusic.mysql.MyDBHelper;
import com.sprd.easymusic.myview.RefreshableListView;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.support.v4.app.Fragment;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MusicListFragment extends Fragment {
    private final String TAG = "MusicListFragment";
    private final String ACTION_REFRESH = "action.refreshmusicList";
    private List<Map<String, Object>> dbMusic = new ArrayList<>();
    private List<Map<String, Object>> storedMusic = new ArrayList<>();
    private ListView musicListView;
    private LayoutInflater inflater;
    private CallBack mCallBack;
    private Context mContext;
    private MyDBHelper myHelper;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "onCreate");
        mContext = this.getActivity();
        myHelper = new MyDBHelper(mContext, "easyMusic.db3", null, 1);
        inflater = LayoutInflater.from(mContext);
        dbMusic = mCallBack.getAllMusic();
        storedMusic = mCallBack.getStoredMusic();
    }

    // NetFragment向外界展示的內容,返回值為view
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.musiclist, container, false);
        musicListView = (ListView) view.findViewById(R.id.musicList);
        musicListView.setAdapter(musicListAdapter);
        musicListView.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                mCallBack.onItemSelected((String) dbMusic.get(position).get("url"));
                TextView title = (TextView) view.findViewWithTag("title");
                Toast.makeText(mContext,"title = " + title.getText().toString(),Toast.LENGTH_SHORT).show();
            }
        });
        return view;
    }

    // 音樂列表介面卡
    private BaseAdapter musicListAdapter = new BaseAdapter() {

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

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            View view = convertView;
            Map<String, Object> item = dbMusic.get(position);
            if (convertView == null) {
                view = inflater.inflate(R.layout.musiclist_item, null);
            }
            final ImageView storeMusic = (ImageView) view.findViewById(R.id.love);
            if (checkIfStored((String) item.get("url"))) {
                storeMusic.setImageResource(android.R.drawable.btn_star_big_on);
            } else {
                storeMusic.setImageResource(android.R.drawable.btn_star_big_off);
            }
            storeMusic.setOnClickListener(new OnClickListener() {
                public void onClick(View v) {
                    new MyAsyncTask(storeMusic, dbMusic.get(position)).execute();
                }
            });
            TextView musicTitle = (TextView) view.findViewById(R.id.musicTitle);
            musicTitle.setTag("title");
            TextView musicArtist = (TextView) view.findViewById(R.id.musicArtist);
            musicTitle.setText((String) item.get("title"));
            musicArtist.setText((String) item.get("artist"));
            return view;
        }

    };

    // 檢查當前歌曲是否在收藏列表中,在收藏列表返回true,否則返回false
    protected boolean checkIfStored(String url) {
        for (Map<String, Object> map : storedMusic) {
            if (url.equals((String) map.get("url"))) {
                return true;
            }
        }
        return false;
    }

    // 執行收藏或者取消收藏動作後重新整理刷收藏音樂列表
    private void refreshStoredMusic(Map<String, Object> musicInfo) {
        int i = 0;
        for (; i < storedMusic.size(); i++) {
            Map<String, Object> map = storedMusic.get(i);
            String url = (String) map.get("url");
            if (url.equals((String) musicInfo.get("url"))) {
                Log.d(TAG, "remove index =" + i);
                storedMusic.remove(i);
                //musicListAdapter.notifyDataSetChanged();
                mContext.sendBroadcast(new Intent(ACTION_REFRESH));
                return;
            }
        }
        storedMusic.add(musicInfo);
        //傳送廣播通知StoredSongFargment更新列表
        mContext.sendBroadcast(new Intent(ACTION_REFRESH));
        // 重新整理收藏列表有兩種方法:1:重新查詢一次資料庫-呼叫getStoredMusic(),這種效率比較低;2:用上面的方法,直接從storedMusic中刪除或新增
        // 這裡用第一種方法
        // getStoredMusic();
        // 通知介面卡資料發生改變的方法來重新整理列表,最好別用musicListView.setAdapter(adapter)這種方法,該方法會導致焦點重新回到首行
        //musicListAdapter.notifyDataSetChanged();
    }

    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mCallBack = (CallBack) activity;
    }

    public void onDestroy() {
        super.onDestroy();
    }

    public interface CallBack {
        public void onItemSelected(String url);
        public List<Map<String, Object>> getAllMusic();
        public List<Map<String, Object>> getStoredMusic();
    }

    // 執行收藏音樂/取消收藏的非同步任務
    private class MyAsyncTask extends AsyncTask<String, Void, Void> {
        private ImageView starView;
        private Map<String, Object> musicInfo;
        // 標記收藏,true表示收藏音樂成功,false表示取消收藏音樂
        private boolean storeSuccess;

        public MyAsyncTask(ImageView starView, Map<String, Object> musicInfo) {
            this.starView = starView;
            this.musicInfo = musicInfo;
        }

        protected void onPreExecute() {
            super.onPreExecute();
        }

        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }

        protected Void doInBackground(String... params) {
            Log.d(TAG, "doInBackground");
            Cursor cursor = myHelper.getReadableDatabase().rawQuery(
                    "select * from stored_music", null);
            while (cursor.moveToNext()) {
                String title = cursor.getString(1);
                String artist = cursor.getString(2);
                Log.d(TAG, "title = " + title + " artist = " + artist);
                Log.d(TAG,
                        "musicInfo.title = " + (String) musicInfo.get("title")
                                + " musicInfo.artist = "
                                + (String) musicInfo.get("artist"));
                if (cursor.getString(4).equals((String) musicInfo.get("url"))) {
                    // 已經收藏的音樂取消收藏並移出收藏音樂表格-stored_music
                    myHelper.getReadableDatabase()
                            .execSQL(
                                    "delete from stored_Music where title like ? and artist like ?",
                                    new String[] { title, artist });
                    storeSuccess = false;
                    return null;
                }
            }
            // 未收藏的音樂加入到收藏中
            myHelper.getReadableDatabase().execSQL(
                    "insert into stored_music values(null, ?, ?, ?, ?)",
                    new Object[] { musicInfo.get("title"),
                            musicInfo.get("artist"), musicInfo.get("duration"),
                            musicInfo.get("url") });
            storeSuccess = true;
            return null;
        }

        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            if (storeSuccess) {
                starView.setImageResource(android.R.drawable.btn_star_big_on);
                refreshStoredMusic(musicInfo);
                Toast.makeText(mContext, "收藏成功", 100).show();
            } else {
                starView.setImageResource(android.R.drawable.btn_star_big_off);
                refreshStoredMusic(musicInfo);
                Toast.makeText(mContext, "取消收藏", 100).show();
            }
        }

    }

}

MusicListFragment主要顯示本地音樂,並提供音樂的收藏和取消收藏操作(非同步任務來完成該操作)。其佈局檔案為:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/musicList"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

ListView的每個item佈局為:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/musicTag"
        android:layout_width="50dp"
        android:layout_height="40dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_centerVertical="true"
        android:src="@drawable/music" />

    <TextView
        android:id="@+id/musicTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@id/musicTag"
        android:singleLine="true"
        android:ellipsize="marquee"
        android:marqueeRepeatLimit="marquee_forever"/>

    <TextView
        android:id="@+id/musicArtist"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/musicTitle"
        android:layout_toRightOf="@id/musicTag"
        android:text="TextView" />

    <ImageView
        android:id="@+id/love"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/musicTag"
        android:layout_alignParentRight="true"
        android:src="@android:drawable/btn_star_big_off"/>

</RelativeLayout>

3.StoredSongFragment.java

package com.sprd.easymusic.fragment;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.sprd.easymusic.R;
import com.sprd.easymusic.myview.RefreshableListView;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class StoredSongFragment extends Fragment {
    private final String TAG = "StoredSongFragment";
    private final String ACTION_REFRESH = "action.refreshmusicList";
    private List<Map<String, Object>> storedMusic = new ArrayList<>();
    private ListView storedMusicList;
    private CallBack mCallBack;
    private LayoutInflater inflater;
    private Context mContext;

    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mCallBack = (CallBack) activity;
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this.getActivity();
        inflater = LayoutInflater.from(mContext);
        storedMusic = mCallBack.getStoredMusic();
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_REFRESH);
        mContext.registerReceiver(refreshMusicReceiver, filter);
        Log.d(TAG, "onCreate");
    }

    // StoredSongFragment向外界展示的內容,返回值為view
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater
                .inflate(R.layout.storedmusiclist, container, false);
        storedMusicList = (ListView) view.findViewById(R.id.storedmusicList);
        storedMusicList.setAdapter(musicListAdapter);
        storedMusicList.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                mCallBack.onItemSelected((String) storedMusic.get(position).get("url"));
                TextView title = (TextView) view.findViewWithTag("title");
                Toast.makeText(mContext, "title = " + title.getText().toString(),Toast.LENGTH_SHORT).show();
            }
        });
        return view;
    }

    // 音樂列表介面卡
    private BaseAdapter musicListAdapter = new BaseAdapter() {

        public int getCount() {
            return storedMusic.size();
        }

        public Object getItem(int position) {
            return null;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(final int position, View convertView, ViewGroup parent) {
            View view = convertView;
            Map<String, Object> item = storedMusic.get(position);
            if (convertView == null) {
                view = inflater.inflate(R.layout.storedmusiclist_item, null);
            }
            TextView musicTitle = (TextView) view.findViewById(R.id.musicTitle);
            musicTitle.setTag("title");
            TextView musicArtist = (TextView) view.findViewById(R.id.musicArtist);
            musicTitle.setText((String) item.get("title"));
            musicArtist.setText((String) item.get("artist"));
            return view;
        }

    };

    public void onDestroy() {
        if (refreshMusicReceiver != null) mContext.unregisterReceiver(refreshMusicReceiver);
        super.onDestroy();
    }

    public interface CallBack {
        public void onItemSelected(String url);

        public List<Map<String, Object>> getStoredMusic();
    }

    //接收來自MusicListFragment的收藏或取消收藏音樂的廣播,並更新收藏列表
    private BroadcastReceiver refreshMusicReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(ACTION_REFRESH)) {
                musicListAdapter.notifyDataSetChanged();
                Toast.makeText(mContext, "重新整理收藏列表成功!", 100).show();
            }
        }

    };

}

StoredSongFragment主要顯示收藏的音樂,也提供播放監聽,其佈局與MusicListragment幾乎一樣(區別在listview的item是否有收藏圖示),因此就不提供了,參考MusicListragment的佈局即可。