安卓基础学习笔记(十)

/ 0评 / 0

音乐播放器V2.0
----------------------------------
一、显示界面
1. 在MainActivity中显示ListView
二、编写播放功能代码
1. [PlayMusicService] 声明全局变量MediaPlayer player
2. [PlayMusicService] 重写onCreate(),创建MediaPlayer对象
3. [PlayMusicService] 声明全局变量List musics
4. [PlayMusicService] 声明全局变量MusicPlayerApplication app
5. [PlayMusicService] 在onCreate()中,通过getApplication()方法为app赋值
6. [PlayMusicService] 调用app对象的getMusics()方法,为musics对象赋值
7. [PlayMusicService] 声明全局变量int currentMusicIndex、int pausePosition
8. [PlayMusicService] 声明以下播放控制的相关方法:
private void play()
private void pause()
private void previous()
private void next()
三、准备Service,使之可以被绑定
1. [IMusicPlayer] 创建接口IMusicPlayer.java
2. [IMusicPlayer] 在接口中定义如下抽象方法:
void callPlay();
void callPause();
void callPrevious();
void callNext();
void callIsPlaying();
3. [PlayMusicService] 创建内部类InnerBinder,继承自Binder,并实现IMusicPlayer接口
4. [PlayMusicService] 在InnerBinder重写的抽象方法中,分别调用以上已经实现的具体播放控制的方法,例如在callPlay()方法中,直接调用void play()方法
5. [PlayMusicService] 在onBind()方法中,创建InnerBinder的对象,并作为该方法的返回值
四、完善Service中的其它代码
1. [PlayMusicService] 重写onDestroy()方法,在该方法中,调用player.release()方法,以释放MediaPlayer对象占用的资源
五、在Activity中绑定Service
1. [MainActivity] 创建内部类InnerServiceConnection,实现ServiceConnection接口,并重写抽象方法,代码暂不实现
2. [MainActivity] 声明全局变量InnerServiceConnection conn
3. [MainActivity] 声明全局变量IMusicPlayer player
4. [MainActivity] 在onCreate()方法中,创建Intent对象,在Intent的构造方法中,指定需要激活PlayMusicService
5. [MainActivity] 在onCreate()方法中,创建InnerServiceConnection的对象,并赋值给conn对象
6. [MainActivity] 在onCreate()方法中,调用bindService()方法,绑定Service
7. [MainActivity] 在InnerServiceConnection的onServiceConnected()方法中,通过参数IBinder serivce为player对象赋值,赋值过程中需要强制转换类型
六、实现基本播放功能
1. [MainActivity] 声明ImageButton ibPlayOrPause等3个按钮对应的对象
2. [MainActivity] 初始化以上对象
3. [MainActivity] 让MainActivity实现OnClickListener,并添加抽象方法
4. [MainActivity] 为以上按钮配置点击监听器
5. [MainActivity] 在onClick()方法中,对按钮进行判断,并根据点击的按钮不同,分别调用player对象的对应方法,例如,点击的如果是R.id.ib_next,则调用player.callNext()即可
七、完善Activity的其它代码
1. [MainActivity] 重写onDestroy()方法,调用unbindService()解除与Service的绑定
八、整理项目中的包与类
1. 将Activity类放到项目的activity包中
2. 将Service类放到项目的service包中
3. 将Application类放到项目的app包中
4. 将Adapter类放到项目的adapter包中
5. 将实体类,例如Music类放到项目的entity包中
6. 将Dao类放到项目的dal包中
7. 将工具类放到项目的util包中
九、实现点击界面上的列表后播放歌曲
1. [IMusicPlayer] 添加新的抽象方法:
void callPlay(int position);
2. [PlayMusicService] 添加新的方法:
private void play(int position) {}
3. [PlayMusicService] 在InnerBinder中,重写新的抽象方法callPlay(int),在该方法中调用play(int)方法即可
4. [MainActivity] 使得MainActivity实现OnItemClickListener,并添加抽象方法,为ListView配置监听器
5. [MainActivity] 在onItemClick()方法中,通过player对象调用callPlay(int)即可
十、显示歌曲播放信息
1. [IMusicPlayer] 添加以下抽象方法:
int callGetCurrentMusicIndex();
int callGetCurrentPosition();
int callGetDuration();
2. [PlayMusicService] 在InnerBinder中,重写新的抽象方法,并实现具体代码
3. [MainActivity] 声明显示歌曲信息的相关控件:3个TextView与1个SeekBar,并在onCreate()方法中完成初始化
4. [MainActivity] 创建内部类UpdateProgressThread,继承自Thread类,重写public void run()方法,在重写的方法中,使用一个长期的循环,在循环内部通过player对象获取当前播放的歌曲的索引、当前播放到的位置、当前播放的歌曲的时长,计算出需要显示的数据,并通过runOnUiThread()方法进行显示,且每次显示后休眠500ms。
5. [MainActivity] 声明全局变量UpdateProgressThread updateProgressThread
6. [MainActivity] 创建private void startUpdateProgressThread()方法,在方法中,判断全局变量updateProgressThread是否为null,如果为null,则创建新的线程对象,并启动启动
7. [MainActivity] 创建private void stopUpdateProgressThread()方法,在方法中,判断全局变量updateProgressThread是否为null,如果不为null,则停止线程,并将对象设置为null
8. [MainActivity] 在播放/播放上一首/播放下一首/播放指定的歌曲之后,均调用startUpdateProgressThread()方法开启线程,在暂停之后,调用stopUpdateProgressThread()方法停止线程
9. [MainActivity] 在onDestroy()方法中,调用stopUpdateProgressThread()方法停止线程,注意:本次调用必须在解除与Service的绑定(即Service释放播放器相关资源)之前
十一、拖拽进度条
1. [IMusicPlayer] 添加以下抽象方法:
void callSeekTo(int progress); // 从??进度开始播放
2. [PlayMusicService] 添加私有方法:
private void seekTo(int progress) {}
3. [PlayMusicService] 在InnerBinder中实现新的抽象方法,实现过程调用步骤2的方法即可
4. [MainActivity] 为SeekBar控件配置onSeekBarChangeListener,重写抽象方法
5. [MainActivity] 在onStopTrackingTouch()方法中,获取当前SeekBar的进度,并通过IMusicPlayer对象,调用callSeekTo(int)方法
十二、完善进度条的拖拽
1. [MainActivity] 声明全局变量private boolean isUserTrackingTouch,表示用户是否正在拖拽进度条,默认值为false
2. [MainActivity] 在onStartTrackingTouch中,将isUserTrackingTouch的值更新为true
3. [MainActivity] 在onStopTrackingTouch中,将isUserTrackingTouch的值更新为false
4. [MainActivity] 在UpdateProgressThread类中,更新UI控件时,判断isUserTrackingTouch的值,仅当该值为false时可更新SeekBar,更新其它控件不受影响
十三、完善其它
1. 自动播放下一首
1.1 [PlayMusicService] 在onCreate()方法中,为MediaPlayer对象配置OnCompletionListener,在监听方法中,调用next()播放下一首即可
2. 优化线程的启动与停止
2.1 [MainActivity] 重写onStop()方法,在该方法中,添加停止更新进度的线程的代码,并修改onDestroy()方法,去除停止更新进度的线程的代码
2.2 [MainActivity] 重写onRestart()方法,在该方法中,先判断播放状态,如果正在播放,则添加启动更新进度的线程的代码

Intent:意图
------------------------------
Intent的主要作用:
1. 激活系统组件,例如激活Activity,激活Service⋯⋯
2. 在组件之间传递数据,例如putExtra()与get???Extr()
Intent的核心属性:
1. ComponentName:组件名称,用于显式的指定被激活的组件
直接或间接使用ComponentName属性的方法有:
>> Intent的构造方法
>> Intent对象的setClass()方法
>> Intent对象的setClassName()方法
>> ComponentName的构造方法
推荐使用Intent的构造方法快速指定被激活的组件,不管是哪种方式,都是直接或间接的指定了Intent中的mComponent属性,用于确定被激活的组件
2. Action:动作,用于隐式的指定被激活的组件,且不要求该组件是当前应用程序的组件
每个Intent对象中最多只有1个Action属性
设置Action的方式:
>> Intent的构造方法
>> Intent对象的setAction(String)方法
3. Data:数据,用于指定激活组件时的数据,通常该属性与Action属性同时使用
每个Intent对象中最多只有1个Data属性
设置Data的方法:
>> Intent对象的setData(Uri)方法
Uri对象的创建方式:Uri.parse(String)
4. Category:分类,通常用于与IntentFilter进行匹配
每个Intent对象中可以存在若干个Category属性
添加Category的方式:
>> Intent对象的addCategory(String)方法
5. Extras:附加数据,用于在组件之间传递用户自定义的数据
Extras属性是Bundle类型的。Bundle的内部通过Map存储数据,但是,该Map对象并不对象提供访问权限,所以,只能通过Bundle的公有方法间接访问该Map对象存储数据,这些公共方法约定的Map的Value数据类型是相对有限的。
Intent中的putExtra(String, ???)等方法,是间接的操作Bundle的。

Parcelable接口
------------------------------
Parcelable接口是Android系统中用于确定数据在传递过程中如何序列化的接口。
实现Parcelable接口的步骤:
1. 自定义实体类,实现Parcelable接口,并添加抽象方法
2. describeContents()方法直接返回0即可
3. writeToParcel()方法中,通过参数Parcel dest的write???()系列方法将属性写入到Parcel容器中
4. 声明public static final Parcelable.Creator CREATOR属性,并使用匿名内部类语法创建对象
5. 在实现Creator的2个抽象方法中,newArray()方法直接根据参数int size创建当前实体类的数据即可
6. 在实现Creator的2个抽象方法中,createFromParcel()方法,根据参数Parcel source的read???()方法从Parcel容器中获取传递过来的数据,并根据这些数据创建当前实体类的对象即可
注意:在调用Parcel对象的写入和读取方法时,必须保证顺序的一致,即第1次调用write???()写入的数据,必须是第1次调用read???()读出的数据。

IntentFilter:意图过滤器
------------------------------
IntentFilter的作用是对Intent进行过滤,使得其中一部分Intent可以放行,而另一部分将被拦截,亦可以理解为是判断Intent是否匹配某些条件。
IntentFilter对Intent的过滤,可以通过以下属性进行过滤:
1. Action
2. Category
通俗的原则:IntentFilter中的Action、Category,相关Intent对象中的Action、Category只能多,不能少,或者理解为在Intent对象中的Action、Category在同一个IntentFilter中都可以找到。
注意:如果Intent对象中已经显式的指定了ComponentName属性,则不会进行任何匹配,直接激活显式指定的组件。
注意:关于Intent与IntentFilter的匹配,还需要参考Type和Data属性。

【仅了解】跨进程绑定Service
------------------------------
跨进程绑定Service表现为A应用程序的Activity绑定B应用程序的Service。
在跨进程绑定Service的应用场景中,即使用Service提供服务的一方称之为“服务端”,绑定其它应用程序的Service直接使用服务的一方称之为“客户端”。

AIDL接口
------------------------------
AIDL:Android接口定义语言
AIDL接口的创建方式:
1. 使用java语法创建接口文件
2. 接口文件的声明语句中,去掉public关键字
3. 打开接口文件所在的文件夹,将接口文件的扩展名改为.aidl
4. 在项目中按F5刷新

评论已关闭。