请看效果
简单的音乐播放器
开发工具:Android Studio
涉及到的类:
涉及到的layout(有一个是多余的item_layout.xml)
悄悄说一句:有的命名不规范,勿怪。
登录界面
登录界面 activity_login.xml
登录界面 MyActivityLogin
import android.app.Activity; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.widget.Toolbar; import androidx.core.app.NotificationCompat; import com.example.mymusic.R; public class MyActivityLogin extends Activity { private static final String TAG = "lzs"; Button btn; EditText num; EditText pw; String num1; String password; Intent intent1; private NotificationManager notificationManager; private Notification notification; private Toolbar toolbar; private Button btn_login; private SharedPreferences sp; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); ActivityCollector.addActivity(this); num = findViewById(R.id.num); pw = findViewById(R.id.pw); sp = getSharedPreferences("mrsoft",MODE_PRIVATE); //注册 //自动登录 //手动登录 } @Override public void onStart() { super.onStart(); } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); } @Override public void onStop() { super.onStop(); } @Override public void onRestart() { super.onRestart(); } @Override public void onDestroy() { super.onDestroy(); ActivityCollector.removeActivity(this); } //重写onActivityResult @Override protected void onActivityResult(int requestCode,int resultCode,Intent data){ super.onActivityResult(requestCode,resultCode,data); if(requestCode == 1 && resultCode == 1){ String returnData = data.getStringExtra("data"); TextView tvDo = (TextView) findViewById(R.id.tvDoThing); tvDo.setText(returnData); } } //注册 public void two5(View view) { boolean b = num.getText().toString()==null; boolean c= pw.getText()==null; Log.i(TAG, "two5: "+b); Log.i(TAG, "two5: "+c); Log.i(TAG, "two5: "+num.getText()); Log.i(TAG, "two5: "+pw.getText()); if(!TextUtils.isEmpty(num.getText()) && !TextUtils.isEmpty(pw.getText())) { String in_username = num.getText().toString(); //获取输入的账号 String in_password = pw.getText().toString(); //获取输入的密码 SharedPreferences.Editor editor = sp.edit(); //获取Editer对象 editor.putString("username",in_username); //保存账号 editor.putString("password",in_password); //保存密码 editor.commit(); Toast.makeText(MyActivityLogin.this,"注册成功",Toast.LENGTH_SHORT).show(); //捕获数据并封装数据 num1 = num.getText().toString(); password = pw.getText().toString(); intent1 = new Intent(this,MyActivityZhuce.class); intent1.putExtra("id",num1); intent1.putExtra("ps",password); startActivityForResult(intent1,1); notificationManager.notify(1,notification); }else { Toast.makeText(MyActivityLogin.this,"账号或密码填写错误",Toast.LENGTH_SHORT).show(); } } //登录 public void two6(View view) { if(!TextUtils.isEmpty(num.getText()) && !TextUtils.isEmpty(pw.getText())){ String username = sp.getString("username","null");//获取账号 String password = sp.getString("password","null");//获取密码 String in_username = num.getText().toString(); //获取输入的账号 String in_password = pw.getText().toString(); //获取输入的密码 SharedPreferences.Editor editor = sp.edit(); //获取Editer对象 if(in_username.equals(username) && in_password.equals(password)){ //跳转 Intent it1 = new Intent(MyActivityLogin.this, MainActivity1.class); startActivity(it1); Toast.makeText(MyActivityLogin.this,"登录成功",Toast.LENGTH_SHORT).show(); }else { Toast.makeText(MyActivityLogin.this,"账号或密码错误",Toast.LENGTH_SHORT).show(); } }else { Toast.makeText(MyActivityLogin.this,"账号或密码填写错误",Toast.LENGTH_SHORT).show(); } } }
注册页面
注册页面 activity_three.xml (这命名你们可以改一下,我现在才发现,就不改了)
注册页面 MyActivityZhuce
import android.app.alertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.EditText; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import com.example.mymusic.R; public class MyActivityZhuce extends AppCompatActivity { TextView tv; private static final String TAG="lzs"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_three); ActivityCollector.addActivity(this); tv=findViewById(R.id.tishi); Intent intent = getIntent(); String id = intent.getStringExtra("id"); String ps = intent.getStringExtra("ps"); tv.setText("您好,欢迎您!"+id+"您的密码是:"+ps); } @Override public void onStart() { super.onStart(); } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); } @Override public void onStop() { super.onStop(); } @Override public void onRestart() { super.onRestart(); } @Override public void onDestroy() { super.onDestroy(); ActivityCollector.removeActivity(this); } //隐式启动 public void three(View view){ Intent intent = new Intent(MyActivityZhuce.this,MyActivityLogin.class); startActivity(intent); } }
音乐播放列表页面
首先解释一下,这个页面的布局情况,它是activity里放了fragment的,实现歌曲和专辑两选项的切换,如下图(左边的是activity,右边是fragment)
左边activity_main_music2.xml
右边music_list.xml
专辑页面 frag2_layout.xml(我就放了一个ListView,并且没有设置样式和内容,有兴趣的可以自己加一些专辑图片什么的)
每首音乐的 item样式item_local_music.xml(可以根据兴趣设置自己的样式)
到此我把音乐播放列表的布局都讲完了,接下来是它们的逻辑。
MainActivity1 类
import android.os.Bundle; import android.view.KeyEvent; import android.view.View; import android.widget.frameLayout; import android.widget.ImageView; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import com.example.mymusic.R; import com.synnapps.carouselview.CarouselView; import com.synnapps.carouselview.ImageClickListener; import com.synnapps.carouselview.ImageListener; public class MainActivity1 extends AppCompatActivity implements View.onClickListener { private frameLayout content; private TextView tv1,tv2; private FragmentManager fm; private FragmentTransaction ft; CarouselView carouselView; private int[] images = new int[]{ R.drawable.img11, R.drawable.img22, R.drawable.img33, R.drawable.img44, R.drawable.img55 }; private com.example.mymusic.mymusic.frag1 mFragmentConversation; private frag2 mFragmentConversation2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main_music2); ActivityCollector.addActivity(this); carouselView = findViewById(R.id.carouselView); //设置轮播图的页面数量 carouselView.setPageCount(images.length); carouselView.setImageListener(imageListener); carouselView.setImageClickListener(new ImageClickListener() { @Override public void onClick(int position) { } }); 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 com.example.mymusic.mymusic.frag1());//默认情况下Fragment1 ft.commit(); InitFragment(); getSupportFragmentManager().beginTransaction() .add(R.id.content, mFragmentConversation).commit(); } private void InitFragment() { mFragmentConversation = new com.example.mymusic.mymusic.frag1(); mFragmentConversation2 = new frag2(); } ImageListener imageListener = new ImageListener() { @Override public void setImageForPosition(int position, ImageView imageView) { imageView.setImageResource(images[position]); } }; @Override public void onClick(View v){ ft=fm.beginTransaction(); FragmentTransaction mTransaction = getSupportFragmentManager() .beginTransaction(); switch (v.getId()){ case R.id.menu1: if (!getSupportFragmentManager().getFragments().contains(mFragmentConversation)) { mTransaction.add(R.id.content, mFragmentConversation); } mTransaction.show(mFragmentConversation); HideOtherFragments(mFragmentConversation); break; case R.id.menu2: if (!getSupportFragmentManager().getFragments().contains(mFragmentConversation2)) { mTransaction.add(R.id.content, mFragmentConversation2); } mTransaction.show(mFragmentConversation2); HideOtherFragments(mFragmentConversation2); break; default: break; } mTransaction.commit(); } private void HideOtherFragments(Fragment fragment) { if (getSupportFragmentManager().getFragments() == null) { return; } for (Fragment fm : getSupportFragmentManager().getFragments()) { if (fm != fragment) { getSupportFragmentManager().beginTransaction().hide(fm) .commit(); } } } @Override protected void onDestroy() { super.onDestroy(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode == KeyEvent.KEYCODE_BACK){ moveTaskToBack(true); return true; } return super.onKeyDown(keyCode, event); } }
数据源类 localMusicBean
package com.example.mymusic.mymusic; import java.io.Serializable; public class localMusicBean implements Serializable { private String id; //歌曲id private String song; //歌曲名称 private String singer; //歌手名称 private String album; //专辑名称 private String duration; //歌曲时长 private String path; //歌曲路径 private String albumArt; //专辑地址 public localMusicBean() { } public localMusicBean(String id, String song, String singer, String album, String duration, String path, String albumArt) { this.id = id; this.song = song; this.singer = singer; this.album = album; this.duration = duration; this.path = path; this.albumArt = albumArt; } public String getAlbumArt() { return albumArt; } public void setAlbumArt(String albumArt) { this.albumArt = albumArt; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getSong() { return song; } public void setSong(String song) { this.song = song; } public String getSinger() { return singer; } public void setSinger(String singer) { this.singer = singer; } public String getAlbum() { return album; } public void setAlbum(String album) { this.album = album; } public String getDuration() { return duration; } public void setDuration(String duration) { this.duration = duration; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } }
适配器类 LocalMusicAdapter2
import android.annotation.SuppressLint; import android.content.Context; 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.mymusic.R; import java.util.List; public class LocalMusicAdapter2 extends RecyclerView.Adapter{ Context context; List mDatas; onItemClickListener onItemClickListener; //接口回调 public void setonItemClickListener(onItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } public interface OnItemClickListener{ public void onItemClick(View view,int position); } public LocalMusicAdapter2(Context context, List mDatas) { this.context = context; this.mDatas = mDatas; } @NonNull @Override public LocalMusicViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(context).inflate(R.layout.item_local_music,parent,false); LocalMusicViewHolder holder = new LocalMusicViewHolder(view); return holder; } @Override public void onBindViewHolder(@NonNull LocalMusicViewHolder holder, @SuppressLint("RecyclerView") final int position) { localMusicBean musicBean = mDatas.get(position); holder.idTv.setText(musicBean.getId()); holder.songTv.setText(musicBean.getSong()); holder.singerTv.setText(musicBean.getSinger()); holder.albumTv.setText(musicBean.getAlbum()); holder.timeTv.setText(musicBean.getDuration()); holder.itemView.setonClickListener(new View.onClickListener() { @Override public void onClick(View v) { onItemClickListener.onItemClick(v,position); } }); } @Override public int getItemCount() { return mDatas.size(); } class LocalMusicViewHolder extends RecyclerView.ViewHolder{ TextView idTv,songTv,singerTv,albumTv,timeTv; public LocalMusicViewHolder(View itemView) { super(itemView); idTv = itemView.findViewById(R.id.item_local_music_num); songTv = itemView.findViewById(R.id.item_local_music_song); singerTv = itemView.findViewById(R.id.item_local_music_singer); albumTv = itemView.findViewById(R.id.item_local_music_album); timeTv = itemView.findViewById(R.id.item_local_music_durtion); } } }
活动管理类 ActivityCollector(便于管理活动是否销毁)
import android.app.Activity; import java.util.linkedList; public class ActivityCollector { public static linkedList activities = new linkedList(); public static void addActivity(Activity activity) { activities.add(activity); } public static void removeActivity(Activity activity) { activities.remove(activity); } public static void finishAll() { for (Activity activity:activities ) { if(!activity.isFinishing()) { activity.finish(); } } } }
音乐播放列表类 frag1(继承自Fragment)
import android.content.ContentResolver; import android.content.Intent; import android.database.Cursor; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.example.mymusic.R; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class frag1 extends Fragment implements View.OnClickListener{ private static final String TAG = "lzs"; private View view; public String name; public static int icons=R.drawable.iuyuantu; private ImageView btn_music; RecyclerView musicRv; // 数据源 private ListmDatas; private LocalMusicAdapter2 adapter; private MediaPlayer mediaPlayer; private Intent it; public String addr=null; public int position1=-1; private int idd; private TextView t1,t2; @Override public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ // 可能初始化一个新实例的默认值的成员 view=inflater.inflate(R.layout.music_list,container,false); musicRv = view.findViewById(R.id.local_music_rv1); mediaPlayer = new MediaPlayer(); mDatas = new ArrayList<>(); t1=view.findViewById(R.id.local_music_bottom_tv_song); t2=view.findViewById(R.id.local_music_bottom_tv_singer); btn_music=view.findViewById(R.id.local_music_icon); btn_music.setonClickListener(this); //创建适配器对象 adapter = new LocalMusicAdapter2(frag1.this.getContext(), mDatas); musicRv.setAdapter(adapter); //设置布局管理器 LinearLayoutManager layoutManager = new LinearLayoutManager(frag1.this.getContext(), LinearLayoutManager.VERTICAL, false); musicRv.setLayoutManager(layoutManager); //加载本地数据源 loadLocalMusicData(); //设置每一项的点击事件 setEventListener(); Log.i(TAG, "onCreateView: "+position1); return view; } private void loadLocalMusicData() { //1.获取ContentResolver对象 ContentResolver resolver = frag1.this.getContext().getContentResolver(); //2.获取本地音乐存储的Uri地址 Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; Log.i(TAG, "loadLocalMusicdata: "+uri); //3 开始查询地址 Cursor cursor = resolver.query(uri, null, null, null, null); Log.i(TAG, "loadLocalMusicdata: "+cursor); //4.遍历Cursor int id = 0; while (cursor.moveTonext()) { String song = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE)); String singer = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST)); String album = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM)); id++; String sid = String.valueOf(id); String path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA)); long duration = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION)); SimpleDateFormat sdf = new SimpleDateFormat("mm:ss"); String time = sdf.format(new Date(duration)); //获取专辑图片主要是通过album_id进行查询 String album_id = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)); //将一行当中的数据封装到对象当中 localMusicBean bean = new localMusicBean(sid, song, singer, album, time, path,""); mDatas.add(bean); } idd=id; Log.i(TAG, "loadLocalMusicdata: "+mDatas); //数据源变化,提示适配器更新 adapter.notifyDataSetChanged(); } private void setEventListener() { adapter.setonItemClickListener(new LocalMusicAdapter2.onItemClickListener() { @Override public void onItemClick(View view, int position) { position1 = position; Log.i(TAG, "OnItemClick: "+position1); addr=mDatas.get(position).getPath(); t1.setText(mDatas.get(position).getSong()); t2.setText(mDatas.get(position).getSinger()); it = new Intent(frag1.this.getContext(), com.example.mymusic.mymusic.Music_Activity.class); it.putExtra("position",String.valueOf(1)); it.putExtra("id1",position); //点击歌曲id it.putExtra("id2",idd); //歌曲总数 it.putExtra("data1", (Serializable) mDatas); //歌曲集合 it.putExtra("musicI",0); //传0表示用户点击的是歌曲列表里的歌曲,而不是返回播放界面 startActivity(it); } }); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.local_music_icon: it = new Intent(frag1.this.getContext(), com.example.mymusic.mymusic.Music_Activity.class); it.putExtra("data1", (Serializable) mDatas); it.putExtra("musicI",1); //传1表示用户点击的是那个音箱图标,只是想返回播放界面,而不是要换歌 it.putExtra("id2",idd); //歌曲总数 it.putExtra("id1",position1); //传歌曲id startActivity(it); break; } } @Override public void onDestroy() { super.onDestroy(); } }
专辑 类frag2(继承自Fragment)
import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.fragment.app.Fragment; import com.example.mymusic.R; public class frag2 extends Fragment { private View zj; public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { zj = inflater.inflate(R.layout.frag2_layout, null); return zj; } }
到此音乐播放列表的布局文件和类都写完了,接下来是
音乐播放界面
音乐播放界面 activity_music
音乐播放界面类 Music_Activity
import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.content.Intent; import android.media.MediaPlayer; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.animation.LinearInterpolator; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import com.example.mymusic.R; import java.util.List; import java.util.Timer; import java.util.TimerTask; public class Music_Activity extends AppCompatActivity implements View.OnClickListener{ private static final String TAG = "lzs"; private static SeekBar sb; private static TextView tv_progress,tv_total,song_name; private ObjectAnimator animator; private String name; private Intent intent1; // 数据源 private ListmDatas1; private ImageView play1,last1,next1; private int num; private int id; private ImageView btn_xunhuang; private boolean aa=true; private boolean bb=true; private ImageView btn_shouc; private int musicI; private ImageView iv_music; private MediaPlayer player; private Timer timer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_music); ActivityCollector.addActivity(this); //intent 通信 intent1=getIntent(); mDatas1=(List ) getIntent().getSerializableExtra("data1");//接收歌曲集合 num = intent1.getIntExtra("id2",0);//歌曲总数 id = intent1.getIntExtra("id1",0);//点击歌曲id player=new MediaPlayer();//创建音乐播放器对象 init(); //初始化布局控件 Log.i(TAG, "onCreate: "); } private void init(){ tv_progress=(TextView)findViewById(R.id.tv_progress); tv_total=(TextView)findViewById(R.id.tv_total); sb=(SeekBar)findViewById(R.id.sb); song_name=findViewById(R.id.song_name); play1=findViewById(R.id.btn_play); last1=findViewById(R.id.btn_last); next1=findViewById(R.id.btn_next); btn_xunhuang=findViewById(R.id.btn_xuhuang); btn_shouc=findViewById(R.id.btn_shouc); play1.setonClickListener(this); last1.setonClickListener(this); next1.setonClickListener(this); btn_xunhuang.setonClickListener(this); btn_shouc.setonClickListener(this); if(id!=-1) { name=mDatas1.get(id).getSong(); song_name.setText(name); } //为滑动条添加事件监听 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的进度 seekTo(progress);//改变播放进度 } }); iv_music=(ImageView)findViewById(R.id.iv_music); iv_music.setImageResource(frag1.icons); //设置专辑图片 animator=ObjectAnimator.ofFloat(iv_music,"rotation",0f,360.0f); animator.setDuration(10000);//动画旋转一周的时间为10秒 animator.setInterpolator(new LinearInterpolator());//匀速 animator.setRepeatCount(-1);//-1表示设置动画无限循环 if(id!=-1) animator.start(); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.btn_play://播放按钮点击事件 if(id==-1) { id=0; play1.setImageResource(R.drawable.play1); song_name.setText(mDatas1.get(id).getSong()); play(mDatas1.get(id).getPath()); animator.start(); }else { if(isPlay()) { play1.setImageResource(R.drawable.pause1); pausePlay(); animator.pause(); }else { play1.setImageResource(R.drawable.play1); continuePlay(); if(animator.isPaused()) animator.resume(); else { animator.start(); } } } break; case R.id.btn_last://上一首 if(id<=0) { Toast.makeText(this,"已经是第一首了,没有上一曲!",Toast.LENGTH_SHORT).show(); }else { if(isPlay()) { animator.pause(); animator.clone(); id--; song_name.setText(mDatas1.get(id).getSong()); play(mDatas1.get(id).getPath()); animator.start(); }else { animator.pause(); animator.clone(); play1.setImageResource(R.drawable.play1); id--; song_name.setText(mDatas1.get(id).getSong()); play(mDatas1.get(id).getPath()); animator.start(); } } break; case R.id.btn_next://下一首 if(id>=num) { Toast.makeText(this,"已经是最后一首了,没有下一曲!",Toast.LENGTH_SHORT).show(); }else { if(isPlay()) { animator.pause(); animator.clone(); id++; song_name.setText(mDatas1.get(id).getSong()); play(mDatas1.get(id).getPath()); animator.start(); } else { animator.pause(); animator.clone(); id++; song_name.setText(mDatas1.get(id).getSong()); play1.setImageResource(R.drawable.play1); play(mDatas1.get(id).getPath()); animator.start(); } } break; case R.id.btn_xuhuang: btn_xunhuang.setSelected(aa); if(aa==true) { Toast.makeText(Music_Activity.this,"顺序播放",Toast.LENGTH_SHORT).show(); aa=false; } else { Toast.makeText(Music_Activity.this,"单曲循环",Toast.LENGTH_SHORT).show(); aa=true; } break; case R.id.btn_shouc: btn_shouc.setSelected(bb); if(bb==true) { Toast.makeText(Music_Activity.this,"收藏成功",Toast.LENGTH_SHORT).show(); bb=false; } else { Toast.makeText(Music_Activity.this,"取消收藏",Toast.LENGTH_SHORT).show(); bb=true; } break; } } @Override protected void onStop() { super.onStop(); Log.i(TAG, "onStop: "); } @Override protected void onPause() { super.onPause(); Log.i(TAG, "onPause: "); } @Override protected void onResume() { super.onResume(); Log.i(TAG, "onResume: "); } @Override protected void onStart() { Log.i(TAG, "onStart: "); super.onStart(); } @Override public void onWindowFocusChanged(boolean hasFocus) { Log.i(TAG, "onWindowFocusChanged: "); if (hasFocus) { Log.i("lsh123", "onWindowFocusChanged: "+isPlay()); if(id!=-1) { song_name.setText(mDatas1.get(id).getSong()); musicI=intent1.getIntExtra("musicI",-1); Log.i(TAG, "onWindowFocusChanged: "+musicI); if(musicI==0) { play1.setImageResource(R.drawable.play1); play(mDatas1.get(id).getPath()); animator.start(); } } } } //在Musiv_Activity从后台重新切换到前台时,更新当前intent对象,已达到更新数据的目的 @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); intent1 = getIntent(); id = intent1.getIntExtra("id1",-1); Log.i(TAG, "onNewIntent: "+id); } @Override protected void onDestroy(){ super.onDestroy(); Log.i("lsh123", "onDestroy1: "); } //让activity进入后台,不销毁 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { Log.i(TAG, "onKeyDown: "); if(keyCode == KeyEvent.KEYCODE_BACK){ Intent it = new Intent(Music_Activity.this,MainActivity1.class); startActivity(it); return true; } return super.onKeyDown(keyCode, event); } 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); Log.i("lsh123", "run: "); } }; //开始计时任务后的5毫秒,第一次执行task任务,以后每500毫秒执行一次 timer.schedule(task,5,500); } } //播放歌曲 public void play(String str){//String path Log.i("lsh123", "play: "+str); Uri uri=Uri.parse(str+""); try{ player.reset();//重置音乐播放器 //加载多媒体文件 Log.i("lsh123", "play: 123"+str); player=MediaPlayer.create(getApplicationContext(),uri); Log.i("lsh123", "play: "+str); player.start();//播放音乐 addTimer();//添加计时器 }catch(Exception e){ e.printStackTrace(); } } public boolean isPlay(){ if(player.isPlaying()) return true; else return false; } public void pausePlay(){ player.pause();//暂停播放音乐 } public void continuePlay(){ player.start();//继续播放音乐 } public void seekTo(int progress){ player.seekTo(progress);//设置音乐的播放位置 } public static Handler handler=new Handler(){//创建消息处理器对象 //在主线程中处理从子线程发送过来的消息 @SuppressLint("HandlerLeak") @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); } }; }
还有一些配置信息
AndroidManifest.xml
模块内的build.gradle
plugins { id 'com.android.application' } android { compileSdk 30 defaultConfig { applicationId "com.example.mymusic" minSdk 21 targetSdk 30 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } //添加包路径 //开启dataBinding功能支持 dataBinding { enabled = true } // 自定义打包名称 android.applicationVariants.all { variant -> variant.outputs.all { outputFileName = "ac.apk" } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } buildFeatures { viewBinding true } } dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.3.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.preference:preference:1.1.1' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' //添加 RecyclerView 依赖包 implementation "androidx.recyclerview:recyclerview:1.2.1" //添加 ViewPager2 依赖包 implementation 'androidx.viewpager2:viewpager2:1.0.0' implementation'com.synnapps:carouselview:0.1.5' implementation 'org.greenrobot:eventbus:3.1.1' }
到此,所有布局文件,类和配置信息都写完了,当然里面的逻辑思路就不具体介绍了,不然就我这
打字速度得写到什么时候,所以我就大概讲讲用到了哪些方法:
1.首先是登录界面,我是用了Shared Preferences 存储(对于注册少量用户来说,建议使用
sqlite)
2.还有就是,音乐列表和专辑两个页面的切换,其实就是activity里两个fragment的切换,注意
通过add方法添加fragment,再通过hide,show决定显示哪一个fragment,此方式是将fragment隐藏
而非重建,replace:每次都是重新创建fragment,所以为了保存数据,我采用的是add。
3.音乐列表上方的轮播图是我用第三方插件写的,当然你也可以自己写,用Handler消息机制。
4.在音乐列表和音乐播放界面跳转过程中,我让音乐播放界面直接切入后台,不销毁,从而达到数
据的保存,当然你也可以使用Service,进程间的通信解决数据交互问题。
5.音乐播放界面的音乐进度条是通过Handler消息机制实现的,每个几毫秒就向主线程发送消息,
然后修改当前进度条的值,从而达到动态的效果
6.还有很多小知识,我就不一一讲了,相信你们也能看的懂,没有用到特别难的知识,功能也挺简
单的。
GitHub链接:https://github.com/1577643176/Simplemusicplayer.git
联系QQ:1577643176
以上是我个人总结,难免会有不妥之处,欢迎指正,谢谢。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)