




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
国家开放大学Android智能手机编程形考任务
2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每
个3-5分钟,帮助开发者创建更快更优秀的AndroidApp。课程专题不仅仅介绍了
Android系统中有关性能问题的底层工作原理,同时也介绍了如何通过工具来找出性能问
题以及提升性能的建议。主要从三个方面展开,Android的渲染机制,内存与GC,电量
优化。下面是对这些问题和建议的总结梳理。超越高度整理
0)RenderPerformance
大多数用户感知到的卡顿等性能问题的最主要根源都是因为渲染性能。从设计师的角度,
他们希望App能够有更多的动画,图片等时尚元素来实现流畅的用户体验。但是Android
系统很有可能无法及时完成那些复杂的界面渲染操作。Android系统每隔16ms发出VSYNC
信号,触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的
60fps,为了能够实现60fps,这意味着程序的大多数操作都必须在16ms内完成。
16ms16ms16ms
表1超越高度整理
如果你的某个操作花费时间是24ms,系统在得到VSYNC信号的时候就无法进行正常
渲染,这样就发生了丢帧现象。那么用户在32ms内看到的会是同一帧画面。
16ms34ms
UPDATE24msUPDATE
Whoops!
droppedframe
用户容易在UI执行动画或者滑动Listview的时候感知到卡顿不流畅,是因为这里的操
作相对复杂,容易发生丢帧的现象,从而感觉卡顿。有很多原因可以导致丢帧,也许是因
为你的layout太过复杂,无法在16ms内完成渲染,有可能是因为你的UI上有层叠太多的
绘制单元,还有可能是因为动画执行的次数过多。这些都会导致CPU或者GPU负载过重。
我们可以通过一些工具来定位问题,比如可以使用Hierarchyviewer来查找Activity中
的布局是否过于复杂,也可以使用手机设置里面的开发者选项,打开ShowGPUOverdraw
等选项进行观察。你还可以使用TraceView来观察CPU的执行情况,更加快捷的找到性能
瓶颈。
l)UnderstandingOverdraw超越高度整理
Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多
层次的UI结构里面,如果不可见的UI也在做绘制的操作,这就会导致某些像素区域被绘制
了多次。这就浪费大量的CPU以及GPU资源。
13minutestoSheraton
当设计上追求更华丽的视觉效果的时候,我们就容易陷入采用越来越多的层叠组件来实
现这种视觉效果的怪圈。这很容易导致大量的性能问题,为了获得最佳的性能,我们必须尽
量减少Overdraw的情况发生。
幸运的是,我们可以通过手机设置里面的开发者选项,打开ShowGPUOverdraw的选
项,可以观察UI上的Overdraw情况。
a1
蓝色,淡绿,淡红,深红代表了4种不同程度的Overdraw情况,我们的目标就是尽量
减少红色Overdraw,看到更多的蓝色区域。
Overdraw有时候是因为你的UI布局存在大量重叠的部分,还有的时候是因为非必须的
重叠背景。例如某个Activity有一个背景,然后里面的Layout又有自己的背景,同时子View
又分别有自己的背景。仅仅是通过移除非必须的背景图片,这就能够减少大量的红色
Overdraw区域,增加蓝色区域的占比。这一措施能够显著提升程序性能。
2)UnderstandingVSYNC
为了理解App是如何进行渲染的,我们必须了解手机硬件是如何工作,那么就必须理
解什么是VSYNCo
在讲解VSYNC之前,我们需要了解两个相关的概念:
RefreshRate:代表了屏幕在一秒内刷新屏幕的次数,这取决于硬件的固定参数,例如
60Hzo
FrameRate:代表了GPU在一秒内绘制操作的帧数,例如30fps,60fpso
GPU会获取图形数据进行渲染,然后硬件负责把渲染后的内容呈现到屏幕上,他们两
者不停的进行协作。
不幸的是,刷新频率和帧率并不是总能够保持相同的节奏。如果发生帧率与刷新频率不
一致的情况,就会容易出现Tearing的现象(画面上下两部分显示内容发生断裂,来自不同的
两帧数据发生重叠)。
100fps.
■■■GPU■■■
75Hz/
目
理解图像渲染里面的双重与三重缓存机制,这个概念比较复杂,请移步查看这里:
/devices/graphics/index.html,还有这里
/view/37503/304664o
通常来说,帧率超过刷新频率只是一种理想的状况,在超过60fps的情况下,GPU所产
生的帧数据会因为等待VSYNC的刷新信息而被Hold住,这样能够保持每次刷新都有实际
的新的数据可以显示。但是我们遇到更多的情况是帧率小于刷新频率。
在这种情况下,某些帧显示的画面内容就会与上一帧的画面相同。糟糕的事情是,帧率
从超过60fps突然掉到60fps以下,这样就会发生LAG,JANK,HITCHING等卡顿掉帧的不
顺滑的情况。这也是用户感受不好的原因所在。
3)Tool:ProfileGPURendering
性能问题如此的麻烦,幸好我们可以有工具来进行调试。打开手机里面的开发者选项,
选择ProfileGPURendering,选中Onscreenasbars的选项。
DEVELOPER
OPTIONS
选择了这样以后,我们可以在手机画面上看到丰富的GPU绘制图形信息,分别关于
StatusBar,NavBar,激活的程序Activity区域的GPURending信息。
<>BQioi»
ActiveApp
Performance
随着界面的刷新,界面上会滚动显示垂直的柱状图来表示每帧画面所需要渲染的时间,
柱状图越高表示花费的渲染时间越长。
«,*':♦,Q')H.
中间有一根绿色的横线,代表16ms,我们需要确保每一帧花费的总时间都低于这条横
线,这样才能够避免出现卡顿的问题。
O0▼,。ioi*
Process
Today.Ocaobw23
20,glSwapfiuffers
14,
Totnortow
RainExecute
DisplayList
--R»n
.Sundcy
b
MondayUpdate
IMIILDisplayList
认O□
每一条柱状线都包含三部分,蓝色代表测量绘制DisplayList的时间,红色代表OpenGL
渲染DisplayList所需要的时间,黄色代表CPU等待GPU处理的时间。
4)Why60fps?
我们通常都会提到60fps与16ms,可是知道为何会是以程序是否达到60fps来作为App
性能的衡量标准吗?这是因为人眼与大脑之间的协作无法感知超过60fps的画面更新。
12fps大概类似手动快速翻动书籍的帧率,这明显是可以感知到不够顺滑的。24fps使
得人眼感知的是连续线性的运动,这其实是归功于运动模糊的效果。24fps是电影胶圈通常
使用的帧率,因为这个帧率已经足够支撑大部分电影画面需要表达的内容,同时能够最大的
减少费用支出。但是低于30fps是无法顺畅表现绚丽的画面内容的,此时就需要用到60fps
来达到想要的效果,当然超过60fps是没有必要的。
开发app的性能目标就是保持60fps,这意味着每一帧你只有16ms=1000/60的时间来
处理所有的任务。
5)Android,UIandtheGPU
了解Android是如何利用GPU进行画面渲染有助于我们更好的理解性能问题。那么一
个最实际的问题是:activity的画面是如何绘制到屏幕上的?那些复杂的XML布局文件又是
如何能够被识别并绘制出来的?
Rasterization
@一翻@
Resterization栅格化是绘制那些Button,Sh叩e,Path,String,Bitmap等组件最基础的
操作。它把那些组件拆分到不同的像素上进行显示。这是一个很费时的操作,GPU的引入就
是为了加快栅格化的操作。
CPU负责把UI组件计算成Polygons,Texture纹理,然后交给GPU进行栅格化渲染。
单元3国家开放大学Android智能手机编程形考任
务1
效果图
packagecom.app.MyComputer;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.Editlext;
importandroid.widget.TextView;
importandroid.app.Activity;
publicclassMainActivityextendsActivityimplementsOnClickListener{
〃声明控件
Buttonbtn0;//0键
Buttonbtn1;//1键
Buttonbtn2;//2键
Buttonbtn3;//3键
Buttonbtn4;//4键
Buttonbtn5;//5键
Buttonbtn6;//6键
Buttonbtn7;//7键
Buttonbtn8;//8键
Buttonbtn9;//9键
ButtonbtnC;〃清除键
ButtonbtnAdd;//+键
ButtonbtnSub;〃-键
ButtonbtnMul;//*键
ButtonbtnDiv;〃除键
ButtonbtnEqu;//等于键
ButtonbtnDot;//点键
EditTexttvResult;
〃声明两个参数。接收tvResult前后的值
doublenum1=0,num2=0;
doubleResult=0;〃计算结果
intop=0;〃判断操作数,
Stringopd="显示操作符
booleanisClickEqu=false;//判断是否按了“二"按钮
©Override
protectedvoidonCreate(BundlesavedlnstanceState){
super.onCreate(savedlnstanceState);
setContentView(R.layout.activity_main);
〃从布局文件中获取控件,
btnO=(Button)findViewByld(R.id.btnO);
btn1=(Button)findViewByld(R.id.btn1);
btn2=(Button)findViewByld(R.id.btn2);
btn3=(Button)findViewByld(R.id.btn3);
btn4=(Button)findViewByld(R.id.btn4);
btn5=(Button)findViewByld(R.id.btn5);
btn6=(Button)findViewByld(R.id.btn6);
btn7=(Button)findViewByld(R.id.btn7);
btn8=(Button)findViewByld(R.id.btn8);
btn9=(Button)findViewByld(R.id.btn9);
btnC=(Button)findViewByld(R.id.btnC);
btnEqu=(Button)findViewByld(R.id.btnEqu);
btnAdd=(Button)findViewByld(R.id.btnAdd);
btnSub=(Button)findViewByld(R.id.btnSub);
btnMul=(Button)findViewByld(R.id.btnMul);
btnDiv=(Button)findViewByld(R.id.btnDiv);
btnDot=(Button)findViewByld(R.id.btnDot);
tvResult=(EditText)findViewByld(R.id.tvResult);
〃添加监听
btnO.setOnClickListener(this);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
btn3.setOnClickListener(this);
btn4.setOnClickListener(this);
btn5.setOnClickListener(this);
btn6.setOnClickListener(this);
btn7.setOnClickListener(this);
btn8.setOnClickListener(this);
btn9.setOnClickListener(this);
btnDot.setOnClickListener(this);
btnC.setOnClickListener(this);
btnAdd.setOnClickListener(this);
btnSub.setOnClickListener(this);
btnMul.setOnClickListener(this);
btnDiv.setOnClickListener(this);
btnEqu.setOnClickListener(this);
)
@Override
publicvoidonClick(Viewv){
switch(v.getld()){//switch循环获取点击按钮后的值
caseR.id.btnO://获取,0-9、小数点,并在编辑框显示
StringmyString=tvResult.getText().toString();
myString+="0n;
tvResult.setText(myString);
break;
caseR.id.btnl:
StringmyString1=tvResult.getText().toString();
myString1+=H1";
tvResult.setText(myString1);
break;
caseR.id.btn2:
StringmyString2=tvResult.getText().toString();
myString2+="2”;
tvResult.setText(myString2);
break;
caseR.id.btn3:
StringmyString3=tvResult.getText().toString();
myString3+="3H;
tvResult.setText(myString3);
break;
caseR.id.btn4:
StringmyString4=tvResult.getText().toString();
myString4+="4";
tvResult.setText(myString4);
break;
caseR.id.btn5:
StringmyString5=tvResult.getText().toString();
myString5+="5";
tvResult.setText(myString5);
break;
caseR.id.btn6:
StringmyString6=tvResult.getText().toString();
myString6+="6";
tvResult.setText(myString6);
break;
caseR.id.btn7:
StringmyString7=tvResult.getText().toString();
myString7+=,7H;
tvResult.setText(myString7);
break;
caseR.id.btn8:
StringmyString8=tvResult.getText().toString();
myString8+="8";
tvResult.setText(myString8);
break;
caseR.id.btn9:
StringmyString9=tvResult.getText().toString();
myString9+="9";
tvResult.setText(myString9);
break;
caseR.id.btnAdd:〃判断,使用加戒乘除的操作符
StringmyStringAdd=tvResult.getText().toString();
if(myStringAdd.equals(null)){
return;
)
num1=Double.valueOf(myStringAdd);
tvResult.setText(null);
op=1;
opd="+”;
break;
caseR.id.btnSub:
StringmyStringSub=tvResult.getText().toString();
if(myStringSub.equals(null)){
return;
)
num1=Double.valueOf(myStringSub);
tvResult.setText(null);
op=2;
opd=
break;
caseR.id.btnMul:
StringmyStringMul=tvResult.getText().toString();
if(myStringMul.equals(null)){
return;
)
num1=Double.valueOf(myStringMul);
tvResult.setText(null);
op=3;
opd=3;
break;
caseR.id.btnDiv:
StringmyStringDiv=tvResult.getText().toString();
if(myStringDiv.equals(null)){
return;
)
num1=Double.valueOf(myStringDiv);
tvResult.setText(null);
op=4;
opd="+”;
break;
caseR.id.btnC:〃清除,将编辑框文本显示为空
tvResult.setText(,,H);
Result=0;
break;
caseR.id.btnDot:〃加入小数点,
StringmyStringDot=tvResult.getText().toString();
myStringDot+=
tvResult.setText(myStringDot);
break;
caseR.id.btnEqu:〃计算,以操作符为判断,选择所需的运算,并将结果输出
StringmyStringEqu=tvResult.getText().toString();
if(myStringEqu.equals(null)){
return;
)
num2=Double.valueOf(myStringEqu);
tvResult.setText(null);
switch(op){
case0:
Result=num2;
break;
case1:
Result=num1+num2;
break;
case2:
Result=num1-num2;
break;
case3:
Result=num1*num2;
break;
case4:
if(num2==0)〃除法中分子与分母之分
Result=0;
else
Result=num1/num2;
break;
default:
Result=0;
break;
)
tvResult.setText(Double.toString(Result));
//tvResult.setText(Double.toString(num1)+opd+Double.toString(num2)+n="+
Double.toString(Result));〃将结果完整输出
op=0;
break;
default:
break;
}
)
)
activity_main.xml
<?xmlversion=H1.0nencoding="
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android=n/apk/res/androidn
xmlns:app="/apk/res-auton
xmlns:tools="/tools"
android:layout_width=,'match_parentH
android:layout_height="match_parentH
android:background=',#000000"
>
<!--显示结果
<!-<LinearLayout
android:layout_width="fill_parent,,
android:layout_height=,,wrap_content">
<TextView
android:id=n@+id/tvResult"
android:layout_width=nfill_parent"
android:layout_height=,,wrap_content"
android:height="50dp”
android:text="@string/tvResult"/>
</LinearLayout>->
<EditText
android:id="@+id/tvResuir
android:layout_width=,,395dpH
android:layout_height="209dp"
android:focusable=,'false,,
android:gravity=',right,,
android:text="0H
android:textColor=n#FFFFFF"
android:textSize=,'85spH
app:layout_constraintBottom_toTopOf=',@+id/btnC,
app:layout_constraintEnd_toEndOf="parent”
app:layout_constraintHorizontal_bias="0.0,,
app:layout_constraintStart_toStartOf=,,parent,,
app:layout_constraint7bp_tolbpOf="parentn
app:layout_constraintVertical_bias="1.0"/>
<Button
android:id=M@+id/btnCM
androidJayou^width-'IOOdp',
android:layout_height="100dpn
android:width=M75dpH
android:background=,,@drawable/circle1"
android:text=nAC"
android:textAppearance="@style/TextAppearance.AppCompat.Display2H
android:textColor="@android:color/background_dark"
app:layout_constraintBottom_toTopOf=*,@+id/btn7"
app:layout_constraintEnd_toEndOf="pa「ent”
app:layout_constraintHorizontal_bias二"0.0”
app:layout_constraintStart_toStartOf="parent"/>
<Button
android:id=,,@+id/btnO"
android:layout__width-'100dp"
android:layout_height=,,100dp"
android:width='75dp"
android:backg「ound="@drawable/circle2”
android:text="0"
android:textAppearance=',@style/TextAppearance.AppCompat.Display2,'
android:textColor=',#FFFFFFH
app:layout_constraintBottom_toBottomOf="parent,,
app:layout_constraintStart_toStartOf="parentH/>
<Button
android:id="@+id/btn1"
android:layout_width="100dpK
android:layout_height="100dp"
android:width="75dp”
android:background=H@drawable/circle2n
android:text="r*
android:textAppearance=H@style/TextAppearance.AppCompat.Display2u
android:textColor="#FFFFFFH
app:layout_constraintBottom_toTopOf=',@+id/btnO"
app:layout_constraintStart_toStartOf=,'parent,'/>
<Button
android:id=n@+id/btn2n
android:layout_width="100dpH
android:layout_height="100dp"
android:width="75dp"
android:background="@drawable/circle2H
android:text=',2H
android:textAppearance=H@style/TextAppearance.AppCompat.Display2,'
android:textColor=M#FFFFFFM
app:layout_constraintBottom_toTopOf="@+id/btnDot”
app:layout_constraintStart_toEndOf=,'@+id/btn1H/>
<Button
android:id-'@+id/btn3M
android:layout_width=,,1OOdp"
android:layout_height=,,100dpn
android:width-75dp"
android:backg「ound="@drawable/circle2”
android:bufferType="spannableH
android:text="3"
android:textAppearance=',@style/TextAppearance.AppCompat.Display2n
android:textColor=H#FFFFFF"
app:layout_constraintBottom_to!bpO仁”@+id/btnEqu”
app:layout_constraintStart_toEndOf=,'@+id/btn2H/>
<Button
android:id=H@+id/btn4H
android:layout__width-'100dpH
android:layout_height二TOOdp"
android:width=^75dp,,
android:background=,,@drawable/circle2"
android:text=H4H
android:textAppearance=,,@style/TextAppearance.AppCompat.Display2,'
android:textColor="#FFFFFF”
app:layout_constraintBottom_toTopOf=',@+id/btn1H
app:layout_constraintStart_toStartOf=,'parentH/>
<Button
android:id="@+id/btn5"
androidJayou^width-'IOOdp'1
androidJayou^height-^OOdp"
android:width=,,75dp,,
android:background=',@drawable/circle2H
android:text="5n
android:textAppearance=',@style/TextAppearance.AppCompat.Display2,'
android:textColor=^^#FFFFFF'^
app:layout_constraintBottom_toTopOf=H@+id/btn2"
app:layout_constraintStart_toEndOf="@+id/btn4”/>
<Button
android:id=,'@+id/btn6"
androidJayout_width-'IOOdp',
android:layout_heigh仁"1OOdp”
android:width='75dp"
android:background=H@drawable/circle2"
android:text=',6n
android:textAppearance="@style/TextAppearance.AppCompat.Display2H
android:textColor=H#FFFFFFM
app:layout_constraintBottom_toTopOf=',@+id/btn3H
app:layout_constraintStart_toEndOf="@+id/btn5H/>
<Button
android:id=M@+id/btn7M
android:layout_width二TOOdp”
android:layout_height="100dp”
android:layout_row=,,0H
android:layout_column=,,5,'
android:width=,75dp'^
android:background=**@drawable/circle2H
android:text='7n
android:textAppearance="@style/TextAppearance.AppCompat.Display2H
android:textColor="#FFFFFFK
app:layout_constraintBottom_toTopOf=',@+id/btn4H
app:layout_constraintStart_toStartOf="parent"/>
<Button
android:id="@+id/btn8”
android:layout_width-'100dp"
android:layout_height="1OOdp'1
android:width=,75dpH
android:background=,'@drawable/circle2n
android:text='^8',
android:textAppearance=n@style/TextAppearance.AppCompat.Display2"
android:textColor=',#FFFFFFn
app:layout_constraintBottom_toTopOf="@+id/btn5”
app:layout_constraintStart_toEndOf="@+id/btn7H/>
<Button
android:id="@+id/btn9"
android:layout_width="1OOdp”
android:layout_height="100dp”
android:width二"75dp"
android:background="@drawable/circle2”
android:text='^9'^
android:textAppearance=',@style/TextAppearance.AppCompat.Display2,'
android:textColor=M#FFFFFFu
app:layout_constraintBottom_tolbpOf=',@+id/btn6,'
app:layout_constraintStart_toEndOf=,'@+id/btn8n/>
<Button
and「oid:id="@+id/btnSub”
android:layout_width=H100dp"
android:layout_height="100dp"
android:width='75dp"
android:backg「ound="@drawable/circle4”
android:text='^—^,
android:textAppearance="@style/TextAppearance.AppCompat.Body2H
android:textColor=M#FFFFFFM
android:textSize="24spn
app:layout_constraintBottom_toTopOf=n@+id/btnAddH
app:layout_constraintStart_toEndOf="@+id/btn3”/>
<Button
android:id=M@+id/btnAddM
android:layout_width-'1OOdp"
android:layout_height=',100dp"
android:width-75dp"
android:background=',@drawable/circle4H
android:text="+"
android:textAppearance=n@style/lextAppearance.AppCompat.Display2"
android:textColor=M#FFFFFF"
app:layout_constraintBottom_toBottomOf=',parent,,
app:layout_constraintStart_toEndOf=,'@+id/btnEqu"/>
<Button
android:id=,,@+id/btnMul"
androiddayou^width-MOOdp"
android:layout_height="1OOdp"
android:width-75dp"
android:background="@drawable/circle4"
android:text=Hx"
android:textAppearance="@style/TextAppearance.AppCompat.Display2H
android:textColor=H#FDFFFFFF"
app:layout_constraintBottom_to!bpOf="@+id/btnSub”
app:layout_constraintStart_toEndOf=,'@+id/btn6H/>
<Button
android:id-'@+id/btnDot"
android:layout_width=,,100dp,,
android:layout_height="100dpn
android:width=,,1Odp"
android:background=',@drawable/circle2n
android:text=,^.,,
android:textAppearance="@style/TextAppearance.AppCompat.Display2H
android:textColor="#FFFFFFH
app:layout_constraintBottom_toBottomOf=nparent"
app:layout_constraintStart_toEndOf="@+id/btnO”/>
<Button
android:id="@+id/btnEqu”
android:layout_width=H100dp"
android:layout_height=',100dpn
android:width="75dpu
android:background=',@drawable/circle2n
android:text=,,=H
android:textAppearance=,,@style/TextAppearance.AppCompat.Display2u
android:textColor=H#FFFFFF"
app:layout_constraintBottom_toBottomOf="parentH
app:layout_constraintStart_toEndOf="@+id/btnDot"/>
<Button
android:id="@+id/btnDiv"
android:layout_width=,,1OOdp"
android:layout_height="100dp”
androickwidth=“75dp”
android:background="@drawable/circle4”
android:text='7"
android:textAppearance="@style/TextAppearance.AppCompat.Display2,'
android:textColor=',#FFFFFFH
app:layout_constraintBottom_toTopOf="@+id/btnMul"
app:layout_constraintStart_toEndOf="@+id/btn9”/>
</androidx.constraintlayout.widget.ConstraintLayout
单元4国家开放大学Android智能手机编程形考任
务1
效果图
▼■8:00
生僻字
activity-mainoxml:
<?xmlversion="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height=",match_parent"
android:background="#696969">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="10dp"
android:layout_alignParentTop="true"
android:id="@+id/title"
android:orientation="horizontar,>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginBottom="3dp"
androidtext二"生僻字”
androidtextSize="25dp”
androidgravity="center”
android:textColor="#ffffff"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#afafaf"
android:layout_below="@+id/title'7>
<lmageView
android:id="@+id/disc"
android:layout_width="280dp"
android:layout_height="280dp,1
android:layout_centerHorizontal="true"
android:layout_below="@+id/title"
android:layout_marginTop="50dp"
android:src="@drawable/xcvb"/>
<lmageView
android:id="@+id/needle"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_below="@+id/title"
android:layout_marginLeft="150dp'7>
<RelativeLayout
android:id="@+id/musicl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/rr'
android:layout_marginTop=H20dp"
android:layout_marginBottom="10dp"
androidgravity="center”〉
<SeekBar
androidid="@+id/music_seek_bar”
android:layout_width="240dp"
android:layout_height="wrap_content7>
<TextSwitcher
android:id="@+id/text_switcher"
android:layout_width="80dp"
android:layout_height=n50dp"
android:layout_toRightOf="@+id/music_seek_bar">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="00:00/2:00"
android:textColor="@color/colorAccent7>
</TextSwitcher>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
androidJayouLheight='VOdp"
android:gravity="center"
androidid="@+id/iT
android:layout_marginBottom="20dp"
android:layout_alignParentBottom="true"
android:orientation="horizontar'>
<ImageView
android:id="@+id/playing_pre"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@drawable/music_previous"/>
<lmageView
android:id="@+id/playing_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_verticar'
android:src="@drawable/music_play"/>
<lmageView
android:id="@+id/playing_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity=',center_vertical"
android:src="@drawable/music_next"/>
</LinearLayout>
</RelativeLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
部分:
mainoactivity
packagecom.example.cungu.musicdemo;
importandroid.animation.ObjectAnimator;
importandroid.animation.ValueAnimator;
importandroid.content.ComponentName;
importandroid.content.lntent;
importandroid.content.ServiceConnection;
importandroid.graphics.Bitmap;
importandroid.graphics.Color;
importandroid.os.Build;
importandroid.os.lBinder;
importandroid.support.v7.app.AppCompatActivity;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.view.Window;
importandroid.view.WindowManager;
importandroid.view.animation.Linearlnterpolator;
importandroid.widget.Button;
importandroid.widget.lmageView;
importandroid.widget.SeekBar;
importandroid.widget.TextSwitcher;
importjava.text.SimpleDateFormat;
importjava.util.Date;
publicclassMainActivityextendsAppCompatActivityimplementsView.OnClickListener,
Runnable,ServiceConnection,SeekBar.OnSeekBarChangeListener{
privateImageViewdisc.needle.playingPre.playingPlay.playingNext;
privateObjectAnimatordiscAnimation,needleAnimation;〃自定义指针和唱盘
privatebooleanisPlaying=true;//0,l判断是否处于播放状态
〃声明服务
privatestaticfinalStringTAG=MainActivity.class.getSimpleName();
privateMediaService.MusicControllermMusicController;
〃使用方法:mMusicController.play();播放mMusicController.pause();暂停
privatebooleanrunning;
privateTextSwitchermSwitcher;
privateSeekBarmSeekBar;
©Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
〃设置透明栏
if(Build.VERSION.SDK_INT>=Build.VERSION.CODES.LOLLIPOP){
Windowwindow=getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
|WindowManager.LayoutParams.FLAG_TRANSLUCENT_NA\/IGATION);
window.getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|View.SYSTEM_UI_FLAG_LAYOUT_STABLE
);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROU
NDS);
window.setStatusBarColor(Color.TRANSPARENT);
)
〃滑动条部分
mSeekBar=(SeekBar)findViewByld(R.id.music_seek_bar);
mSeekBar.setOnSeekBarChangeListener(this);
mSwitcher=(TextSwitcher)findViewByld(R.id.text_switcher);
mSwitcher.setlnAnimation(this,android.R.anim.fadejn);
mSwitcher.setOutAnimation(this,android.R.anim.fade_out);
Intentintent=newlntent(this,MediaService.class);
〃增力口StartService,来增加后台播放功能
startService(intent);
〃绑定服务,使用context来绑定
//那个界面需要绑定就用哪个Activity
//参数1:Intent代表需要绑定哪一个Service
〃参数2:Serviceconnection回调接口,可以接收到Service连接成功和断开的回调,成功
就可以取到对象。
//绑定服务参数2就是服务和指定的对象绑定在一起
bindService(intent,this,BIND_AUTO_CREATE);
〃指针和唱片部分
initViews();〃定义背景图
setAnimations();
)
privatevoidinitViews(){
playingPre=(ImageView)findViewByld(R.id.playing_pre);
playingPlay二(ImageView)findViewByld(R.id.playing_play);
playingNext=(ImageView)findViewByld(R.id.playing_next);
disc=(ImageView)findViewByld(R.id.disc);
needle=(ImageView)findViewByld(R.id.needle);
playingPre.setOnClickListener(this);
playingPlay.setOnClickListener(this);
playingNext.setOnClickListener(this);
)
〃动画设置
privatevoidsetAnimations(){
discAnimation=ObjectAnimator.ofFloat(disc,"rotation",0,360);
discAnimation.setDuration(20000);
discAnimation.setlnterpolator(newLinearlnterpolator());
discAnimation.setRepeatCount(ValueAnimator.lNFINITE);
needleAnimation=ObjectAnimator.ofFloat(needle,"rotation",0,25);
needle.setPivotX(O);
needle.setPivotY(O);
needleAnimation.setDuration(800);
needleAnimation.setlnterpolator(newLinearlnterpolator());
)
©Override
publicvoidonClick(Viewv){
intid=v.getld();
switch(id){
caseR.id.playing_pre:〃前一曲
if(discAnimation!=null){
discAnimation.end();
playingQ;
)
break;
caseR.id.playing_play〃播放中
if(isPlaying){
playingQ;
}else{
if(needleAnimation!=null){
needleAnimation.reverse();
needleAnimation.end();
mMusicController.pauseO;
)
if(discAnimation!=null&&discAnimation.isRunning()){
discAnimation.cancel();
mMusicController.pauseO;
floatvalueAvatar二(float)discAnimation.getAnimatedValue();
discAnimation.setFloatValues(valueAvatar,360f+valueAvatar);
)
playingPlay.setlmageResource(R.drawable.music_play);
isPlaying=true;
)
break;
caseR.id.playing_next:〃下一曲
if(discAnimation!=null){
discAnimation.end();
playingQ;
}
break;
default:
break;
)
)
〃播放:L播放音乐2、动画旋转3、暂停图片切换为播放按钮图片
privatevoidplaying(){
needleAnimation.start();
discAnimation.start();
playingPlay.setlmageResource(R.drawable.music_pause);
mMusicController.play();〃播放
isPlaying=false;
)
〃二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二播放歌曲服务开启、停止、结束
©Override
protectedvoidonStart(){
super.onStart();
Threadthread=newThread(this);
thread.start();
)
©Override
protectedvoidonStop(){
running=false;
super.onStop();
)
©Override
protectedvoidonDestroy(){
//解除绑定
unbindService(this);
super.onDestroy();
}
//----------------------播放到当前音乐的滑动条及时间设置--------------------------
©Override
publicvoidrun(){
running=true;
try{
while(running){
if(mMusicController!=null){
longmusicDuration=mMusicControlle
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 地方课程课题申报书
- 亚马逊购买店铺合同范本
- 动漫授权协议合同范本
- mcn公司合伙合同范例
- 合同范本理解写好
- 个人软件销售合同范本
- 合伙餐饮采购合同范本
- 知识产权保护高地建设的实施计划
- 推动农业新质生产力发展路径探索
- 民营经济高质量发展推动力的关键措施
- 实验室在突发公共卫生事件中的作用和任务(143)-行政管理
- 三人合伙餐饮合同范本
- 树木栽培与养护合同样本2025
- 人教PEP版(2024)三年级下册英语Unit3 Learning better单元整体教学设计(共6课时)
- 2025年哈尔滨传媒职业学院单招职业技能测试题库完整
- 2025年河南林业职业学院单招职业技能测试题库完整版
- 地理-浙江省强基联盟2025年2月高三年级联考试题和答案
- 中华人民共和国建筑法
- 2024年济南护理职业学院高职单招(英语/数学/语文)笔试历年参考题库含答案解析
- 2024年江苏护理职业学院高职单招(英语/数学/语文)笔试历年参考题库含答案解析
- 执业助理医师报考执业医师执业期考核证明【范本模板】
评论
0/150
提交评论