Android课设:简易音乐播放器

实验主题
本次课程设计计划实现一个低配版的仿网易云音乐的音乐播放器,主要实现功能如下:

  • 打开APP需先进行注册
  • 已有账号可进行登录
  • 登录后跳转至音乐界面,本地歌曲列表读取本地音乐文件并显示
  • 点击本地音乐中音乐列表页的歌曲跳转至播放页
  • 点击在线音乐中的网易云按钮可打开网易云网址
  • 播放页可实现对歌曲的暂停,继续,上一首,下一首以及回退至歌曲列表页
    在这里插入图片描述
    在这里插入图片描述
    activity_main为MainActivity的布局文件,显示注册界面。
    activity_login为login的布局文件,显示登录界面,
    activity_player是player的布局页面,显示主界面
    activity_music为Music_Activity的布局文件,显示音乐播放器界面。
    music_list和item_list一起组成play1的布局文件,就是音乐列表界面
    activity_play2就是play2的布局文件,就是在线音乐界面,可打开网易云。
    本地音乐文件
    实验内容
    在这里插入图片描述
 <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="25dp"
        android:text="用户名:"
        android:textColor="#000000"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_goneMarginLeft="20dp" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20dp"
        android:id="@+id/name"
        android:hint="请输入用户名">
    </EditText>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="密码:"
        android:textSize="25dp"
        android:textColor="#000000"
        android:layout_marginTop="10dp" />

        <com.example.musicplayer.Showpwd
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:id="@+id/pwd"
            android:hint="请输入密码">
        </com.example.musicplayer.Showpwd>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_weight="1">

           <Button
            android:id="@+id/register"
            android:layout_marginTop="20dp"
            android:layout_marginLeft="20dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="注册"
            android:textSize="20dp"
            android:background="#FFFFFF"/>

        <Button
            android:id="@+id/login"
            android:layout_marginTop="20dp"
            android:layout_marginLeft="100dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="已有账号,去登录"
            android:textSize="20dp"
            android:background="#FFFFFF"/>
    </LinearLayout>

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

    init();
}

private void init(){
    mContext = getApplicationContext();
    sh = new Sharehelp(mContext);

    //创建表
    dh=new Databasehelp(mContext,"mydb.db",null,1);
    db=dh.getWritableDatabase();
    final ContentValues values=new ContentValues();

    name=(EditText)findViewById(R.id.name);
    pwd=(Showpwd)findViewById(R.id.pwd);
    register=(Button)findViewById(R.id.register);
    login=(Button)findViewById(R.id.login);

    login.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
已有账号跳转至登录界面
            Intent intent=new Intent(MainActivity.this,Login.class);
            startActivity(intent);
        }
    });
    register.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
进行注册
            uname=String.valueOf(name.getText());
            upwd=String.valueOf(pwd.getText());
            values.put("name",uname);
            values.put("pwd",upwd);
            sh.save(uname,upwd);
            用户名和密码不能为空
            if(uname.equals("")||upwd.equals("")){
                Toast.makeText(MainActivity.this, "信息不全,请补充", Toast.LENGTH_SHORT).show();
            }
            else{
信息存入数据库
                db.insert("mydb",null,values);
                values.clear();
                Toast.makeText(MainActivity.this, "保存成功", Toast.LENGTH_SHORT).show();
                name.setText("");//保存成功清空信息
                pwd.setText("");
                //跳转至登录页面
                Intent intent=new Intent(MainActivity.this,Login.class);
                startActivity(intent);
            }

        }
    });
}

Database
在这里插入图片描述
创建名为mytb的表

public static final String CREATE_LIST="create table mydb("
        +"id integer primary key autoincrement,"
        +"name text,"
        +"pwd text)";

Sharehelp:
在这里插入图片描述

Showpwd:
实现密码的隐藏与显示:

private void init() {
        cl = mContext.getResources().getDrawable(R.drawable.close);//眼睛关闭图片
        op=mContext.getResources().getDrawable(R.drawable.open);//眼睛打开图片

        setInputType(129);
        setCompoundDrawablesWithIntrinsicBounds(null, null, cl, null);

        addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                setDrawable();
            }
        });
    }

    private void setDrawable(){
        if (length() < 1)
            setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
        else
            setCompoundDrawablesWithIntrinsicBounds(null, null, cl, null);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if(cl != null && event.getAction() == MotionEvent.ACTION_UP)
        {
            int eventX = (int) event.getRawX();
            int eventY = (int) event.getRawY();
            Rect rect = new Rect();
            getGlobalVisibleRect(rect);
            rect.left = rect.right - 100;
            if (rect.contains(eventX, eventY)) {
                if(flag==0){
                    setInputType(128);
                    setCompoundDrawablesWithIntrinsicBounds(null, null, op, null);
                    flag=1;
                }else{
                    setInputType(129);
                    setCompoundDrawablesWithIntrinsicBounds(null, null, cl, null);
                    flag=0;
                }
            }
        }
        return super.onTouchEvent(event);
    }
}

登录
在这里插入图片描述
主界面布局与注册功能无太大区别

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="25dp"
        android:text="用户名:"
        android:textColor="#000000"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_goneMarginLeft="20dp" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20dp"
        android:id="@+id/name"
        android:hint="请输入用户名">
    </EditText>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="密码:"
        android:textSize="25dp"
        android:textColor="#000000"
        android:layout_marginTop="10dp" />

    <com.example.musicplayer.Showpwd
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20dp"
        android:id="@+id/pwd"
        android:hint="请输入密码">
    </com.example.musicplayer.Showpwd>

    <Button
        android:id="@+id/login"
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="登录"
        android:textSize="20dp"
        android:background="#FFFFFF"/>
</LinearLayout>

在这里插入图片描述
音乐播放器
在这里插入图片描述

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="
        android:textSize="25dp"/>
</LinearLayout>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/menu1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="本地歌曲"
        android:textSize="25dp"/>
    <TextView
        android:id="@+id/menu2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="在线音乐"
        android:textSize="25dp"/>
</LinearLayout>
<FrameLayout
    android:id="@+id/content"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="9">
</FrameLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_player);
    content=(FrameLayout)findViewById(R.id.content);

    tv1=(TextView)findViewById(R.id.menu1);
    tv2=(TextView)findViewById(R.id.menu2);

    tv1.setOnClickListener(this);
    tv2.setOnClickListener(this);
    fm=getSupportFragmentManager();//若是继承FragmentActivity,fm=getFragmentManger();
    ft=fm.beginTransaction();
    ft.replace(R.id.content,new Play1());//默认情况下Fragment1
    ft.commit();
}

@Override
public void onClick(View v){
    ft=fm.beginTransaction();
    switch (v.getId()){
        case R.id.menu1:
            ft.replace(R.id.content,new Play1());
            break;
        case R.id.menu2:
            ft.replace(R.id.content,new Play2());
            break;
         default:
             break;
    }
    ft.commit();
}

本地歌曲页
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

private View view;
//本地歌曲歌名及歌手
public String[] name={"告五人——爱人错过","告五人——你要不要吃哈密瓜","告五人——温蒂公主的侍卫"};
//歌曲图片读取
public static int[] icons={R.drawable.music0,R.drawable.music1,R.drawable.music2};
@Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
//将上图布局加载进来
    view=inflater.inflate(R.layout.music_list,null);
    ListView listView=view.findViewById(R.id.lv);
    MyBaseAdapter adapter=new MyBaseAdapter();
    listView.setAdapter(adapter);
    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            Intent intent=new Intent(Play1.this.getContext(),Music_Activity.class);//创建Intent对象,启动check
            //将数据存入Intent对象
            intent.putExtra("name",name[position]);
            intent.putExtra("position",String.valueOf(position));
            startActivity(intent);
        }
    });
    return view;
}
class MyBaseAdapter extends BaseAdapter {//数据显示到list view中
    @Override
    public int getCount(){return  name.length;}
    @Override
    public Object getItem(int i){return name[i];}
    @Override
    public long getItemId(int i){return i;}

    @Override
    public View getView(int i ,View convertView, ViewGroup parent) {
        View view=View.inflate(Play1.this.getContext(),R.layout.item_list,null);
        TextView tv_name=view.findViewById(R.id.item_name);
        ImageView iv=view.findViewById(R.id.iv);

        tv_name.setText(name[i]);
        iv.setImageResource(icons[i]);
        return view;
    }
}

音乐播放页面
在这里插入图片描述

//为进度条添加事件监听
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        //进度条改变时,会调用此方法
        if (progress==seekBar.getMax()){//当进度条到末端时,结束动画
            animator.pause();//停止播放动画
        }
    }
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {//进度条开始滑动时调用
    }
    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {//进度条停止滑动时调用
        //根据拖动的进度改变音乐播放进度
        int progress=seekBar.getProgress();//获取seekBar的进度
        musicControl.seekTo(progress);//改变播放进度
    }
});
public static Handler handler=new Handler(){
    @Override
    public void handleMessage(Message msg){
        Bundle bundle=msg.getData();//获取从子线程发送过来的音乐播放进度
        int duration=bundle.getInt("duration");
        int currentPosition=bundle.getInt("currentPosition");
        sb.setMax(duration);
        sb.setProgress(currentPosition);
        //歌曲总时长
        int minute=duration/1000/60;
        int second=duration/1000%60;
        String strMinute=null;
        String strSecond=null;
        if(minute<10){//如果歌曲的时间中的分钟小于10
            strMinute="0"+minute;//在分钟的前面加一个0
        }else{
            strMinute=minute+"";
        }
        if (second<10){//如果歌曲中的秒钟小于10
            strSecond="0"+second;//在秒钟前面加一个0
        }else{
            strSecond=second+"";
        }
        tv_total.setText(strMinute+":"+strSecond);
        //歌曲当前播放时长
        minute=currentPosition/1000/60;
        second=currentPosition/1000%60;
        if(minute<10){//如果歌曲的时间中的分钟小于10
            strMinute="0"+minute;//在分钟的前面加一个0
        }else{
            strMinute=minute+" ";
        }
        if (second<10){//如果歌曲中的秒钟小于10
            strSecond="0"+second;//在秒钟前面加一个0
        }else{
            strSecond=second+" ";
        }
        tv_progress.setText(strMinute+":"+strSecond);
    }
};
上一首,下一首歌曲切换
private void preplay(){
    String position= intent1.getStringExtra("position");
    int i=parseInt(position);
    if(i==0)
        i=2;
    else
        i=(i-1)%3;
    musicControl.play(i);
    ImageView iv_music=(ImageView)findViewById(R.id.iv_music);
    iv_music.setImageResource(Play1.icons[i]);
    name_song=(TextView)findViewById(R.id.song_name);
    name_song.setText(names[i]);
    //animator.start();
}
private void nxtplay(){
    String position= intent1.getStringExtra("position");
    int i=parseInt(position);
    i=(i+1)%3;
    musicControl.play(i);
    ImageView iv_music=(ImageView)findViewById(R.id.iv_music);
    iv_music.setImageResource(Play1.icons[i]);
    name_song=(TextView)findViewById(R.id.song_name);
    name_song.setText(names[i]);
   // animator.start();
}
各个button功能实现:
@Override
public void onClick(View v) {
    switch (v.getId()){
        case R.id.btn_play://播放
            String position=intent1.getStringExtra("position");
            int i=parseInt(position);
            musicControl.play(i);
            animator.start();
            break;
        case R.id.btn_pause://暂停
            musicControl.pausePlay();
            animator.pause();
            break;
        case R.id.btn_continue_play://继续播放
            musicControl.continuePlay();
            animator.start();
            break;
        case R.id.btn_exit://退出
            unbind(isUnbind);
            isUnbind=true;
            finish();
            break;
        case R.id.btn_pre://上一首
            preplay();
            break;
        case R.id.btn_nxt://下一首
            nxtplay();
            break;
    }
}

Musicservice:
进度条方法:
public void addTimer(){ //添加计时器用于设置音乐播放器中的播放进度条
    if(timer==null){
        timer=new Timer();//创建计时器对象
        TimerTask task=new TimerTask() {
            @Override
            public void run() {
                if (player==null) return;
                int duration=player.getDuration();//获取歌曲总时长
                int currentPosition=player.getCurrentPosition();//获取播放进度
                Message msg=Music_Activity.handler.obtainMessage();//创建消息对象
                //将音乐的总时长和播放进度封装至消息对象中
                Bundle bundle=new Bundle();
                bundle.putInt("duration",duration);
                bundle.putInt("currentPosition",currentPosition);
                msg.setData(bundle);
                //将消息发送到主线程的消息队列
                Music_Activity.handler.sendMessage(msg);
            }
        };
        //开始计时任务后的5毫秒,第一次执行task任务,以后每500毫秒执行一次
        timer.schedule(task,5,500);
    }
}
设置播放器:
class MusicControl extends Binder {//Binder是一种跨进程的通信方式
    public void play(int i){//String path
        Uri url=Uri.parse("android.resource://"+getPackageName()+"/raw/"+"music"+i);
        try{
            player.reset();//重置音乐播放器
            //加载多媒体文件
            player=MediaPlayer.create(getApplicationContext(),url);
            player.start();//播放音乐
            addTimer();//添加计时器
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    public void pausePlay(){
        if(player.isPlaying()){
            player.pause();//暂停播放音乐
        }
    }
    public void continuePlay(){
        player.start();//继续播放音乐
    }
    public void seekTo(int progress){
        player.seekTo(progress);//设置音乐的播放位置
    }
}

在这里插入图片描述
在这里插入图片描述
设置网络
在这里插入图片描述

public class Play2  extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.activity_play2, null);
        Button btn=view.findViewById(R.id.wyy);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Uri uri = Uri.parse("https://music.163.com");//要跳转的网址
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                startActivity(intent);

            }
        });
        return view;
    }
}
  • 10
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值