【达内课程】音乐播放器2.0(上)

我们对 音乐播放器v1.0 进行改进。

1、把获取数据部分提取出来

增加 Music 信息的数据访问类 MusicDao。我们把 MainActivity 中使用 getData() 放到这里稍加修改即可。

/**
 * Music信息的数据访问类
 * Data Access Object
 */
public class MusicDao {
    public List<Music> getMusicList() {
        List<Music> musics = new ArrayList<>();

        File musicDir = Environment.getExternalStoragePublicDirectory
                (Environment.DIRECTORY_MUSIC);
        Log.d("MUSIC", Environment.getExternalStorageState());
        if (musicDir.exists()) {
            Log.d("MUSIC", "【信息】文件夹存在");
            File[] files = musicDir.listFiles();
            if (files != null && files.length > 0) {
                Log.d("MUSIC", "【信息】文件夹列表有效");
                for (int i = 0; i < files.length; i++) {
                    if (files[i].isFile()) {
                        String fileName = files[i].getName();
                        if (fileName.toLowerCase().endsWith(".mp3")) {
                            Music music = new Music();
                            music.setPath(files[i].getAbsolutePath());
                            music.setTitle(files[i].getName());
                            musics.add(music);
                            Log.d("MUSIC", files[i].getAbsolutePath());
                        } else {
                            Log.w("MUSIC", "【错误】当前遍历到的不是mp3文件");
                        }
                    } else {
                        Log.w("MUSIC", "【错误】当前遍历到的第" + i + "个不是文件");
                    }
                }
            } else {
                Log.w("MUSIC", "【错误】文件夹列表无效");
            }
        } else {
            Log.w("MUSIC", "【错误】文件夹不存在");
        }
        return musics;
    }
}

MainActivity 中 onCreate() 中加载数据的时候把getData改为使用 MusicDao 获取,直接让变量 musics 赋值即可。同时改为在 initView() 之前获取,因为initView()中就需要用到音乐数据了。以下代码即可:

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

        //获取数据
        MusicDao dao = new MusicDao();
        musics = dao.getMusicList();
        //初始化控件
        initView();
        //添加点击事件
        initListener();
    }

private void initView() {
        listView = findViewById(R.id.listview);
        adapter = new MusicAdapter(this, musics);
        listView.setAdapter(adapter);

        ......
    }

2、创建不同的包
在这里插入图片描述

Activity 可以放在 Activity 或 UI 包中
DAL 表示 Data Access Layer
Entity 里面放实体类

3、Adapter的改进

增加 BaseAdapter

public class BaseAdapter<T> extends android.widget.BaseAdapter {
    private Context context;
    private List<T> data;
    private LayoutInflater inflater;

    public BaseAdapter(Context context, List<T> data) {
        this.context = context;
        this.data = data;
        inflater = LayoutInflater.from(this.context);
    }

    protected final List<T> getData(){
        return data;
    }

    protected final LayoutInflater getLayoutInflater(){
        return inflater;
    }

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

    @Override
    public Object getItem(int position) {
        return data.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return null;
    }
}

MusicAdapter 改为继承 BaseAdapter。因为需要 data 和 inflater,所以之前的 BaseAdapter 中有对应的 getData()getLayoutInflater() 方法方便获取。

public class MusicAdapter extends BaseAdapter<Music> {

    public MusicAdapter(Context context, List<Music> data) {
        super(context, data);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = getLayoutInflater().inflate(R.layout.item_music, null);
        }

        Music music = getData().get(position);
        TextView tv_music_path = convertView.findViewById(R.id.tv_music_path);
        TextView tv_music_title = convertView.findViewById(R.id.tv_music_title);
        tv_music_path.setText(music.getPath());
        String fileName = music.getTitle();
        tv_music_title.setText(fileName.substring(0, fileName.lastIndexOf(".")));

        return convertView;
    }
}

4、BaseAdapter 还能优化

思考一个问题,当我们创建 MusicAdapter 对象时 Context 传 null

adapter = new MusicAdapter(null,musics);

语法没错误,但是程序运行会报错,因为构造方法中用到了 context,所以会报空指针的错误
在这里插入图片描述
因此可以对 BaseAdapter 进行改进,给 Context 增加 get 方法,在为空时抛出异常,为了保持统一,也给 data 和 inflater 也增加 get 方法。

public class BaseAdapter<T> extends android.widget.BaseAdapter {
    ......

    public BaseAdapter(Context context, List<T> data) {
        setContext(context);
        setData(data);
        setInflater();
        setInflater();
    }

    private final void setContext(Context context) {
        if (context == null) {
            throw new IllegalArgumentException("参数Context不允许为null");
        }
        this.context = context;
    }

    private final void setData(List<T> data) {
        if (data == null) {
            data = new ArrayList<T>();
        }
        this.data = data;
    }

    private void setInflater() {
        inflater = LayoutInflater.from(context);
    }

    protected final List<T> getData() {
        return data;
    }

    protected final LayoutInflater getLayoutInflater() {
        return inflater;
    }
    ......
}

这样当我们创建 MusicAdapter 对象时 Context 再传 null 时,报错会更明显。
在这里插入图片描述
5、对 MusicDao 改造
MusicDao 的作用是获取歌曲信息,在 MainActivity 中使用时:

//获取歌曲数据
MusicDao dao = new MusicDao();
musics = dao.getMusicList();

如果还有其他 Activity 获取数据时也要写同样的代码,如果发现 MusicDao 写的不合理,要改成 MusicDao2,那么所有 Activity 都要改,这说明对 MusicDao 的依赖性太大,要减少对 MusicDao 的依赖,用到的是工厂模式。

首先找出只要是 MusicDao 的共同点,都有getData()方法,所以先写一个接口 IDao

public interface IDao<T> {
    /**
     * 获取数据
     *
     * @return 数据的List集合
     */
    List<T> getData();
}

再让 MusicDao 实现这个接口,把 getMusicList() 的内容放到 getData() 中。

创建工厂 MusicDaoFactory

public class MusicDaoFactory {
    public static IDao<Music> newInstance() {
        return new MusicDao();
    }
}

MainActivity 获取数据时可以这样写:

//获取数据
IDao<Music> dao = MusicDaoFactory.newInstance();
musics = dao.getData();

工厂中的接口,就是约定要实现的哪些方法。接口是用来约定规范和标准的,因为实现一个接口就要实现对应的方法。

MusicDao 实现了 IDao 的接口,就是 IDao 类型的数据了。

最后可以把 MusicDao 的 public 去掉,在当前包内访问到即可在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值