由于这一周事情实在不少,所以今天决定上交这次实验了!
开始做时,也不清楚要做成什么样子,想过使用动画界面,使用列表,使用多个activity,把界面做好看一点,但又觉得该加点新功能才好,于是就试着按照自己的想法去一步步实现!
刚开始做的是程序只有五个Imagebutton的按钮,分别实现开始,下一首,暂停/播放,上一首,停止的功能,主要用到的是service类的onStartCommand()方法和onDestroy()方法,用到了ListView空间,涉及到计算的地方就是判断当前歌曲是否是第一首或最后一首,其他就没什么了!
做到这里时感觉做出来的东西还特简单,于是就想在实现点其他功能,这时我就想把歌曲目录显示出来,但如果直接用列表显示的话,主界面的背景和按钮就看不到了,影响视觉效果,于是就决定用spinner下拉列表实现,之前我还以为可以吧下拉列表完全隐藏,但做到最后我才发现列表至少有一行是隐藏不掉的,这时有点失望,但没想再改已经做的部分了。在做列表时,遇到了一个问题浪费了我很长时间,就是我在定义myadapter时:myadapter = new ArrayAdapter<String>(Ajtest4serviceActivity.this,android.R.layout.simple_spinner_item, mymusiclist);把第二个参数写成R.id.spinner了,而本来参数android.R.layout.simple_spinner_item是android里提供的,包含了一些组件相关的样式信息,所以不能写成自己spinner的id。出现这个错误时提示也特别头疼,不提示是哪行出了问题,所以会浪费很长时间。
然后我就想把按钮做成可拖动的,上网查了一下,似乎也不太麻烦,主要是实现OnTouchListener()监听器里的onTouch()方法,其中MotionEvent.ACTION_DOWN代表鼠标按下时刻,实验中必须在这时读取空间原本坐标;MotionEvent.ACTION_DOWN代表鼠标移动的过程,把处理代码放在这里的话,实现的效果是控件随鼠标的移动而不停移动;MotionEvent.ACTION_UP代表鼠标弹起,如果把处理代码放在这里的话,控件不会和鼠标一起移动,但会在鼠标氮气的瞬间由其本来位置一次性移动到鼠标氮气的位置;而类似的常数还有MotionEvent.ACTION_CANCEL,MotionEvent.ACTION_MASK等,再一次鼠标按下,移动到弹起的过程中均不会产生这些参数,但这些参数具体什么意思我也还不是太清楚。在判断空间位置时,必须要防止控件移出边界,这时就需要判断其具体坐标并作相应处理(不是太难,具体见代码)。可以用getResources().getDisplayMetrics()获得一个DisplayMetrics对象,这是一个包含了当前可显示界面很多信息(包含大小,分辨率和字体)的对象,当显示界面大小可变时,这个对象应该会大有用处。最后,必须在移动鼠标过程中不断更新视图,在这个方法中就要使用postInvalidate()方法,起到刷新作用。
这时,既然有了显示歌曲目录的下拉列表,如果没有点击列表就播放对应歌曲的功能的话就明显是个缺陷了,于是就增加了该功能,具体实现过程并不麻烦,其实就是值传递,为了防止传值冲突,我就把ImageButton的监听器里的值用负数替代(具体见代码)。
然后我又想到是否该有当前播放歌曲的显示呢?于是就增加了这个功能,文字效果用到了之前提到过的跑马灯效果。这一点也很简单,只是多增加了一个textview控件而已。
但这时又有问题了,有了当前播放歌曲的显示,那么当service里歌曲播放到下一首时,当前显示明显没有改变,这又是一个BUG。要解决这个问题,肯定要用到service向activity传值。上网收了一下,似乎必须得用BroadcastReceiver和sendBroadcast()了,于是就又开始学习广播,最后终于解决了这个问题(所用方法比较简单,就是建一个filter,然后加一个Action——其实就是一个标记而已,然后把filter绑定到一个BroadcastReceiver对象上,即所谓的注册,这样就可以接受sendBroadcast()发送的消息了)。
至此,该实验已基本完成。
该实验的缺点:
1),实验中用到了spinner控件,但spinner控件在初始化时就有一次默认的选择,所以为了避免一打开程序就播放,我使用了ischoosed标记变量,但这样还有问题,spinner控件不能连续两次选相同的选项,这一点就不好解决了,这也是我后悔用spinner的一个原因。
2),读取音乐文件的目录时固定的,没有自己选择文件功能,这一点导致放到手机上测试很不方便;但这个功能以后有空的话回加上去的;
3),没有任何与http有关的代码,本来是想实现一点下载歌曲或读取天气信息的功能的,但由于时间紧迫,哪些部分还没学习,所以就只能暂时先放下了!
代码:
//Ajtest4serviceActivity.java
package com.taylor.service.test4;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.Spinner;
import android.widget.TextView;
public class Ajtest4serviceActivity extends Activity
{
private ImageButton bt1 = null;
private ImageButton bt2 = null;
private ImageButton bt3 = null;
private ImageButton bt4 = null;
private ImageButton bt5 = null;
private int option = 0;
private DisplayMetrics dm;
private int screenWidth ;
private int screenHeight ;
private List<String> mymusiclist;
private TextView myTextView;
private Spinner mySpinner;
private ArrayAdapter<String> myadapter;
private static final String dir = "/sdcard/";
private boolean ischoosed = false;
private UpdateReceiver receiver;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main1);
dm = getResources().getDisplayMetrics();
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels-50;
bt1 = (ImageButton) findViewById(R.id.imagebt1);
bt2 = (ImageButton) findViewById(R.id.imagebt2);
bt3 = (ImageButton) findViewById(R.id.imagebt3);
bt4 = (ImageButton) findViewById(R.id.imagebt4);
bt5 = (ImageButton) findViewById(R.id.imagebt5);
mymusiclist = new ArrayList<String>();
mySpinner = (Spinner)findViewById(R.id.spinner);
myTextView = (TextView) findViewById(R.id.textview1);
receiver = new UpdateReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("myaction");
this.registerReceiver(receiver, filter);
bt1.setOnClickListener(listener);
bt2.setOnClickListener(listener);
bt3.setOnClickListener(listener);
bt4.setOnClickListener(listener);
bt5.setOnClickListener(listener);
bt1.setOnTouchListener(listener1);
bt2.setOnTouchListener(listener1);
bt3.setOnTouchListener(listener1);
bt4.setOnTouchListener(listener1);
bt5.setOnTouchListener(listener1);
getMusicList();
}
private void getMusicList()
{
File home = new File(dir);
if(home.listFiles(new MusicFilter()).length>0)
{
for(File file : home.listFiles(new MusicFilter()))
{
mymusiclist.add(file.getName());
}
myadapter = new ArrayAdapter<String>(Ajtest4serviceActivity.this,android.R.layout.simple_spinner_item, mymusiclist);
myadapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mySpinner.setAdapter(myadapter);
mySpinner.setOnItemSelectedListener(new Spinner.OnItemSelectedListener()
{
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1,
int arg2, long arg3)
{
Log.e("main",arg2+" selected");
if(ischoosed)
{
Intent intent = new Intent(Ajtest4serviceActivity.this, Myservice.class);
option = arg2;
if(option+1>=mymusiclist.size())
{
myTextView.setText("当前播放:"+mymusiclist.get(arg2)+" 下一首:"+mymusiclist.get(0));
}
else
{
myTextView.setText("当前播放:"+mymusiclist.get(arg2)+" 下一首:"+mymusiclist.get(arg2+1));
}
Bundle bundle = new Bundle();
bundle.putInt("option", option);
intent.putExtras(bundle);
startService(intent);
}
else
{
ischoosed = true;
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0)
{
arg0.setVisibility(View.VISIBLE);
}
});
}
}
OnTouchListener listener1 = new OnTouchListener()
{
int lastX=0, lastY=0;
@Override
public boolean onTouch(View v, MotionEvent event)
{
int action = event.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN: //鼠标按下时刻
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
Log.e("MAIN","action-down");
break;
case MotionEvent.ACTION_MOVE: //鼠标移动
Log.e("MAIN","action-move");
int dx = (int) event.getRawX() - lastX;
int dy = (int) event.getRawY() - lastY;
int l = v.getLeft() + dx;
int b = v.getBottom() + dy;
int r = v.getRight() + dx;
int t = v.getTop() + dy;
if (l < 0)
{
l = 0;
r = l + v.getWidth();
}
if (t < 0)
{
t = 0;
b = t + v.getHeight();
}
if (r > screenWidth)
{
r = screenWidth;
l = r - v.getWidth();
}
if (b > screenHeight)
{
b = screenHeight;
t = b - v.getHeight();
}
v.layout(l, t, r, b);
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
v.postInvalidate();
break;
case MotionEvent.ACTION_UP: //鼠标弹起
Log.e("MAIN","action-up");
break;
case MotionEvent.ACTION_CANCEL:
Log.e("MAIN","action-cancel");
break;
case MotionEvent.ACTION_MASK:
Log.e("MAIN","action-mask");
break;
}
return false;
}
};
OnClickListener listener = new OnClickListener()
{
ImageButton bt = null;
int x = 0;
@Override
public void onClick(View v)
{
bt = (ImageButton)v; //也可以不强制转换
Intent intent = new Intent(Ajtest4serviceActivity.this, Myservice.class);
switch(bt.getId())
{
case R.id.imagebt1:
option = -1;
break;
case R.id.imagebt2:
option = -2;
break;
case R.id.imagebt3:
option = -3;
break;
case R.id.imagebt4:
option = -4;
break;
case R.id.imagebt5:
x=1;
stopService(intent);
Ajtest4serviceActivity.this.finish();
break;
}
if(x==0)
{
Bundle bundle = new Bundle();
bundle.putInt("option", option);
intent.putExtras(bundle);
startService(intent);
}
}
};
class UpdateReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Bundle bundle=intent.getExtras();
int current=bundle.getInt("current");
if(current+1>=mymusiclist.size())
{
myTextView.setText("当前播放:"+mymusiclist.get(current)+" 下一首:"+mymusiclist.get(0));
}
else
{
myTextView.setText("当前播放:"+mymusiclist.get(current)+" 下一首:"+mymusiclist.get(current+1));
}
}
}
}
//Myservice.java
package com.taylor.service.test4;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
public class Myservice extends Service
{
private MediaPlayer myPlayer= null;
private List<String> myMusicList = new ArrayList<String>();
private static final String dir = "/sdcard/";
private String pathString = null;
private int choose = 0;
@Override
public IBinder onBind(Intent intent)
{
return null;
}
@Override
public void onCreate()
{
Log.e("Myservice","oncreate");
if(myPlayer==null)
{
myPlayer=new MediaPlayer();
myPlayer.setLooping(true);
}
musicList();
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.e("Myservice","onStartCommand");
if (intent != null)
{
Bundle bundle = intent.getExtras();
pathString = dir + myMusicList.get(choose);
if (bundle != null)
{
int option = bundle.getInt("option");
switch(option)
{
case -1:
playMusic(pathString);
broadcastEvent(choose); //疏忽了,竟忘了这一句,难怪直接点播放按钮时无当前播放显示
break;
case -2:
if(--choose<0)
{
choose = myMusicList.size()-1;
}
pathString = dir + myMusicList.get(choose);
playMusic(pathString);
broadcastEvent(choose); //这一句也是又修改的,没有的话点播放上一首按钮时当前播放显示不会改变
break;
case -3:
if(myPlayer.isPlaying())
{
myPlayer.pause();
}
else
{
myPlayer.start();
}
break;
case -4:
nextMusic();
break;
default:
choose = option;
pathString = dir+myMusicList.get(option);
playMusic(pathString);
break;
}
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy()
{
Log.e("Myservice","onDestroy");
if (myPlayer!= null)
{
myPlayer.stop();
myPlayer.release();
}
super.onDestroy();
}
private void playMusic(String pathString)
{
try
{
myPlayer.reset();
myPlayer.setDataSource(pathString);
myPlayer.prepare();
myPlayer.start();
myPlayer.setOnCompletionListener(new OnCompletionListener()
{
@Override
public void onCompletion(MediaPlayer mp)
{
nextMusic();
}
});
}
catch (Exception e)
{
e.printStackTrace();
}
}
private void nextMusic()
{
if(++choose>=myMusicList.size())
{
choose = 0;
}
pathString = dir + myMusicList.get(choose);
playMusic(pathString);
broadcastEvent(choose);
}
private void musicList()
{
File home = new File(dir);
if(home.listFiles(new MusicFilter()).length>0)
{
for(File file : home.listFiles(new MusicFilter()))
{
myMusicList.add(file.getName());
Log.e("music","000");
}
}
}
private void broadcastEvent(int current)
{
Intent intent=new Intent();
intent.putExtra("current", current);
intent.setAction("myaction");
sendBroadcast(intent);
}
}
class MusicFilter implements FilenameFilter //文件过滤器
{
@Override
public boolean accept(File dir, String filename)
{
return (filename.endsWith(".mp3"));
}
}
这是两个类文件,至于布局文件就特别简单了,只是几个ImageButton,TextView和一个Spinner而已。
截图:
打开程序:
播放音乐:(按钮播放或列表播放均可)
移动按钮: