一、案例作用
二、欢迎界面的规划与功用
2.1 **、**案例作用
规划一个倒计时自动跳转的页面
2.2**、** 布局界面 activity_welcome.xml 参阅代码:
<?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:orientation="vertical"
android:background="@drawable/welcome_picture"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:text="欢 迎"
android:textSize="90dp"
android:textStyle="bold"
android:textColor="#ad0000"
android:layout_marginTop="150dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="H"
android:layout_gravity="center"
android:layout_marginTop="50dp"
android:textSize="100sp"
android:textColor="#000000"
/>
</LinearLayout>
2.3、类文件 WelcomeActivity.java 参阅代码:
package com.example.musicplayer;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
public class WelcomeActivity extends AppCompatActivity {
private static final String TAG="MainActicity";
private TextView textView1;
private Timer timer; //创立定时器
private TimerTask timerTask; //创立定时器使命
private int count=5;
private Handler handler; //音讯处理器,专门发送和接收音讯
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
initView(); //控件初始化
initDate(); //数据初始化
initStatus(); //页面状况初始化
}
private void initView() {
textView1=findViewById(R.id.text1);
}
private void initDate() {
timer=new Timer();
timerTask=new TimerTask() {
@Override
//run()中的代码是定时器要完成的使命,都是耗时的操作,在 android中,耗时的操作都放在子线程中进行
public void run() {
// count++;
Log.d(TAG, "run: "+count);
//让子线程给主线程发送音讯信号,主线程接收到音讯信号后就能够更新主界面的数字显现信息
if(count!=0){
//给主线程发送音讯信息 1
Message msg=new Message();
msg.what=1; //1 表明音讯信号
handler.sendMessage(msg);
}else {
//给主线程发送音讯信息 0
Message msg=new Message();
msg.what=0; //0 表明音讯信号
handler.sendMessage(msg);
}
}
};
//敞开定时器 参数 1:定时器使命 参数 2:延迟 参数 3:变化的周期
timer.schedule(timerTask,0,1000);
//主线程承受到音讯信号对主界面数字显现进行更新
handler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
//主线程依据接收到的音讯进行判别
switch (msg.what){
case 1:
//让数字递减
count--;
textView1.setText(count+""); //让变化的数字显现在主界面上
break;
case 0:
//倒计时结束,跳转到主界面
Intent intent=new Intent(WelcomeActivity.this,MainActivity.class);
startActivity(intent);
finish();
timer.cancel(); //封闭定时器
timerTask.cancel(); //封闭定时器使命
break;
default:
break;
}
}
};
}
//第一次登录 APP 时显现欢迎界面的倒计时,第二次登录 APP 时直接进入到主界面
private void initStatus() {
//读取保存的登录状况值
Boolean status = getSharedPreferences("mystatus",MODE_PRIVATE).getBoolean("status",false);
//将第一次登录的状况 True 保存起来,下次登录后判别状况,假如为 True 直接跳转到主页面,否则从欢迎界面倒计时登录
SharedPreferences.Editor editor =getSharedPreferences("mystatus",MODE_PRIVATE).edit();
editor.putBoolean("firstlogin_status",true);
editor.commit();
if(status){
//假如 status 为 True
Intent intent2=new Intent(WelcomeActivity.this,MainActivity.class);
startActivity(intent2);
finish();
timer.cancel();
timerTask.cancel();
}
}
}
2.4、知识点解说
1.Timer及TemerTask的运用(计时器东西类)
• 在开发中咱们有时会有这样的需求,即在固定的每隔一段时刻履行某一个使命。 比如UI上的控件需要随着时刻改动,咱们能够运用Java为咱们提供的计时器的东西类,即Timer和TimerTask。
• Timer是一个一般的类,其中有几个重要的办法;而TimerTask则是一个笼统类 ,其中有一个笼统办法run(),相似线程中的run()办法,咱们运用Timer创立一个它的目标,然后运用这目标的schedule办法来完成这种距离的操作。
Timer便是一个线程,运用schedule办法完成对TimerTask的调度,多个TimerTask 能够共用一个Timer,也便是说Timer目标调用一次schedule办法便是创立了一个线程,并且调用一次schedule后TimerTask是无限制的循环下去的,运用Timer的 cancel()中止操作。
2.schedule办法
schedule办法有三个参数:
第一个参数便是TimerTask类型的目标,咱们完成TimerTask的run()办法便是要周 期履行的一个使命;
第二个参数有两种类型,第一种是long类型,表明多长时刻后开端履行,另一种是 Date类型,表明从那个时刻后开端履行;
第三个参数便是履行的周期,为long类型。
3.Handler的运用
• 耗时的操作放在一个子线程中,由于子线程涉及到UI更新,**更新UI只能在主线程 中更新,子线程中操作是风险的。**这个时候,Handler就能够处理这个杂乱的问题 , Handler 是首要承受子线程发送的数据, 并用此数据合作主线程更新UI。
• 由于Handler运行在主线程中(UI线程中), 它与子线程能够经过Message目标来 传递数据, 这个时候,Handler就承担着承受子线程传递过来的Message目标,(里边包含数据) , 把这些音讯放入主线程行列中,合作主线程进行更新UI。
•Handler :子线程向主线程发送音讯、主线程处理接收到的音讯;
•Message:音讯载体,假如传输数据简单能够直接运用arg1、arg2这两个整型数 据,假如需要传杂乱的音讯,运用obj传输目标数据;
三、主界面的规划与功用
3.1 **、**案例作用
3.2 **、**布局界面 activity_welcome.xml 参阅代码:
<?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:orientation="vertical"
android:background="@drawable/main_picture"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:text="音乐播映器"
android:textSize="60dp"
android:textStyle="bold"
android:textColor="#0000ff"
android:layout_marginTop="150dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="进入音乐列表"
android:background="@drawable/button_style"
android:layout_gravity="center"
android:layout_marginTop="150dp"
android:textSize="30sp"
android:textStyle="bold"
android:textColor="#000000"
/>
</LinearLayout>
3.3、类文件 MainActivity.java 参阅代码:
package com.example.musicplayer;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
//界说目标
Button button1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
btnclick();
}
private void initView() {
button1=findViewById(R.id.button1);
}
private void btnclick() {
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(MainActivity.this,MusicActivity.class);
startActivity(intent);
finish();
}
});
}
}
四、音乐列表界面的规划与功用
4.1 **、**案例作用
提醒:(1)增加依靠,由于 RecyclerView 是 android 5.0 新增的控件,所以需 要在 build.gradle 里边增加依靠:如下
implementation 'androidx.recyclerview:recyclerview:1.1.0'
(2)由于要读写 sd 卡上的歌曲,所以需要在配置文件中增加权限,如下
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
tools:ignore="ProtectedPermissions" />
4.2、布局界面 activity_music.xml 参阅代码:
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MusicActivity">
<TextView
android:text="音乐列表"
android:textSize="50sp"
android:layout_gravity="center"
android:textStyle="bold"
android:textColor="#000078"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
4.3、类文件 MusicAdapter.java 参阅代码:
package com.example.musicplayer;
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 java.util.List;
import androidx.annotation.NonNull;
import androidx.appcompat.view.menu.ActionMenuItemView;
import androidx.recyclerview.widget.RecyclerView;
public class MusicAdapter extends
RecyclerView.Adapter<MusicAdapter.ViewHolder> {
Context mcontext;
List<Music> myMusicList;
public MusicAdapter(List<Music> musicList) {
myMusicList=musicList;
}
//办法 1:用于创立 ViewHolder 实例
@NonNull
@Override
public MusicAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.music_item,parent,false);
final ViewHolder holder=new ViewHolder(view);
//单击任意歌曲跳转到播映界面
holder.musicview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position= holder.getAdapterPosition(); //返回数据在适配器中的位置
Intent intent=new Intent(view.getContext(),PlayerActivity.class);
intent.putExtra("my",position);
view.getContext().startActivity(intent);
}
});
return holder;
}
//办法 2:用于对 Recyclerview 中子项的数据进行赋值的
@Override
public void onBindViewHolder(@NonNull MusicAdapter.ViewHolder holder, int position) {
Music musicinfo=myMusicList.get(position);
holder.music_title.setText(musicinfo.getMusicTitle());
holder.singer_name.setText(musicinfo.getSingerName());
}
//办法 3:数据源长度
@Override
public int getItemCount() {
return myMusicList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
View musicview;
TextView music_title;
TextView singer_name;
public ViewHolder(@NonNull View view) {
super(view);
musicview=view;
music_title=view.findViewById(R.id.music_title);
singer_name=view.findViewById(R.id.singer_name);
}
}
}
4.4、布局界面 music_item.xml 参阅代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
<ImageView
android:src="@drawable/music_icon"
android:layout_width="70dp"
android:layout_height="70dp"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/music_title"
android:textStyle="bold"
android:text="音乐的姓名"
android:textSize="30sp"
android:textColor="#000000"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/singer_name"
android:textStyle="bold"
android:text="歌手的姓名"
android:textSize="20sp"
android:textColor="#0000ff"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
4.5、类文件 Music.java 参阅代码:
package com.example.musicplayer;
public class Music {
private String musicTitle;
private String singerName;
public String getMusicTitle() {
return musicTitle;
}
public String getSingerName() {
return singerName;
}
public Music(String musicTitle, String singerName) {
this.musicTitle = musicTitle;
this.singerName = singerName;
}
}
4.6、类文件 MusicActivity.java 参阅代码
package com.example.musicplayer;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
public class MusicActivity extends AppCompatActivity {
//界说目标
RecyclerView recyclerView;
private static final String TAG = "MusicActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_music);
initView();
initData();
}
private void initView() {
recyclerView = findViewById(R.id.recyclerview);
}
private void initData() {
List<Music> musicList = new ArrayList<>();
Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
Log.d(TAG, "initData:我查询获取到的歌曲共:" + cursor.getCount() + "首");
while (cursor.moveToNext()){
String mymusictitle=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String mysingername =cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
Music music=new Music(mymusictitle,mysingername);
musicList.add(music);
}
cursor.close();
MusicAdapter adapter=new MusicAdapter(musicList);
StaggeredGridLayoutManager layoutManager=new StaggeredGridLayoutManager(1,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
}
4.7**、**代码解说
在android中,每个应用程序是能够完成数据同享的,便是咱们能够为每个应用程序创立一个ContentProvider,也便是说你能够经过ContentProvider把应用程序中的数据同享给其他程序拜访调用。其他应用程序能够经过ContentProvider对你应用程序中的数据进行拜访,修正,删去等操作。
getContentResolver是办理一切程序的contentProvider的实例(ContentResolver负责获取ContentProvider提供的数据)即:APP—>ContentReSolver—>ContentProvider。
getContentResolver.query参数说明:
第1个参数: table,是依据Uri确认的数据库表;
第2个参数: projection,是要查询的列;
第3个参数: selection, 查询条件;
第4个参数: selectionArgs ,填充where查找条件中的占位符”?“
第5个参数: order,是咱们想要的排序办法。
对应于SQL的结构是:select projection from table where ( selection ) order by order;
五、音乐播映界面的规划与功用
5.1 **、**案例作用
5.2、布局界面 activity_player.xml 参阅代码:
<?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"
android:orientation="vertical"
tools:context=".PlayerActivity">
<TextView
android:id="@+id/title"
android:text="获取到的音乐标题"
android:textColor="#000000"
android:textSize="35sp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/name"
android:text="获取到的歌手姓名"
android:textColor="#000000"
android:textSize="35sp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ImageView
android:src="@drawable/music_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:orientation="horizontal"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:weightSum="1"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/current_time"
android:text="0:00"
android:textSize="25sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<SeekBar
android:id="@+id/seek_bar"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/total_time"
android:text="8:23"
android:textSize="25sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
5.3、类文件 PlayerActivity.java 参阅代码:
package com.example.musicplayer;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
public class PlayerActivity extends AppCompatActivity {
//界说目标
private static final String TAG = "PlayerActivity";
private TextView title;
private TextView name;
private Cursor cursor;
private MediaPlayer mediaPlayer;
private SeekBar seekBar;
private TextView current_time;
private TextView total_time;
private Handler mhandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player);
initView(); //绑定控件
initData(); //获取并显现歌曲标题和歌手姓名
initPlay(); //播映歌曲
initSeek(); //初始化进展条
moveSeek(); //拖动滑动条
initUpdate(); //实时更新滑动条的当时时刻
}
private void initView() {
title=findViewById(R.id.title);
name=findViewById(R.id.name);
seekBar=findViewById(R.id.seek_bar);
current_time=findViewById(R.id.current_time);
total_time=findViewById(R.id.total_time);
}
private void initData() {
int position=getIntent().getIntExtra("my",0);
Log.d(TAG, "initData: "+position);
cursor=getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null,null,null,MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
cursor.moveToPosition(position);
String mytitle=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String myname=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
title.setText(mytitle);
name.setText(myname);
}
private void initPlay() {
mediaPlayer=new MediaPlayer();
String path=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
mediaPlayer.reset(); //清空里边的其他歌曲
try {
mediaPlayer.setDataSource(path);
mediaPlayer.prepare(); //准备就绪
mediaPlayer.start(); //开端唱歌
} catch (IOException e) {
e.printStackTrace();
}
}
private void initSeek() {
seekBar.setMax(mediaPlayer.getDuration()); //获取音频文件总时长
seekBar.setProgress(mediaPlayer.getCurrentPosition()); //获取当时播映的进展值
total_time.setText(toTime(mediaPlayer.getDuration()));
current_time.setText(toTime(mediaPlayer.getCurrentPosition()));
}
private String toTime(int getDutation) {
int time=getDutation/1000; //毫秒转化为秒
int minute=time/60; //取整:求出分钟
int second=time%60; //取余:求出秒 90 秒/60=1(分钟)....30(秒)
String mm=String.format("%01d:%02d",minute,second); //指定显现的格式
return mm;
}
private void moveSeek() {
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int position, boolean b) {
if(b){
mediaPlayer.seekTo(position); //音频从你拖到的位置处开端播映
initSeek();
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
private void initUpdate() {
Timer timer=new Timer();
TimerTask timerTask=new TimerTask() {
@Override
public void run() {
Message msg=new Message();
msg.what=11;
mhandler.sendMessage(msg);
}
};
timer.schedule(timerTask,0,1000);
mhandler=new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 11:
initSeek(); //重新履行进展条的初始化代码
break;
default:
break;
}
}
};
}
//按返回键中止播映
@Override
protected void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
}
}
5.4**、代码解说;**
MediaPlayer详解
Android的MediaPlayer包含了Audio和Video的播映功用,在Android的界 面上,Music和Video两个应用程序都是调用MediaPlayer来完成的。 MediaPlayer的作业流程:
1、首先创立MediaPlayer目标;
2、然后调用setDataSource()办法来设置音频文件的路径;
3、再调用prepare()办法使MediaPlayer进入到准备状况;
4、调用start办法就能够播映音频。
SeekBar.OnSeekBarChangeListener解析
当进展改动后用于告诉客户端的回调函数。这包含用户经过手势、方向键戒 轨迹球触发的改动, 以及编程触发的改动。
public abstract void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
参数
seekBar 当时被修正进展的SeekBar;
progress 当时的进展值,此值的取值范围为0到max之间;
fromUser 假如是用户触发的改动则返回True。
六、资源文件
免费资源
本文转自 blog.csdn.net/indeedes/ar…,如有侵权,请联系删去。