如何使用AndriodStudio制作音乐播放器音乐列表界面和导入手机音乐资源
思路:
创建一个空的Activity页面、两个Fragment、两个Adapter适配器、一个实体类、一个行布局文件;
在实体类中定义必要的属性;
配置两个Adapter适配器,其中MusicAdapter要用到缓存原理,配置行控件。
在LocalFragment里获取手机音乐文件资源(歌曲名、歌手名、专辑名、专辑图片),绑定适配器;
在MIanActivity.java里绑定碎片、设置点击事件、绑定适配器。
难点:
动态获取手机权限
获取图片资源
效果图:
1.准备工作
实现音乐播放器里的音乐列表必须要使用Activity活动页面和Fragment页面相结合。
在这里我将MainActivity作为主页面,然后新建两个Fragment(LocalMusic和OnlineMusic)分别作为“我的音乐”和“在线音乐”的活动界面。
还需要新建MusicAdapter适配器和MusicPagerAdapater适配器。MusicAdapter配置音乐的ListView和LocalFragment,MusicPagerAdapater是用来配置Fragment和Activity的。再创建一个实体类Music用来接音乐数据,最后新建一个item_list.XML文件,作为ListView的行布局文件
准备工作做好如下图:(MusicActivity是后续需要的工作,可以暂时不用管)
2.在实体类Music中定义自己需要的属性:
public class Music {
public String title;//歌曲名称
public String artist;//歌手名称
public String album;//专辑名称
public int length;//歌曲时间长度
public Bitmap albumbtm;//专辑图片
}
3.设置item_list.XML行布局:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="60dp">
<ImageView
android:id="@+id/song_album"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
android:layout_margin="10dp"
android:src="@mipmap/ts1" />
<TextView
android:id="@+id/song_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/song_album"
android:text="you belong with me"
android:textSize="20sp" />
<TextView
android:id="@+id/singer_name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/song_album"
android:layout_toEndOf="@+id/song_album"
android:layout_toRightOf="@+id/song_album"
android:text="Taylar Swift"
android:textSize="15sp" />
<View
android:layout_width="300dp"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:layout_alignLeft="@+id/singer_name_tv"
/>
</RelativeLayout>
4.写MusicAdapter.java的代码,设置适配器:
创建两个全局变量,context和musicList,并且创建有参构造方法public MusicAdapter,给参数传值。用上缓存原理来创建行布局试图,创建行布局控件以及给行布局控件赋值。首先要创建一个ViewHoder类,定义行布局文件的属性。
//自己定义的适配器要继承BaseAdapter
public class MusicAdapter extends BaseAdapter {
public Context context;//
public List<Music> musicList;
public MusicAdapter(Context context, List<Music> musicList) {
this.context = context;
this.musicList = musicList;
}//创建有参构造方法,给参数传值。
@Override
public int getCount() {
return musicList.size();
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
View view1 = null;
ViewHolder viewHolder = null;
if (view == null) {
view1 = LayoutInflater.from(context).inflate(R.layout.item_list, null);
//创建布局视图
viewHolder = new ViewHolder();
viewHolder.titletv = view1.findViewById(R.id.song_name_tv);
viewHolder.artisttv = view1.findViewById(R.id.singer_name_tv);
//创建布局控件
view1.setTag(viewHolder);
}else {
view1=view;
viewHolder= (ViewHolder) view.getTag();
}
Music music=musicList.get(i);
viewHolder.titletv.setText(music.title);
viewHolder.artisttv.setText(music.artist+" - "+music.album);
//给行布局控件赋值
if(music.albumbtm!=null){
viewHolder.albumimg.setImageBitmap(music.albumbtm);
}else{
viewHolder.albumimg.setImageResource(R.mipmap.ts2);
//用if语句判断专辑图片是否不为null,如果不为null就引用它专辑图片,如果为null就给它一个默认的图片
return view1;
}
class ViewHolder {
TextView titletv;
TextView artisttv;
ImageView albumimg;
}
}
5.配置LocalFragment:
首先,在其XML布局文件里面写好ListView视图,在java代码里除了定义ListView和数组List,还需要定义第三方插件所需要的全局变量。
private ListView listView;
private List<Music> musicList = new ArrayList<>();
private PermissionHelper permissionHelper;//第三方插件所需要的变量
private String TAG = "HelloActivity";
引入第三方插件compile:在模块对应的build.gradle里的dependencies{}里加上:
compile ‘com.master.android:permissionhelper:1.3’
然后将其下载下来。
在AndroidManifest.xml文件里写上:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在LocalFragment.java文件中要实现动态获取读取手机音乐资源的权限,在前面已经将第三方插件下载好了,在这里直接引用就可以了:
permissionHelper = new PermissionHelper(this, new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
permissionHelper.request(new PermissionHelper.PermissionCallback() {
@Override
public void onPermissionGranted() {
Log.d(TAG, "onPermissionGranted() called");
initListView();// initListView()是自己定义的内部类,用来读取手机资源
} //用户允许获取权限后才执行此方法
@Override
public void onIndividualPermissionGranted(String[] grantedPermission) {
Log.d(TAG, "onIndividualPermissionGranted() called with:
grantedPermission = [" + TextUtils.join(",",grantedPermission) + "]");
}//要获取多条权限,用户允许获取其中的权限后才执行此方法
@Override
public void onPermissionDenied() {
Log.d(TAG, "onPermissionDenied() called");
}//用户拒绝获取权限后才执行此方法
@Override
public void onPermissionDeniedBySystem() {
Log.d(TAG, "onPermissionDeniedBySystem() called");
}//用户勾选不在询问此问题,不允许获取权限后才执行此方法
});
在initListView()这个方法中,先获取游标,再用do\while方法获取自己想要的资源,在获取图片资源时注意要将类型换为int型。
private void initListView() {
ContentResolver resolver = getActivity().getContentResolver();
//获取游标
Cursor cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
cursor.moveToFirst();//将游标放至第一位
do {
Music M = new Music();
M.title = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
//读取歌名
M.artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
//读取歌手名
M.album = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM));
//读取专辑名
int albumID=cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
M.albumbtm=getAlbumArt(albumID);
//读取专辑图片
musicList.add(M);
} while (cursor.moveToNext());
//当游标移到最后的时候,结束循环
cursor.close();
MusicAdapter musicAdapter = new MusicAdapter(getActivity(), musicList);
listView.setAdapter(musicAdapter);
}
/**
* 根据专辑ID获取专辑封面图
* @param album_id 专辑ID
* @return
*/
private Bitmap getAlbumArt(int albumID) {
String mUriAlbums = "content://media/external/audio/albums";
String[] projection = new String[]{"album_art"};
Cursor cur = getActivity().getContentResolver().query(Uri.parse(mUriAlbums + "/" + Integer.toString(albumID)), projection, null, null, null);
String album_art = null;
if (cur.getCount() > 0 && cur.getColumnCount() > 0) {
cur.moveToNext();
album_art = cur.getString(0);
}
cur.close();
Bitmap bm = null;
if (album_art != null) {
// Log.e("LOCAL",album_art);
bm = BitmapFactory.decodeFile(album_art);
}
return bm;
}
6.配置MainActivity代码:
在Mian活动里要实现两个Fragment的滑动切换和点击切换。
在MianActivity.java文件中绑定两个Fragment,给两个TextView设置监听事件。
在MianActivity.xml文件里除了设置两个TextView控件,还要写ViewPager控件:
<android.support.v4.view.ViewPager
android:id="@+id/mian_vp"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</android.support.v4.view.ViewPager>
MianActivity.java代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView localtv;
private TextView onlinetv;
private ViewPager viewPager;
private List<Fragment> fragmentList=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindID();
localtv.setOnClickListener(this);
onlinetv.setOnClickListener(this);
LocalFragment localFragment=new LocalFragment();
OnlineFragment onlineFragment=new OnlineFragment();
fragmentList.add(localFragment);
fragmentList.add(onlineFragment);
//绑定两个Fragment
MusicPagerAdapter pagerAdapter=new MusicPagerAdapter(getSupportFragmentManager(),fragmentList);
viewPager.setAdapter(pagerAdapter);
//创建适配器,启动适配器
}
//绑定ID
private void bindID() {
localtv = findViewById(R.id.main_local_tv);
onlinetv = findViewById(R.id.main_online_tv);
viewPager = findViewById(R.id.mian_vp);
}
//给两个控件添加点击事件
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.main_local_tv:
viewPager.setCurrentItem(0);
break;
case R.id.main_online_tv:
viewPager.setCurrentItem(1);
break;
default:
break;
}
}
}