歌单页面 (MusicViewActivity)
1. Music类
package com.example.free.Classes;
public class Music {
private String name="";//歌曲名
private String path="";//歌曲在存储中的路径
private long size=0;//歌曲大小
private long time=0;//歌曲时长
public Music(String _name,String _path,long _size,long _time){
name=_name;
path=_path;
size=_size;
time=_time;
}
public String getName(){
return name;
}
public String getPath(){
return path;
}
public long getSize(){
return size;
}
public long getTime(){
return time;
}
}
2. activity_music_view.xml
RecyclerView的样式,后面活动页面通过访问它的id,适配adapter来传递子项item的样式和数据。比ListView更灵活,具体区别不做赘述。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MusicViewActivity">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/recyclerView">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
3. music_item.xml
RecyclerView的每一个item的具体样式,在MusicAdapter向ViewHolder传该样式。
<?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="wrap_content"
><!--注意这里的height是不是match_parent,不然会是一个子项占了一整个页面-->
<ImageView
android:id="@+id/imageLeft"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginTop="5dp"
android:src="@drawable/_note"
/><!--这里是一个音符符号的图片-->
<TextView
android:layout_width="match_parent"
android:layout_height="60dp"
android:id="@+id/textView"
android:textColor="@color/colorBlack"
android:gravity="center_vertical"
android:textIsSelectable="false"
android:layout_margin="5dp"
android:padding="5dp"
android:textSize="18dp">
</TextView>
</LinearLayout>
4. MusicAdapter
为RecyclerView分配每一个子项。
package com.example.free.Classes;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.free.OriginChoiceActivity;
import com.example.free.R;
import java.util.List;
//以下都是沿袭了RecyclerView.Adapter的结构,具体原理不做赘述
public class MusicAdapter extends RecyclerView.Adapter<MusicAdapter.ViewHolder> {
private List<Music> musicList;
//传入Music音乐列表,方面后面ViewHolder更新当前页面数据
public MusicAdapter(List<Music> _musicList) {
musicList=_musicList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//得到每一项的样式view,不继承parent
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.music_item,parent,false);
//只在adapter创建的时候向ViewHolder传一次子项样式
final ViewHolder viewHolder=new ViewHolder(view);
final Context context=parent.getContext();//得到当前上下文活动,方便后面intent传会话
//实现每个子项的点击效果(点击完把音乐信息传给下一个界面)
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position=viewHolder.getAdapterPosition();//得到当前音乐index
Music music=musicList.get(position);//得到音乐信息
String musicPath=music.getPath();
long musicSize=music.getSize();
long musicTime=music.getTime();
Intent intent=new Intent(context, OriginChoiceActivity.class);//转入模式选择界面
intent.putExtra("musicPath",musicPath);//会话同时传递歌曲信息,下个活动选完模式后再把信息继续传给游戏界面
intent.putExtra("musicSize", musicSize);
intent.putExtra("musicTime",musicTime);
context.startActivity(intent);
}
});
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int position) {
Music music=musicList.get(position);
viewHolder.textView.setText(music.getName());
}
@Override
public int getItemCount() {
return musicList.size();
}
//内部类ViewHolder,就是实现了一层封装
class ViewHolder extends RecyclerView.ViewHolder{
//ViewHolder在adapter新建时储存控件实例/样式,这样在后面就不用一直findViewById查找子样式
TextView textView;//子项文本内容,对应onBindViewHolder里的setText,adapter及时更新当前页面子项信息
ViewHolder(View view){
super(view);
textView=view.findViewById(R.id.textView);
}
}
}
5. MusicViewActivity
具体歌单页面,适配MusicAdapter,初始化musicList,将音乐信息传给adapter。
通过调用本地数据库MediaStore.Audio.Media.EXTERNAL_CONTENT_URI来查找所有音乐文件,不用自己写代码过滤全部的目录。
package com.example.free;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import com.example.free.Classes.BaseActivity;
import com.example.free.Classes.Music;
import com.example.free.Classes.MusicAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MusicViewActivity extends BaseActivity {
//该项目的所有活动(除首页)都继承自BaseActivity,方便调试及实现广播,避免一个活动点击多次出现重复页面的情况
List<Music> musicList=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music_view);//通过啊id加载进来activity_music_view.xml的视图
setTitle("选择歌曲");//当前页面bar的标题,就是页面最上方的位置
initMusics();//调用后面初始化音乐列表的方法
RecyclerView recyclerView=findViewById(R.id.recyclerView);//找到里面的瀑布流视图
LinearLayoutManager layoutManager=new LinearLayoutManager(this);//线性布局管理器,可自行设置布局
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);//设置垂直分布布局
recyclerView.setLayoutManager(layoutManager);//将布局管理器配给该瀑布流
MusicAdapter musicAdapter=new MusicAdapter(musicList);//新建adapter,将音乐列表参数传进去
recyclerView.setAdapter(musicAdapter);//瀑布流运用该适配器
}
//初始化音乐列表方法
public void initMusics() {
Cursor cursor = null;//初始化游标,(同访问数据库的query用法)
try {
//这里是利用了自带的数据库,不用从sd卡里过滤目录
cursor = getApplicationContext().getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
, null, null, null, MediaStore.Audio.AudioColumns.IS_MUSIC);//查看外存是音乐的文件;
if (cursor != null) {
while (cursor.moveToNext()) {
//得到音乐名字
String name=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
//得到音乐文件路径
String path=cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
//得到音乐文件大小
long size=cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.SIZE));
//得到音乐时长
long time=cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DURATION));
if(name!=null)//这里一定要先判断是否为空,否则后面的.contains方法会报错
if(name.contains(".wav")||name.contains(".mp3"))
musicList.add(new Music(name,path,size,time));
//本项目只实现了wav和mp3格式音乐文件的自动识别节奏
}
}
Collections.reverse(musicList);//倒置按时间顺序排序,使最新下载的音乐在最上方
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();//这里记得finally关闭游标
}
}
}