Android Studio 開發實踐——簡易版音遊APP(二)

歌單頁面 (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關閉遊標
        }
    }


}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章