欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android开发 - PsyDuck说明书

程序员文章站 2022-04-20 22:20:59
...

点击进入GitHub查看源代码

1 设计任务书

众所周知,随着移动互联网的发展,我国在线音乐类APP发展迅猛,不断受到资本热捧,如今在线音乐类APP开发功能得到了极大的丰富,除了基本的听歌搜索功能,还有听歌识曲、铃声剪辑、彩铃专区、在线KTV唱歌等功能,满足了用户对音乐的大部分需求。如今,消费不断升级,其融入了社交属性,和短视频、直播等时下最热门的内容相结合,对用户的吸引力进一步提升,用户规模持续增长,行业前景受到看好。

音乐是这个世界上最美好的东西,给人艺术的愉悦,智慧的启迪,音乐之美无处不在。本人认为音乐播放器具有一定的市场,并对当下较好的音乐app进行研究分析,进行了页面设计和需求分析,提出了系统的整体设计目标解决方案。并根据需求分析对系统做了概要设计和数据库设计,并详细探讨了几个关键功能模块的技术实现。

2 本人任务

本组课题:PusDuckMusic App
小组分工:cs(代码编写)
cs (UI设计)
感谢帮助:yjd(PsyDuck手绘)
ahj(部分图片处理)

3 项目背景

随着科技发展和人民生活质量的提高,大众对于音乐的需求越来越大。随着数码产品的普及,听歌渐渐成为人们生活的一部分。互联网给我们的生活带来很大的便利,我们可以在线听歌,后来随着技术的发展,大部分开始使用软件听歌,在随后随着手机的发展互app软件也可以满足我们听歌的需求。然而,纵观如今所有在线音乐类APP,大都有曲库和评论推送功能,同质化功能严重。

因此,PsyDuck Music旨在做好细节,利用简洁的页面,精简的功能吸引用户。同时,PsyDuck Music利用场景化的功能开发,细化丰富的场景,让音乐有了情感和温度,让用户找到内心情绪、情感的寄托,从而找到自己,增加音乐APP的忠诚度。

4 需求分析

本项目自行构思得出,由个人独立编写程序研究。本项目的目的是开发一个可以播放主流的音乐文本格式的播放器。设计的主要实现功能是播放MP3等格式的音乐文件,并且能控制播放,暂停,停止,歌曲列表文件的管理操作,在线播放,读取存储卡播放等多种播放控制,界面简明,操作简单。 除此之外,用户还可以在PsyDuck平台上发表动态,搜索并关注自己喜欢的音乐人,拓展朋友圈,了解音乐文化。如图4-1所示,我将从基本控制、友好性、界面和可靠性4个方面对PsyDuck Music进行需求分析。

Android开发 - PsyDuck说明书

图 4-1 PsyDuck系统需求分析图

4.1PsyDuck播放器的基本控制要求

  • 顺序播放:点击播放列表中的歌曲进行“顺序播放”按钮,点击“查看更多”标识可显示更多的歌曲信息,包括所含歌曲信息和演唱歌手等。
  • 暂停播放:当歌曲正在播放时,点击歌曲播放界面下方的“暂停播放”按钮,停止当前播放的歌曲。
  • 下一首播放:当歌曲正在播放时,点击歌曲播放界面下方的“下一首播放”按钮,暂停当前播放的歌曲,同时播放歌单中下一首歌曲。

4.2PsyDuck播放器友好性需求

  • 视觉外观:使用PsyDuck Music时,播放器根据歌曲文件的特性,通过视觉外观动态显示,外观优美。
  • 系统稳定:使用PsyDuck Music时能显示播放器的状态,是播放还是暂停,播放音乐时稳定。
  • 后台播放:使用PsyDuck Music时,能够进行后台播放。
  • 播放模式:播放音乐时,更改播放模式能够顺利地、快速地、无差错地完成模式的转换。

4.3PsyDuck Music 界面需求

PsyDuck Music界面要求布局合理,颜色舒适,控制按钮友好;为了较少开发工程量,可以借鉴现在流行的播放器的皮肤作为播放器的界面目标需求。

4.4PsyDuck Music可靠性需求

PsyDuck Music系统能持续运行,不影响其他程序的使用,不多占用内存,不会造成死机等问题。

5 技术路线和实现方案

5.1系统概况

PsyDuck Music系统基于android平台和SQLITE数据库,并调用多种API端口,利用统一的命名规则对组件和变量进行命名。安卓手机只需装上我们的客户端,并成功注册认证,登录系统后便能享受音乐。下面介绍一下PsyDuck Music系统所使用的技术。

  1. 多种控件的使用
    在PsyDuck Music系统中,我通过调用layout中的不同的控件,比如简单的TextView、ListView、EditText、Combox、Button、SeekBar等,高级控件例如ExpendListView、ImageViewFactory。除此之外,在此基础上,我还参考了网上的资料,学习和模仿了ViewPagerAdapter、SearchView的编写,实现了流畅的轮播图和歌曲搜索功能,通过这么些控件的调用来使得UI效果变得更加的符合用户的审美需求。

  2. SQLite数据库
    SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。SQLite的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中只需要几百k的内存,能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟Java语言相结合,拥有 ODBC接口,比起Mysql、PostgreSQL处理速度更快。

  3. C/S架构
    PsyDuck Music使用俩层C/S架构,应用服务器运行数据负荷较轻。一旦服务器程序被启动,就随时等待响应客户程序发来的请求;PsyDuck Music程序运行在用户自己的手机上,对应于数据库服务器,当需要对数据库中的数据进行任何操作时,PsyDuck Music就自动地寻找服务器程序,并向其发出请求,服务器程序根据预定的规则作出应答,送回结果,服务器运行数据负荷较轻。除此之外,数据的储存管理功能较为透明。

5.2技术实现

本系统采用俩层C/S架构,服务器负责数据的管理,客户机负责完成与用户的交互任务。
Android开发 - PsyDuck说明书

图 5-1 C/S架构详解

在C/S结构中,PsyDuck Music分为两部分:服务器部分和客户机部分。服务器部分是多个用户共享的信息与功能,执行后台服务,如控制共享数据库的操作等;客户机部分为用户所专有,负责执行前台功能,在出错提示、在线帮助等方面都有强大的功能,并且可以在子程序间*切换。
PsyDuck Music系统的全局架构如下图5-2所示:

Android开发 - PsyDuck说明书

图 5-2 PsyDuck Music系统全局架构图

5.3开发环境

  • 开发工具:Eclipse
  • 集成开发环境(IDE):Eclipse+ADT+JDK8+Android SDK
  • 开发语言:java
  • 操作系统:Windows 10
  • 数据库:SQLLite

6 数据库设计

PsyDuck Music系统的数据库设计详情见下。

表格 6-1 User表

User表 属性名 数据类型 长度 备注
Uid Varchar 10 非空
Upass Varchar 16 非空
Udate Data 非空

表格 6-2 Song表

Song表 属性名 数据类型 长度 备注
Sid Varchar 50 非空
Sname Varchar 16 非空
Singer Varchar 50 非空
Sdate Data 非空
Stime Time 非空

表格 6-3 Ssheet表

Ssheet表 属性名 数据类型 长度 备注
Ssid Varchar 10 非空
Ssname Varchar 16 非空
Uid Varchar 50 非空
Ssdate Timestamp 非空

表格 6-4 Prend表

Prend表 属性名 数据类型 长度 备注
Ud Varchar 10 非空
Pid Varchar 16 非空
Pitem Varchar 500 非空
Pdate Timestamp 非空

7 方法说明

表格 7-1 PsyDuck Music系统方法说明表

方法名 功能 备注(须输入的参数)
Csnb 定义了Csnb的类
Fans 定义了Fans的类
Find. setSearchWay 设置搜索方法 SearchView.SearchWay< String>
Find. initListView 初始化歌曲库
Find.MyOnClickListener 定义了切换歌曲页面的内部类
FrameTabActivity 主菜单切换
Guanzhu 定义了Guanzhu的类
MusicService.play 播放音乐 String path
MusicService.pause 暂停播放音乐
MusicService.replay 查询播放音乐
MusicService.stop 停止播放音乐
MusicService.getMusicLength 获取资源文件长度
MusicService. getCurrentProgress 获取当前进度
NormalActivity 定义了NormalActivity的类
Prend 定义了Prend的类
PsyDuckIntroduction 定义了PsyDuckIntroduction的类
Prend.setMessage 发布动态 String prendItem
PsyDuckItemActivity 定义了PsyDuckItemActivity的类
PsyDuckItemActivity.logout 退出登录 String uid
PsyDuckMusicActivity 定义了PsyDuckMusicActivity的类
PsyDuckMusicActivity.login 用户登录 String uid,String upass
PsyDuckMusicActivity.rememberMe 记住我选项
RadioActivity 定义了RadioActivity的类
RegisterActivity 定义了RegisterActivity的类
RegisterActivity.Reg 用户注册 String uid,String upass,Boolean man,int hobby
SearchView 定义了SearchView的类
SearchView. setSearchWay 设置匹配数据的方法 SearchWay search
SearchView .getText 获取搜索框的文字
SearchView .afterTextChanged 搜索框的文字发生变化 Editable s
SearchView .setWaitTime 设置搜索延时时间 int waitTime
SearchView .WaitThread 延时搜索的线程
SearchWay 定义用于匹配项的内部类
SongItemActivity 定义了SongItemActivity的类
Songs 定义了Songs的类
Songs.initSeekBar 初始化进度条
Songs .updateProgress 跟新音乐播放的进度条
Songs .MyOnClickListener 切换歌曲详细信息内部类
StartActivity 定义了StartActivity的类
ViewPagerAdapter 定义了ViewPagerAdapter的内部类

8 总体设计

根据需求分析和系统运行的需要,PsyDuck Music系统需要实现六个主要模块的功能。
Android开发 - PsyDuck说明书

图 8-1 PsyDuck Music系统模块功能图
  1. 用户登录:任何一个系统,都需要一个访问系统的入口。用户需要通过自行注册帐号密码登陆PsyDuck Music App,验证通过后才能使用系统。

  2. 用户注册:主要包括四个信息。本系统用户需要输入用户名,密码,性别,爱好完成注册。用户一旦完成注册,就能够成为PsyDuck Music的会员登入App。

  3. 歌曲查询:用户需要在登录以后,才能进行歌曲。首先用户进入到“查找”的菜单栏下,输入需要查找的歌曲名称或者歌手名称即可。

  4. 歌曲播放:歌曲播放作为系统的核心模块。用户需要在登录以后,才能进行歌曲播放。首先用户进入到一个歌单的显示页面,点击“顺序播放”按钮即可。

  5. 动态发布:用户需要在登录以后,才能进行动态发布。首先用户进入到“动态”的菜单栏下,输入动态内容,点击“发布动态”按钮即可。

  6. 动态查询:用户需要在登录以后,才能进行动态查询。首先用户进入到“动态”的菜单栏下,PsyDuck Music会自动进行查询并显示用户的历史动态。

  7. 个人/关注者/粉丝信息查看:用户需要在登录以后,才能进行关注/粉丝查看。首先用户进入到“我的”的菜单栏下,点击对应的按钮,PsyDuck Music切换页面显示用户自己/关注者/粉丝的信息。

9 详细设计

9.1PsyDuck Music初始化页面

Android开发 - PsyDuck说明书

图 9-1 PsyDuck Music初始化页面

PsyDuck Music初始化页面,在程序开始运行时显示,3秒过后会自动跳转到登录界面。

9.2PsyDuck Music登录页面

Android开发 - PsyDuck说明书

图 9-2 PsyDuck Music登录页面
登录界面,用户需要输入已经注册的用户名和密码,若用户名和密码与数据库里面的用户注册时的账号和密码不匹配,将提示错误信息;若用户名和密码与数据库的用户注册时的账号和密码相匹配,则进行页面跳转。

9.3PsyDuck Music项目介绍页面

Android开发 - PsyDuck说明书

图 9-3 PsyDuck Music项目介绍页面

项目介绍界面,用户可以看到关于PsyDuck Music的项目介绍。

9.4 PsyDuck Music作者信息页面

Android开发 - PsyDuck说明书

图 9-4 PsyDuck Music作者信息页面

9.5 PsyDuck Music用户注册页面

Android开发 - PsyDuck说明书

图 9-5 PsyDuck Music用户注册页面(默认)
![用户注册成功](https://img-blog.csdnimg.cn/20200706152259409.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzAyODQ3,size_16,color_FFFFFF,t_70#pic_center)
图 9-6 PsyDuck Music用户注册成功页面

注册界面。用户需要自己设置自己的用户名、密码、性别、爱好等信息。完成注册后,自动跳到登录界面。

9.6 PsyDuck Music“我的”页面

Android开发 - PsyDuck说明书

图 9-7 PsyDuck Music“我的”界面

“我的”界面。用户在登陆之后默认显示的页面,内含个人信息和歌单信息。

9.7 PsyDuck Music“电台”页面

Android开发 - PsyDuck说明书

图 9 8 PsyDuck Music“电台”界面

“电台”界面,内含活动轮播图信息和电台信息。

9.8 PsyDuck Music歌曲查询页面

Android开发 - PsyDuck说明书

图 9 9 PsyDuck Music歌曲查询界面(默认)

Android开发 - PsyDuck说明书

图 9 10 PsyDuck Music歌曲查询界面(查询)

歌曲查询页面,用户登录以后,进入到“查找”的菜单栏下,输入需要查找的歌曲名称或者歌手名称可进行歌曲查询。

9.9 PsyDuck Music歌曲播放页面

Android开发 - PsyDuck说明书

图 9 11 PsyDuck Music歌曲播放界面

歌曲播放页面,用户登录以后,进入到歌单的显示页面,点击“顺序播放”可进行歌曲播放。

9.10 PsyDuck Music动态发布页面

Android开发 - PsyDuck说明书

图 9 12 PsyDuck Music动态发布界面

动态发布页面,用户登录以后,进入到“动态”的菜单栏下,输入动态内容并点击“发布动态”可进行动态发布。

9.11 PsyDuck Music动态查询页面

Android开发 - PsyDuck说明书

图 9-13 PsyDuck Music动态查询界面

动态查询页面,用户登录以后,进入到“动态”的菜单栏下,PsyDuck Music会自动进行查询并显示用户的历史动态。

9.12 PsyDuck Music信息查看页面

Android开发 - PsyDuck说明书

图 9-14 PsyDuck Music信息查看界面(自己)
Android开发 - PsyDuck说明书
图 9-15 PsyDuck Music信息查看界面(关注者)

Android开发 - PsyDuck说明书

图 9-16 PsyDuck Music信息查看界面(粉丝)

信息查看界面可分为三类,一是用户自己的信息界面,二是用户关注者的信息界面,三是用户粉丝的信息界面,用户登录后,在“我的”菜单栏下点击相应的按钮即可查看对应信息界面。

10 工作总结

通过从开学到现在的移动开发课程学习,我收获了很多知识,得到了很大的提升。这将近大半个月的系统开发,更是让我的动手开发能力得到了进步。在PsyDuck Music的系统开发的过程中遇到了超多问题,很幸运的是都有人经历过,大多数通过百度的方式都可以解决。其中有一个错误,让人印象很深的是百度所给的解决方法无法解决,最后是通过阅读安卓源码的方式解决的(附安卓源码地址:https://www.androidos.net.cn/sourcecode)。我向来很少阅读英文文献,平时对这个还会有些抗拒,但是这次系统开发让我们意识到,其实英文API对于理解程序和应用有很大的帮助,有一种醍醐灌顶的感觉。另外,感谢课程老师的耐心指导,在系统开发的过程中,我体会过遇到问题的烦躁、问题没被解决的焦虑以及解决问题后的满足和自豪,这一切都是值得的。
(遇到问题汇总博客网址:
https://blog.csdn.net/qq_44702847/article/details/106708544
同时,PsyDuck Music这个系统也存在很多不足,比如系统的权限安全问题,由于自己的水平不高,所有的代码内容都是在同一个包里的,这就带来了系统的安全问题。针对这一点,我后续会进行改进,并更新到GitHub网站上去,网址:https://github.com/ZUFEcsc/Android-PsyDuck-Music

11 附录

Android开发 - PsyDuck说明书

图 11-1 PsyDuck Music 项目工程目录图

11.1PsyDuckMusicActivity.java代码

package com.cn.csnb;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;

public class PsyDuckMusicActivity extends Activity {
	public static final String SP_INFO = "zscd_data";
	public static final String USERID = "UserId";
	public static final String USERPASS = "UserPass";
	private EditText etUid;
	private EditText etUpwd;
	private String uidStr;
	private String upwdStr;
	private CheckBox cb;
	private TextView tvPsyduck;
	private TextView tvCsnb;
	
	String sq;
	Connection conn;
	Statement st;
	ResultSet rs;
	final String driverName="com.microsoft.sqlserver.jdbc.SQLServerDriver";
	final String dbURL="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ZSCD";
	final String userName="sa";
	final String userPwd="123";
	String sqlStr;
	
	/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.psy_duck_music);
        
        //跳转项目信息
        tvPsyduck = (TextView)this.findViewById(R.id.tv_psyduck);
        tvPsyduck.setOnClickListener(new View.OnClickListener() {
			
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Intent itPsyduck = new Intent(PsyDuckMusicActivity.this, PsyDuckIntroduction.class);
        		startActivity(itPsyduck);
			}
		});
        
        //跳转个人信息
        tvCsnb =(TextView)this.findViewById(R.id.tv_writer);
        tvCsnb.setOnClickListener(new View.OnClickListener() {
			
			public void onClick(View v) {
				// TODO Auto-generated method stub
				Intent itCsnb = new Intent(PsyDuckMusicActivity.this, Csnb.class);
        		startActivity(itCsnb);
			}
		});

        etUid = (EditText)this.findViewById(R.id.etUid);
        etUpwd = (EditText)this.findViewById(R.id.etUpwd);
        
        cb = (CheckBox)this.findViewById(R.id.cbRemember);
        
        checkIfRemember();
        
        Button btnLogin = (Button) this.findViewById(R.id.button1);
		btnLogin.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				// TODO Auto-generated method stub
				String userName = etUid.getText().toString().trim();
				String userPass = etUpwd.getText().toString().trim();
				
//				SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("/data/data/com.cn.csnb/zscd.db", null);
//				Cursor qc = db.query("user", null, "uname=? and upwd=?", new String[] { userName, userPass }, null,
//						null, null);
//				if (qc.getCount() > 0) {
//					Intent it = new Intent(ZscdcsActivity.this, FrameTabActivity.class);
//					startActivity(it);
////					qc.close();
////					db.close();
//				}
				Intent it = new Intent(PsyDuckMusicActivity.this, FrameTabActivity.class);
				startActivity(it);
			}
		});
		Button btReg = (Button) this.findViewById(R.id.button2);
		btReg.setOnClickListener(new View.OnClickListener() {

			public void onClick(View v) {
				// TODO Auto-generated method stub
				Intent it = new Intent(PsyDuckMusicActivity.this, RegisterActivity.class);
				startActivity(it);
			}
		});

//        Button btLogin = (Button)this.findViewById(R.id.button1);
//        btLogin.setOnClickListener(new View.OnClickListener() {
//        	public void onClick(View v) {
//				// TODO Auto-generated method stub
//				Intent it = new Intent(ZscdcsActivity.this,FrameTabActivity.class);
//				startActivity(it);
//			}
//        });
//        
//        Button bt = (Button)this.findViewById(R.id.button2);
//        bt.setOnClickListener(new View.OnClickListener() {
//			
//			public void onClick(View v) {
//				// TODO Auto-generated method stub
//				Intent it = new Intent(ZscdcsActivity.this,RegisterActivity.class);
//				startActivity(it);
//			}
//		}); 
        Button btCreate = (Button)this.findViewById(R.id.button3);
        btCreate.setOnClickListener(new View.OnClickListener() {
			
			public void onClick(View v) {
				// TODO Auto-generated method stub
				SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("/data/data/com.cn.csnb/zscd.db", null);
				String sql = "create table user(uid integer primary key autoincrement,uname text,upwd text)";
				db.execSQL(sql);
			}
		});
        
        btCreate.setVisibility(View.GONE);
        
    }
    
    @Override
	protected void onStop() {
		// TODO Auto-generated method stub
		super.onStop();
		if(cb.isChecked())
		{
			uidStr = etUid.getText().toString().trim();
			upwdStr = etUpwd.getText().toString().trim();
			rememberMe(uidStr,upwdStr);
		}
	}

	//从SharedPreferences中读取用户的账号和密码
    public void checkIfRemember()
    {
    	SharedPreferences sp = getSharedPreferences(SP_INFO,MODE_PRIVATE);
    	uidStr = sp.getString(USERID, null);
    	upwdStr = sp.getString(USERPASS, null);
    	if(uidStr!=null && upwdStr!=null)
    	{
    		etUid.setText(uidStr);
    		etUpwd.setText(upwdStr);
    		cb.setChecked(true);
    	}
    }
    
    //将用户的id和密码存入SharedPreferences
    public void rememberMe(String uid,String upwd)
    {
    	SharedPreferences sp = getSharedPreferences(SP_INFO,MODE_PRIVATE);
    	SharedPreferences.Editor editor = sp.edit();
    	editor.putString(USERID,uid);
    	editor.putString(USERPASS, upwd);
    	editor.commit();
    }
}

11.2 RegisterActivity.java代码

package com.cn.csnb;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class RegisterActivity extends Activity {
	private EditText etUserName;
	private EditText etUserPass;
	
	String sq;
	Connection conn;
	Statement st;
	ResultSet rs;
	final String driverName="com.microsoft.sqlserver.jdbc.SQLServerDriver";
	final String dbURL="jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ZSCD";
	final String userName="sa";
	final String userPwd="123";
	String sqlStr; 
	
	 public void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);
	        setContentView(R.layout.register);
	        
	        etUserName = (EditText)this.findViewById(R.id.editText1);
	        etUserPass = (EditText)this.findViewById(R.id.editText2);	        
	        
	        Button btReg = (Button)this.findViewById(R.id.button1);
	        Button btBack = (Button)this.findViewById(R.id.button2);
	        btReg.setOnClickListener(new View.OnClickListener() {
				
				public void onClick(View v) {
					// TODO Auto-generated method stub
					SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("/data/data/com.cn.csnb/zscd.db", null);
					String userName = etUserName.getText().toString().trim();
					String userPass = etUserPass.getText().toString().trim();
					String sql = "insert into user(uname,upwd) values('"+userName+"','"+userPass+"')";
					db.execSQL(sql);
					db.close();
					try {
						Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
						conn=DriverManager.getConnection(dbURL,userName,userPwd);
						sqlStr="insert into users values('"+userName+"','"+userPass+"')";
						st=conn.createStatement();
						st.execute(sqlStr);
						
					}
					catch(Exception e1) {
						System.out.print("数据库连接失败"+e1.getMessage());
					}
					finish();
					if(userName != "" & userPass !="")
					{
						AlertDialog.Builder builder  = new Builder(RegisterActivity.this);
						 builder.setTitle("恭喜") ;
						 builder.setMessage("用户 "+userName+" 注册成功 ~ " ) ;
						 builder.setPositiveButton("确定" ,null);
						 builder.show(); 
						Intent itreturn = new Intent(RegisterActivity.this,PsyDuckMusicActivity.class);
						startActivity(itreturn);
					}
				}
			});
	        btBack.setOnClickListener(new View.OnClickListener() {
				
				public void onClick(View v) {
					// TODO Auto-generated method stub
					finish();
				}
			});
	    }
}


11.3 SearchView.java代码

package com.cn.csnb;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * Created by Administrator on 2016/8/31.
 * 搜索框
 */
public class SearchView extends LinearLayout implements TextWatcher{
 
    private EditText et_search;     //输入框
    private ImageView iv_clear;     //删除图标
 
    private SearchWay mSearch;      //匹配方法
    private String searchText;      //改变后的文字
    private WaitThread waitThread;  //等待线程
    private int waitTime = 200;     //延时搜索时间,默认200ms
    private int curTime;            //当前延时时间
    private Handler mHandler;
 
    public SearchView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //加载布局文件
        View view = LayoutInflater.from(context).inflate(R.layout.find, null);
 
        //获取控件
        et_search = (EditText) view.findViewById(R.id.ed_find);
        iv_clear = (ImageView) view.findViewById(R.id.img_clear);
 
        //设置清空按钮的触发器
        iv_clear.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                et_search.setText("");
            }
        });
 
        //读取属性
        TypedArray typed = context.obtainStyledAttributes(attrs, R.styleable.SearchView);
        String s;
        //文字大小
        float textSize = typed.getDimension(R.styleable.SearchView_sv_textSize, 15);
        et_search.setTextSize(textSize);
        //搜索框文字
        s = typed.getString(R.styleable.SearchView_sv_text);
        if (s != null){
            et_search.setText(s);
        }
        //提示文字
        s = typed.getString(R.styleable.SearchView_sv_hint);
        if (s != null){
            et_search.setHint(s);
        }
        //是否隐藏搜索图标
//        boolean hideImg = typed.getBoolean(R.styleable.SearchView_sv_hideImg, false);
//        if (hideImg) {
//            view.findViewById(R.id.img_search).setVisibility(GONE);
//        }
        //回收资源
        typed.recycle();
 
        //文字改变监听
        et_search.addTextChangedListener(this);
 
        //异步处理
        mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                //更新回调接口
                if (0 == msg.what){
                    waitThread = null;
                    //匹配结果回调
                    List searchList = new ArrayList();
                    List list = mSearch.getData();
                    if (list != null) {
                        for (Object o : list) {
                            if (mSearch.matchItem(o, searchText)) {
                                searchList.add(o);
                            }
                        }
                        mSearch.update(searchList);
                    }
                }
            }
        };
 
        //把布局添加到当前控件中
        ViewGroup.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        addView(view, params);
    }
 
    /**
     * 设置匹配数据的方法
     */
    public void setSearchWay(SearchWay search){
        mSearch = search;
    }
 
    /**
     * 获取搜索框的文字
     */
    public String getText(){
        return et_search.getText().toString();
    }
 
    public SearchWay getSearchWay() {
        return mSearch;
    }


    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
 
    }
 

    public void onTextChanged(CharSequence s, int start, int before, int count) {
 
    }
 

    public void afterTextChanged(Editable s) {
        //删除图标
        if (s.toString().isEmpty()){
            iv_clear.setVisibility(GONE);
        }else {
            iv_clear.setVisibility(VISIBLE);
        }
 
        if (mSearch != null) {
            if (null == waitThread) {
                waitThread = new WaitThread();
                waitThread.start();
            } else {
                //搜索框的文字发生变化就重置等待时间
                if (!searchText.equals(s.toString())) {
                    curTime = 0;
                }
            }
        }
 
        searchText = s.toString();
    }
 
    /**
     * 设置搜索延时时间
     * @param waitTime 毫秒,精度为100ms
     */
    public void setWaitTime(int waitTime){
        this.waitTime = waitTime;
    }
 
    /**
     * 延时搜索的线程
     */
    private class WaitThread extends Thread{
        @Override
        public void run() {
            //等待延时
            for (curTime = 0; curTime < waitTime; curTime += 100){
                try {
                    Thread.sleep(100);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
 
            mHandler.sendEmptyMessage(0);
        }
    }
 
    /**
     * 用于匹配项
     */
    public static abstract class SearchWay<T>{
        /**
         * @return 数据源
         */
        public abstract List<T> getData();
 
        /**
         * @return item中是否包含有s
         */
        public abstract boolean matchItem(T item, String s);
 
        /**
         * 更新列表
         * @param resultList 匹配的数据,重新加载到列表
         */
        public abstract void update(List<T> resultList);
    }
}