android本地音乐播放(一)

实体类Music
package cn.tedu.music_player_1;

public class Music {

private String name;
private String path;

public String getPath() {
    return path;
}

public void setPath(String path) {
    this.path = path;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}

Activity代码,带注释

package cn.tedu.music_player_1;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Random;

import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;

public class MainActivity extends Activity {
// 歌曲的数据
private List musics;
// ListView
private ListView lvMusics;
// Adapter
private MusicAdapter musicAdapter;
// MediaPlayer
private MediaPlayer player;
// ImageButton:播放/暂停
private ImageButton ibPlayOrPause;
// ImageButton:上一首
private ImageButton ibPrevious;
// ImageButton:下一首
private ImageButton ibNext;
// Button:播放模式
private Button btnPlayMode;
// TextView:当前播放的歌曲名称
private TextView tvMusicTitle;
// TextView:当前播放的歌曲的时长
private TextView tvMusicDuration;
// TextView:当前播放到的时间(播放过程中)
private TextView tvMusicCurrentPosition;
// SeekBar:歌曲的播放进度
private SeekBar sbMusicProgress;
// 暂停时播放到的位置
private int pausePosition;
// 当前播放的歌曲的索引
private int currentMusicIndex;
// 格式化时间的工具
private SimpleDateFormat sdf = new SimpleDateFormat(“mm:ss”, Locale.CHINA);
// 被格式化的时间对象
private Date date = new Date();
// 更新进度的线程
private UpdateProgressThread updateProgressThread;
// 是否是第1次点击列表项
private boolean isFirstClickListItem = true;
// 用户是否正在拖拽进度条
private boolean isUserTrackingTouch;
// 生成随机数据的工具
private Random random = new Random();
// 播放模式
private int playMode;
// 播放模式对应的字符串,用于显示在Button中
public static final String[] PLAY_MODE_TEXT = { “顺”, “随”, “单” };
// 播放模式 – 顺序播放
private static final int PLAY_MODE_ORDER = 0;
// 播放模式 – 随机播放
private static final int PLAY_MODE_RANDOM = 1;
// 播放模式 – 单曲循环
private static final int PLAY_MODE_SINGLE = 2;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 设置歌曲数据
    setMusicData();

    // 初始化播放工具
    player = new MediaPlayer();

    // 为MediaPlayer配置监听器
    player.setOnCompletionListener(new OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            next();
        }
    });

    // 初始化控件
    lvMusics = (ListView) findViewById(R.id.lv_musics);
    ibPlayOrPause = (ImageButton) findViewById(R.id.ib_play_or_pause);
    ibPrevious = (ImageButton) findViewById(R.id.ib_previous);
    ibNext = (ImageButton) findViewById(R.id.ib_next);
    tvMusicTitle = (TextView) findViewById(R.id.tv_music_title);
    tvMusicDuration = (TextView) findViewById(R.id.tv_music_duration);
    tvMusicCurrentPosition = (TextView) findViewById(R.id.tv_music_current_position);
    sbMusicProgress = (SeekBar) findViewById(R.id.sb_music_progress);
    btnPlayMode = (Button) findViewById(R.id.btn_play_mode);

    // 创建Adapter
    musicAdapter = new MusicAdapter(this, musics);

    // 为ListView配置Adapter
    lvMusics.setAdapter(musicAdapter);

    // 为按钮配置监听器
    InnerOnClickListener listener1 = new InnerOnClickListener();
    ibPlayOrPause.setOnClickListener(listener1);
    ibPrevious.setOnClickListener(listener1);
    ibNext.setOnClickListener(listener1);
    btnPlayMode.setOnClickListener(listener1);

    // 为ListView配置监听器
    InnerOnItemClickListener listener2 = new InnerOnItemClickListener();
    lvMusics.setOnItemClickListener(listener2);

    // 为SeekBar配置监听器
    InnerOnSeekBarChangeListener listener3 = new InnerOnSeekBarChangeListener();
    sbMusicProgress.setOnSeekBarChangeListener(listener3);
}

@Override
protected void onDestroy() {
    // 线程运行结束
    stopUpdateProgressThread();

    // 释放播放器资源
    player.release();
    player = null;

    super.onDestroy();
}

private class UpdateProgressThread extends Thread {
    // 播放的进度值
    private int progress;
    // 当前播放到的时间的字符串
    private String timeString;
    // 线程的运行控制变量
    private boolean isRunning;
    // 运行在主线程更新UI的对象
    private Runnable runner = new Runnable() {
        @Override
        public void run() {
            // 判断用户是否正在拖拽进度条
            if (!isUserTrackingTouch) {
                // 更新SeekBar
                sbMusicProgress.setProgress(progress);
            }
            // 更新TextView
            tvMusicCurrentPosition.setText(timeString);
        }
    };

    // 设置线程是否循环
    public void setRunning(boolean isRunning) {
        this.isRunning = isRunning;
    }

    @Override
    public void run() {
        while (isRunning) {
            // 日志
            Log.i("tedu", "Thread(" + Thread.currentThread().getId() + ")尝试更新进度 ... ...");
            // 判断当前是否处于播放状态
            if (player.isPlaying()) {
                // 获取当前歌曲播放到的位置,计算得到显示的数据
                progress = player.getCurrentPosition() * 100 / player.getDuration();
                date.setTime(player.getCurrentPosition());
                timeString = sdf.format(date);

                // 执行更新
                runOnUiThread(runner);
            }

            // 休眠
            try {
                Thread.sleep(450);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

private class InnerOnSeekBarChangeListener implements OnSeekBarChangeListener {
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {
        // 当开始拖拽时,标识用户开始拖拽进度条
        isUserTrackingTouch = true;
    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {
        // 获取进度
        int progress = sbMusicProgress.getProgress();
        // 计算播放的时间点
        pausePosition = player.getDuration() * progress / 100;
        // 播放
        play();
        // 标识用户已经停止拖拽进度条
        isUserTrackingTouch = false;
    }

    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        // 当进度值发生变化时:可能由于程序更新了进度,或者用户正在拖拽的过程中
    }

}

private class InnerOnItemClickListener implements OnItemClickListener {

    @Override
    public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
        // 判断点击的列表项的position是否匹配当前播放的歌曲的索引
        if (isFirstClickListItem || position != currentMusicIndex) {
            // 确定需要播放的歌曲的索引,直接对应点击的列表项的position
            currentMusicIndex = position;
            // 清除暂停位置
            pausePosition = 0;
            // 执行播放
            play();
            // 清除记录第1次点击
            isFirstClickListItem = false;
        }
    }

}

private class InnerOnClickListener implements OnClickListener {

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_play_mode:
            // 计算播放模式变量的值
            playMode++;
            playMode = playMode % 3;
            // 设置按钮上显示的文字
            btnPlayMode.setText(PLAY_MODE_TEXT[playMode]);
            break;

        case R.id.ib_play_or_pause:
            // 判断当前是否正在播放
            if (player.isPlaying()) {
                // 正在播放,则暂停
                pause();
            } else {
                // 没有播放,则播放
                play();
            }
            break;

        case R.id.ib_previous:
            // 播放上一首
            previous();
            break;

        case R.id.ib_next:
            // 播放下一首
            next();
            break;
        }
    }

}

// 开启线程
private void startUpdateProgressThread() {
    if (updateProgressThread == null) {
        updateProgressThread = new UpdateProgressThread();
        updateProgressThread.setRunning(true);
        updateProgressThread.start();
    }
}

// 停止线程
private void stopUpdateProgressThread() {
    if (updateProgressThread != null) {
        updateProgressThread.setRunning(false);
        updateProgressThread = null;
    }
}

// 播放歌曲
private void play() {
    try {
        // 1. 重置
        player.reset();
        // 2. 设置歌曲路径
        player.setDataSource(musics.get(currentMusicIndex).getPath());
        // 3. 缓冲
        player.prepare();
        // 4. 快进
        player.seekTo(pausePosition);
        // 5. 播放
        player.start();
        // 6. 将按钮显示为“暂停”
        ibPlayOrPause.setImageResource(android.R.drawable.ic_media_pause);
        // 7. 显示歌曲的名称
        tvMusicTitle.setText("当前播放:" + musics.get(currentMusicIndex).getName());
        // 8. 显示歌曲的时长
        date.setTime(player.getDuration()); // 设置需要被格式化的时间
        tvMusicDuration.setText(sdf.format(date)); // 显示
        // 9. 开启线程,更新进度
        startUpdateProgressThread();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// 暂停播放
private void pause() {
    // 执行暂停
    player.pause();
    // 记录当前播放到的位置
    pausePosition = player.getCurrentPosition();
    // 将按钮显示为“播放”
    ibPlayOrPause.setImageResource(android.R.drawable.ic_media_play);
    // 停止更新进度的线程
    stopUpdateProgressThread();
}

// 播放上一首
private void previous() {
    // 计算上一首歌曲的索引
    currentMusicIndex--;
    if (currentMusicIndex < 0) {
        currentMusicIndex = musics.size() - 1;
    }
    // 清除记录的暂停位置
    pausePosition = 0;
    // 执行播放
    play();
}

// 播放下一首
private void next() {
    switch (playMode) {
    case PLAY_MODE_ORDER:
        // 计算下一首歌曲的索引
        currentMusicIndex++;
        if (currentMusicIndex >= musics.size()) {
            currentMusicIndex = 0;
        }
        break;

    case PLAY_MODE_RANDOM:
        // 随机生成需要播放的歌曲的索引
        int i;
        while ((i = random.nextInt(musics.size())) == currentMusicIndex) {
        }
        currentMusicIndex = i;
        break;

    case PLAY_MODE_SINGLE:
        break;
    }

    // 清除记录的暂停位置
    pausePosition = 0;
    // 执行播放
    play();
}

// 设置歌曲数据
private void setMusicData() {
    // 初始化List集合
    musics = new ArrayList<Music>();

    // 检查sdcard的状态,即是否可用
    if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
        // 获取sdcard下Music文件夹的File对象
        File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
        // 通过exists()方法检查Music文件夹是否存在
        if (dir.exists()) {
            // 通过listFiles()方法获取Music文件夹下所有文件的File对象,获取的结果是File[]
            File[] files = dir.listFiles();
            // 判断数组是否为null
            if (files != null) {
                // 遍历数组
                for (int i = 0; i < files.length; i++) {
                    // 检查遍历到的是否是文件,而不是文件夹
                    if (files[i].isFile()) {
                        // 检查遍历到的是否是mp3文件
                        if (files[i].getName().toLowerCase(Locale.CHINA).endsWith(".mp3")) {
                            // 如果是mp3文件,则创建Music对象,并添加到List集合中
                            Music music = new Music();
                            music.setPath(files[i].getAbsolutePath());
                            music.setName(files[i].getName().substring(0, files[i].getName().length() - 4));
                            musics.add(music);
                            Log.i("tedu", "扫描到MP3文件:" + music.getName() + ",路径:" + music.getPath());
                        } else {
                            Log.w("tedu", "遍历到File对象" + files[i] + "不是MP3文件!忽略!");
                        }
                    } else {
                        Log.w("tedu", "遍历到File对象" + files[i] + "是文件夹!忽略!");
                    }
                }
            } else {
                Log.w("tedu", "获取Music文件夹的内容失败!");
            }
        } else {
            Log.w("tedu", "sdcard下Music文件夹不存在!");
        }
    } else {
        Log.w("tedu", "sdcard不可用!");
    }
}

}

适配器adapter 具体代码

package cn.tedu.music_player_1;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MusicAdapter extends BaseAdapter {
private Context context;
private List musics;

public MusicAdapter(Context context, List<Music> musics) {
    super();
    this.context = context;
    this.musics = musics;
}

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

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // 1. 获取需要显示的数据
    Music music = musics.get(position);

    // 2. 判断有没有可以直接使用的convertView
    if(convertView == null) {
        // 2.1 如果没有,则通过XML加载得到
        LayoutInflater inflater = LayoutInflater.from(context);
        convertView = inflater.inflate(R.layout.music_item, null);
    } else {
        // 2.2 如果有,则直接使用
    }

    // 3. 组装数据与模板
    TextView tvName = (TextView) convertView.findViewById(R.id.tv_music_item_name);
    tvName.setText(music.getName());
    TextView tvPath = (TextView) convertView.findViewById(R.id.tv_music_item_path);
    tvPath.setText(music.getPath());

    // 4. 返回convertView
    return convertView;
}


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

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

}

activity_main.XML布局文件

你可能感兴趣的:(android,本地音乐播放)