播放器程序的主要流程图在这里:
先介绍下MainContentActivity,后面所有的Activity和Fragment都是基于这个类之上,看下代码:
package com.ldw.music.activity;
import java.util.ArrayList;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.ldw.music.MusicApp;
import com.ldw.music.R;
import com.ldw.music.db.MusicInfoDao;
import com.ldw.music.fragment.MainFragment;
import com.ldw.music.fragment.MenuFragment;
import com.ldw.music.slidemenu.SlidingMenu;
import com.ldw.music.utils.MusicUtils;
import com.ldw.music.utils.SplashScreen;
/**
* 主类,首次进入应用会到这里
* 该类提供了首页MainFragment的显示和侧滑MenuFragment的显示
* @author longdw
*
*/
@SuppressLint("HandlerLeak")
public class MainContentActivity extends FragmentActivity implements IConstants {
public static final String ALARM_CLOCK_BROADCAST = "alarm_clock_broadcast";
public SlidingMenu mSlidingMenu;
private List<OnBackListener> mBackListeners = new ArrayList<OnBackListener>();
public MainFragment mMainFragment;
private Handler mHandler;
private MusicInfoDao mMusicDao;
private SplashScreen mSplashScreen;
private int mScreenWidth;
public interface OnBackListener {
public abstract void onBack();
}
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
DisplayMetrics metric = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metric);
mScreenWidth = metric.widthPixels;
initSDCard();
IntentFilter filter = new IntentFilter();
filter.addAction(ALARM_CLOCK_BROADCAST);
registerReceiver(mAlarmReceiver, filter);
setContentView(R.layout.frame_main);
mSplashScreen = new SplashScreen(this);
mSplashScreen.show(R.drawable.image_splash_background,
SplashScreen.SLIDE_LEFT);
// set the Above View
mMainFragment = new MainFragment();
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_main, mMainFragment).commit();
// configure the SlidingMenu
mSlidingMenu = new SlidingMenu(this);
mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);
mSlidingMenu.setMode(SlidingMenu.RIGHT);
mSlidingMenu.setShadowWidthRes(R.dimen.shadow_width);
mSlidingMenu.setShadowDrawable(R.drawable.shadow);
mSlidingMenu.setBehindOffsetRes(R.dimen.slidingmenu_offset);
mSlidingMenu.setFadeDegree(0.35f);
mSlidingMenu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
mSlidingMenu.setMenu(R.layout.frame_menu);
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_menu, new MenuFragment()).commit();
mMusicDao = new MusicInfoDao(this);
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mSplashScreen.removeSplashScreen();
}
};
getData();
}
private void initSDCard() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.setPriority(1000);// 设置最高优先级
intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);// sd卡被插入,且已经挂载
intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);// sd卡存在,但还没有挂载
intentFilter.addAction(Intent.ACTION_MEDIA_REMOVED);// sd卡被移除
intentFilter.addAction(Intent.ACTION_MEDIA_SHARED);// sd卡作为
// USB大容量存储被共享,挂载被解除
intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);// sd卡已经从sd卡插槽拔出,但是挂载点还没解除
// intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);// 开始扫描
// intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);// 扫描完成
intentFilter.addDataScheme("file");
registerReceiver(sdCardReceiver, intentFilter);// 注册监听函数
}
private void getData() {
new Thread(new Runnable() {
@Override
public void run() {
if (mMusicDao.hasData()) {
// 如果有数据就等三秒跳转
mHandler.sendMessageDelayed(mHandler.obtainMessage(), 3000);
} else {
MusicUtils.queryMusic(MainContentActivity.this,
START_FROM_LOCAL);
MusicUtils.queryAlbums(MainContentActivity.this);
MusicUtils.queryArtist(MainContentActivity.this);
MusicUtils.queryFolder(MainContentActivity.this);
mHandler.sendEmptyMessage(1);
}
}
}).start();
}
public void registerBackListener(OnBackListener listener) {
if (!mBackListeners.contains(listener)) {
mBackListeners.add(listener);
}
}
public void unRegisterBackListener(OnBackListener listener) {
mBackListeners.remove(listener);
}
@Override
public void onBackPressed() {
if (mSlidingMenu.isMenuShowing()) {
mSlidingMenu.showContent();
} else {
if (mBackListeners.size() == 0) {
// super.onBackPressed();
// 在activity中调用 moveTaskToBack (boolean nonRoot)方法即可将activity
// 退到后台,注意不是finish()退出。
// 参数为false代表只有当前activity是task根,指应用启动的第一个activity时,才有效;
moveTaskToBack(true);
}
for (OnBackListener listener : mBackListeners) {
listener.onBack();
}
}
}
private final BroadcastReceiver sdCardReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.intent.action.MEDIA_REMOVED")// 各种未挂载状态
|| action.equals("android.intent.action.MEDIA_UNMOUNTED")
|| action.equals("android.intent.action.MEDIA_BAD_REMOVAL")
|| action.equals("android.intent.action.MEDIA_SHARED")) {
finish();
Toast.makeText(MainContentActivity.this, "SD卡以外拔出,本地数据没法初始化!",
Toast.LENGTH_SHORT).show();
}
}
};
public void showSleepDialog() {
if (MusicApp.mIsSleepClockSetting) {
cancleSleepClock();
Toast.makeText(getApplicationContext(), "已取睡眠模式!",
Toast.LENGTH_SHORT).show();
return;
}
View view = View.inflate(this, R.layout.sleep_time, null);
final Dialog dialog = new Dialog(this, R.style.lrc_dialog);
dialog.setContentView(view);
dialog.setCanceledOnTouchOutside(false);
Window dialogWindow = dialog.getWindow();
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
dialogWindow.setGravity(Gravity.CENTER);
// lp.x = 100; // 新位置X坐标
// lp.y = 100; // 新位置Y坐标
lp.width = (int) (mScreenWidth * 0.7); // 宽度
// lp.height = 400; // 高度
// 当Window的Attributes改变时系统会调用此函数,可以直接调用以应用上面对窗口参数的更改,也可以用setAttributes
// dialog.onWindowAttributesChanged(lp);
dialogWindow.setAttributes(lp);
dialog.show();
final Button cancleBtn = (Button) view.findViewById(R.id.cancle_btn);
final Button okBtn = (Button) view.findViewById(R.id.ok_btn);
final EditText timeEt = (EditText) view.findViewById(R.id.time_et);
OnClickListener listener = new OnClickListener() {
@Override
public void onClick(View v) {
if (v == cancleBtn) {
dialog.dismiss();
} else if (v == okBtn) {
String timeS = timeEt.getText().toString();
if (TextUtils.isEmpty(timeS)
|| Integer.parseInt(timeS) == 0) {
Toast.makeText(getApplicationContext(), "输入无效!",
Toast.LENGTH_SHORT).show();
return;
}
setSleepClock(timeS);
dialog.dismiss();
}
}
};
cancleBtn.setOnClickListener(listener);
okBtn.setOnClickListener(listener);
}
/**
* 设置睡眠闹钟
*
* @param timeS
*/
private void setSleepClock(String timeS) {
Intent intent = new Intent(ALARM_CLOCK_BROADCAST);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
MainContentActivity.this, 0, intent, 0);
// 设置time时间之后退出程序
int time = Integer.parseInt(timeS);
long longTime = time * 60 * 1000L;
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC, System.currentTimeMillis() + longTime,
pendingIntent);
MusicApp.mIsSleepClockSetting = true;
Toast.makeText(getApplicationContext(), "将在"+timeS+"分钟后退出软件", Toast.LENGTH_SHORT)
.show();
}
/**
* 取消睡眠闹钟
*/
private void cancleSleepClock() {
Intent intent = new Intent(ALARM_CLOCK_BROADCAST);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
MainContentActivity.this, 0, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.cancel(pendingIntent);
MusicApp.mIsSleepClockSetting = false;
}
private BroadcastReceiver mAlarmReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//退出程序
finish();
}
};
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(sdCardReceiver);
unregisterReceiver(mAlarmReceiver);
MusicApp.mServiceManager.exit();
MusicApp.mServiceManager = null;
MusicUtils.clearCache();
cancleSleepClock();
System.exit(0);
}
}
该类使用SlideMenu控制着MainFragment和MenuFragment,监听SD卡的变化,具体的实现代码中写的很详细,接下来看看MainFragment:
package com.ldw.music.fragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.ldw.music.MusicApp;
import com.ldw.music.R;
import com.ldw.music.activity.IConstants;
import com.ldw.music.aidl.IMediaService;
import com.ldw.music.db.AlbumInfoDao;
import com.ldw.music.db.ArtistInfoDao;
import com.ldw.music.db.FavoriteInfoDao;
import com.ldw.music.db.FolderInfoDao;
import com.ldw.music.db.MusicInfoDao;
import com.ldw.music.interfaces.IOnServiceConnectComplete;
import com.ldw.music.model.MusicInfo;
import com.ldw.music.service.ServiceManager;
import com.ldw.music.uimanager.MainBottomUIManager;
import com.ldw.music.uimanager.SlidingDrawerManager;
import com.ldw.music.uimanager.UIManager;
import com.ldw.music.uimanager.UIManager.OnRefreshListener;
import com.ldw.music.utils.MusicTimer;
/**
* 首页内容
* 该类展示了软件的几大模块
* 另外要注意嵌套的两层ViewPager
* @author longdw
*
*/
public class MainFragment extends Fragment implements IConstants,
IOnServiceConnectComplete, OnRefreshListener, OnTouchListener {
private GridView mGridView;
private MyGridViewAdapter mAdapter;
protected IMediaService mService;
private MusicInfoDao mMusicDao;
private FolderInfoDao mFolderDao;
private ArtistInfoDao mArtistDao;
private AlbumInfoDao mAlbumDao;
private FavoriteInfoDao mFavoriteDao;
public UIManager mUIManager;
private MusicTimer mMusicTimer;
private MusicPlayBroadcast mPlayBroadcast;
private MainBottomUIManager mBottomUIManager;
private SlidingDrawerManager mSdm;
private RelativeLayout mBottomLayout, mMainLayout;
private Bitmap defaultArtwork;
private ServiceManager mServiceManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMusicDao = new MusicInfoDao(getActivity());
mFolderDao = new FolderInfoDao(getActivity());
mArtistDao = new ArtistInfoDao(getActivity());
mAlbumDao = new AlbumInfoDao(getActivity());
mFavoriteDao = new FavoriteInfoDao(getActivity());
mServiceManager = MusicApp.mServiceManager;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frame_main1, container, false);
mGridView = (GridView) view.findViewById(R.id.gridview);
mAdapter = new MyGridViewAdapter();
mMainLayout = (RelativeLayout) view
.findViewById(R.id.main_layout);
mMainLayout.setOnTouchListener(this);
mBottomLayout = (RelativeLayout) view.findViewById(R.id.bottomLayout);
MusicApp.mServiceManager.connectService();
MusicApp.mServiceManager.setOnServiceConnectComplete(this);
mGridView.setAdapter(mAdapter);
mUIManager = new UIManager(getActivity(), view);
mUIManager.setOnRefreshListener(this);
mSdm = new SlidingDrawerManager(getActivity(), mServiceManager, view);
mBottomUIManager = new MainBottomUIManager(getActivity(), view);
mMusicTimer = new MusicTimer(mSdm.mHandler, mBottomUIManager.mHandler);
mSdm.setMusicTimer(mMusicTimer);
mPlayBroadcast = new MusicPlayBroadcast();
IntentFilter filter = new IntentFilter(BROADCAST_NAME);
filter.addAction(BROADCAST_NAME);
getActivity().registerReceiver(mPlayBroadcast, filter);
return view;
}
private class MyGridViewAdapter extends BaseAdapter {
private int[] drawable = new int[] { R.drawable.icon_local_music,
R.drawable.icon_favorites, R.drawable.icon_folder_plus,
R.drawable.icon_artist_plus, R.drawable.icon_album_plus };
private String[] name = new String[] { "我的音乐", "我的最爱", "文件夹", "歌手",
"专辑" };
private int musicNum = 0, artistNum = 0, albumNum = 0, folderNum = 0, favoriteNum = 0;
@Override
public int getCount() {
return 5;
}
@Override
public Object getItem(int arg0) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
public void setNum(int music_num, int artist_num, int album_num,
int folder_num, int favorite_num) {
musicNum = music_num;
artistNum = artist_num;
albumNum = album_num;
folderNum = folder_num;
favoriteNum = favorite_num;
notifyDataSetChanged();
}
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = getActivity().getLayoutInflater().inflate(
R.layout.main_gridview_item, null);
holder.iv = (ImageView) convertView
.findViewById(R.id.gridview_item_iv);
holder.nameTv = (TextView) convertView
.findViewById(R.id.gridview_item_name);
holder.numTv = (TextView) convertView
.findViewById(R.id.gridview_item_num);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
switch (position) {
case 0:// 我的音乐
holder.numTv.setText(musicNum + "");
break;
case 1:// 我的最爱
holder.numTv.setText(favoriteNum + "");
break;
case 2:// 文件夹
holder.numTv.setText(folderNum + "");
break;
case 3:// 歌手
holder.numTv.setText(artistNum + "");
break;
case 4:// 专辑
holder.numTv.setText(albumNum + "");
break;
}
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int from = -1;
switch (position) {
case 0:// 我的音乐
from = START_FROM_LOCAL;
break;
case 1:// 我的最爱
from = START_FROM_FAVORITE;
break;
case 2:// 文件夹
from = START_FROM_FOLDER;
break;
case 3:// 歌手
from = START_FROM_ARTIST;
break;
case 4:// 专辑
from = START_FROM_ALBUM;
break;
}
mUIManager.setContentType(from);
}
});
holder.iv.setImageResource(drawable[position]);
holder.nameTv.setText(name[position]);
return convertView;
}
private class ViewHolder {
ImageView iv;
TextView nameTv, numTv;
}
}
@Override
public void onServiceConnectComplete(IMediaService service) {
// service绑定成功会执行到这里
refreshNum();
}
public void refreshNum() {
int musicCount = mMusicDao.getDataCount();
int artistCount = mArtistDao.getDataCount();
int albumCount = mAlbumDao.getDataCount();
int folderCount = mFolderDao.getDataCount();
int favoriteCount = mFavoriteDao.getDataCount();
mAdapter.setNum(musicCount, artistCount, albumCount, folderCount, favoriteCount);
}
private class MusicPlayBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BROADCAST_NAME)) {
MusicInfo music = new MusicInfo();
int playState = intent.getIntExtra(PLAY_STATE_NAME, MPS_NOFILE);
int curPlayIndex = intent.getIntExtra(PLAY_MUSIC_INDEX, -1);
Bundle bundle = intent.getBundleExtra(MusicInfo.KEY_MUSIC);
if (bundle != null) {
music = bundle.getParcelable(MusicInfo.KEY_MUSIC);
}
switch (playState) {
case MPS_INVALID:// 考虑后面加上如果文件不可播放直接跳到下一首
mMusicTimer.stopTimer();
mSdm.refreshUI(0, music.duration, music);
mSdm.showPlay(true);
mBottomUIManager.refreshUI(0, music.duration, music);
mBottomUIManager.showPlay(true);
break;
case MPS_PAUSE:
mMusicTimer.stopTimer();
mSdm.refreshUI(mServiceManager.position(), music.duration,
music);
mSdm.showPlay(true);
mBottomUIManager.refreshUI(mServiceManager.position(), music.duration,
music);
mBottomUIManager.showPlay(true);
mServiceManager.cancelNotification();
break;
case MPS_PLAYING:
mMusicTimer.startTimer();
mSdm.refreshUI(mServiceManager.position(), music.duration,
music);
mSdm.showPlay(false);
mBottomUIManager.refreshUI(mServiceManager.position(), music.duration,
music);
mBottomUIManager.showPlay(false);
break;
case MPS_PREPARE:
mMusicTimer.stopTimer();
mSdm.refreshUI(0, music.duration, music);
mSdm.showPlay(true);
mBottomUIManager.refreshUI(0, music.duration, music);
mBottomUIManager.showPlay(true);
// 读取歌词文件
mSdm.loadLyric(music);
break;
}
}
}
}
@Override
public void onRefresh() {
refreshNum();
}
int oldY = 0;
@Override
public boolean onTouch(View v, MotionEvent event) {
int bottomTop = mBottomLayout.getTop();
System.out.println(bottomTop);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
oldY = (int) event.getY();
if (oldY > bottomTop) {
mSdm.open();
}
}
return true;
}
}
布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg"
android:gravity="center"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/top_layout"
android:layout_width="fill_parent"
android:layout_height="50dip"
android:background="@color/half_transparent"
android:gravity="center" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我的首页"
android:textColor="@color/white"
android:textSize="@dimen/title_text_sp" />
</LinearLayout>
<RelativeLayout
android:id="@+id/bottomLayout"
android:layout_width="fill_parent"
android:layout_height="64dip"
android:layout_alignParentBottom="true"
android:background="@color/bottom_color" >
<ImageView
android:id="@+id/headicon_iv"
android:layout_width="64dip"
android:layout_height="64dip"
android:background="@drawable/img_album_background" />
<ImageButton
android:id="@+id/btn_menu2"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_margin="4.0dip"
android:background="@drawable/selector_music_btn"
android:padding="6.0dip"
android:src="@drawable/icon_menu_point" />
<View
android:id="@+id/split"
android:layout_width="1.5dip"
android:layout_height="64dip"
android:layout_marginLeft="6.0dip"
android:layout_marginRight="6.0dip"
android:layout_toLeftOf="@id/btn_menu2"
android:background="#6a5e8a" />
<ImageButton
android:id="@+id/btn_playNext2"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_centerVertical="true"
android:layout_toLeftOf="@id/split"
android:background="@drawable/selector_music_btn"
android:padding="6.0dip"
android:src="@drawable/icon_next_normal" />
<FrameLayout
android:id="@+id/playLayout"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_centerVertical="true"
android:layout_marginRight="12.0dip"
android:layout_toLeftOf="@id/btn_playNext2" >
<ImageButton
android:id="@+id/btn_pause2"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="@drawable/selector_music_btn"
android:padding="6.0dip"
android:src="@drawable/icon_pause_normal"
android:visibility="gone" />
<ImageButton
android:id="@+id/btn_play2"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:background="@drawable/selector_music_btn"
android:padding="6.0dip"
android:src="@drawable/icon_play_normal" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="6.0dip"
android:layout_toLeftOf="@id/playLayout"
android:layout_toRightOf="@id/headicon_iv"
android:orientation="vertical" >
<com.ldw.music.view.AlwaysMarqueeTextView
android:id="@+id/artist_tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="@color/white"
android:textSize="12sp" />
<com.ldw.music.view.AlwaysMarqueeTextView
android:id="@+id/musicname_tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:focusable="true"
android:focusableInTouchMode="true"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="@color/white" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/position_tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="00:00" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" - "
android:textColor="@color/white" />
<TextView
android:id="@+id/duration_tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="00:00" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<ProgressBar
android:id="@+id/playback_seekbar2"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/bottomLayout"
android:max="100"
android:maxHeight="2.0dip"
android:minHeight="2.0dip"
android:progressDrawable="@drawable/playback_seekbar2" />
<GridView
android:id="@+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@id/top_layout"
android:layout_above="@id/playback_seekbar2"
android:layout_margin="8.0dip"
android:horizontalSpacing="6.0dip"
android:numColumns="3"
android:verticalSpacing="6.0dip" />
<com.ldw.music.view.MySlidingDrawer
android:id="@+id/slidingDrawer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/sliding_bg"
android:content="@+id/content"
android:handle="@+id/handle"
android:visibility="invisible" >
<include layout="@layout/sliding_handle" />
<include layout="@layout/sliding_content" />
</com.ldw.music.view.MySlidingDrawer>
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="invisible" >
</android.support.v4.view.ViewPager>
<android.support.v4.view.ViewPager
android:id="@+id/viewPagerSub"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="invisible" >
</android.support.v4.view.ViewPager>
</RelativeLayout>
MainFragment控制着主要的UI部分,从布局文件中可以看出,我这里用了两个ViewPager,原因是从文件夹、列表、歌手进入的时候会有两级目录才能进入歌曲列表,当然天天动听不是这么做的,我这里为了方便用了现成的ViewPager来控制,效果还行。还有就是UIManager类,该类控制从主页的GridView进入其他界面。
还有一些诸如自定义View之类的我这里就不做介绍了,大家可以看下源码就知道了,下面是项目在github上的地址,发帖不容易,希望大家多提提宝贵的意见也算是给我的鼓励。

sdcard的监听是怎样实现的,难道是定义了那个sdCardReceiver,可是它并没有处理如何扫描文件
sdcard监听没有处理扫描哦,很简单的,在onReceive里面监听到sd卡发生了变化就重新扫描就行了,我这里只是做了sd卡没有mount的情况。
想学习,望把原工程发到1061354225@qq.com,谢谢了
github上面有的
为什么需要用到aidl?
aidl,进程间通信,也就是你其他进程也可以访问到,音乐播放器这个应用其实用不用aidl无所谓的,我主要是为了方便操作service
还没看代码,简单看了下功能。发现一个小BUG:点击换肤的时候会出一点小问题。比如在(1)首页——>(2)歌手——>(3)张杰 ——>进入音频列表。此时换肤,(1)(3)成功换肤,但是(2)还没换过来,需要刷新一下再次感谢隆笛大神,您的开源让我收益良多。
本人java开发,现在在学android呢,看到你的代码,学习了,我QQ:895713007
服务器端代码开源吗 求分享yanlei_man@outlook.com
大神,你的功底真的深厚。
为什么歌手列表和专辑列表没有显示啊?