最近没有怎么编码,就把断断续续做了半年的毕业设计拿出来回顾一下。
校园助手,分为服务器端与Android客户端,在此主要介绍客户端,服务器是一位大神用node.js写的。
主要实现的功能有:登陆,信息查询,地图,订餐,网页的调用与解析,主要费劲的就是界面。
客户端的框架是参照网上讲解新浪微博客户端的视频。在现在的工作中经常遇到界面更新的不便,但是这个框架就很解决了这个问题,只是刚入门的我还不知道,遇到很多挫折之后才发现这个框架的便捷。下面就开始简单描述一下:
public class MainService extends Service implements Runnable {
private static final String TAG = "MainService";
private static Queue<Task> tasks = new LinkedList<Task>();
private static ArrayList<Activity> appActivities = new ArrayList<Activity>();
/**
* 标志执行任务的线程是否启动
*/
public static boolean isRun;
/**
* 系统当前的用户
*/
public static UserInfo nowUser;
/**
* 标志当前网络是否可用
*/
public static boolean isNetAvailable = false;
@Override
public void onCreate() {
//启动线程执行任务
Thread thread = new Thread(this);
thread.start();
isRun = true;
//启动一个新线程获取网络状态
new Thread(new Runnable() {
@Override
public void run() {
//一直获取网络状态
isNetAvailable = NetService.getNetWorkState(MainService.this);
}
}).start();
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* 添加一个Activity对象
在每个Activity启动的时候就调用这个函数,将自己的引用加入到主服务,便于管理,更方便界面的更新
* @param activity
*/
public static void addActivity(Activity activity) {
if (!appActivities.isEmpty()) {
for (Activity at : appActivities) {
if (at.getClass().getName()
.equals(activity.getClass().getName())) {
appActivities.remove(at);
break;
}
}
}
appActivities.add(activity);
}
/**
* 根据Activity 的Name 获取Activity对象
需要界面的引用时,就从列表获取,很方便地得到界面的引用,从而更新界面
* @param name
* @return
*/
private static Activity getActivityByName(String name) {
if (!appActivities.isEmpty()) {
for (Activity activity : appActivities) {
if (null != activity) {
if (activity.getClass().getName().indexOf(name) > 0) {
return activity;
}
}
}
}
return null;
}
/**
* 新建任务
界面需要执行耗时操作时,就调用此函数,将任务交给service执行,当执行完后就调用activity的引用来更新界面
* @param t
*/
public static void newTask(Task t) {
tasks.add(t);
}
/**
* 主服务启动后,一直从任务队列中取出任务执行
*/
public void run() {
while (isRun) {
Task task = null;
if (!tasks.isEmpty()) {
task = tasks.poll();// 执行完任务后把改任务从任务队列中移除
if (null != task) {
doTask(task);
}
}
}
}
// 处理任务
private void doTask(Task t) {
Message msg = handler.obtainMessage();
msg.what = t.getTaskId();
switch (t.getTaskId()) {
//直接在这里进行耗时的操作
//最好将各模块进行封装,从而使主服务的代码简洁明了
case Task.USER_LOGIN: {
UserInfo loginUser = (UserInfo) t.getTaskParams().get("loginUser");
if (null != loginUser) {
nowUser = LoginService.login(loginUser);//耗时操作
msg.obj = nowUser;
Log.i(TAG, "用户登录————————>" + nowUser.getUserName());
}
break;
}
default:
break;
}// end of switch
handler.sendMessage(msg);
}
/**
* 异步处理消息
*/
@SuppressLint("HandlerLeak")
public static Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
IAssistantActivity activity = null;
switch (msg.what) {
//处理耗时操作后,发送过来的消息
//将结果通过参数传过来,然后通过activity的引用传入界面
case Task.USER_LOGIN: {
if (null != msg.obj) {
activity = (IAssistantActivity) getActivityByName("LoginActivity");
}
break;
}
default:
break;
}//end of switch
//通过activity的引用调用相应界面的更新函数
activity.refresh(msg.obj);
};
};
/**
* 退出系统
退出系统时,很方便地清楚掉所有的activity
* @param context
*/
public static void appExit(Context context) {
// Finish 所有的Activity
for (Activity activity : appActivities) {
if (!activity.isFinishing())
activity.finish();
}
// 结束 Service
Intent service = new Intent("cn.edu.wit.services.MainService");
context.stopService(service);
}
}
这个主服务基本可以完全复用,根据需求添加一些内容即可。
再来看看界面这边是如何搭建的
public class LoginActivity extends Activity implements IAssistantActivity {
public static final String TAG = "LoginActivity";
private ProgressDialog progressDialog = null;
private Button btn_Login;
private ClearEditText etUserId;
private ClearEditText etPassword;
private CheckBox cbIsRemember;
private CheckBox cbIsAuto;
private ImageButton ib_spinner;
protected View listView;
private PopupWindow pop;
private List<String> userIDs ;
private List<UserInfo> loginedUsers ;
private MyAdapter adapter;
private Animation shake ;
private UserInfoServices userInfoServices = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
//初始化界面
init();
}
@Override
public void init() {
//确保主服务已启动
if(!MainService.isRun){
Intent service = new Intent(this, MainService.class);
startService(service);
}
//获取所有用户,添加到登陆框的下拉列表中
userInfoServices = new UserInfoServices(LoginActivity.this);
//获取所用用户
initData();
initView();
// 把自己添加到Activity集合里面
MainService.addActivity(this);
}
/**
* 初始化界面
*/
private void initView() {
//一个抖动动画
shake = AnimationUtils.loadAnimation(LoginActivity.this, R.anim.shake);
etUserId = (ClearEditText) findViewById(R.id.userid);
etPassword = (ClearEditText) findViewById(R.id.password);
cbIsRemember = (CheckBox) findViewById(R.id.isremember);
cbIsAuto = (CheckBox) findViewById(R.id.isAuto);
TextView tvGetPassword = (TextView) findViewById(R.id.tvGetPassword);
//"找回密码"下划线,为文字添加下划线
tvGetPassword.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);
tvGetPassword.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
Intent intent = new Intent(LoginActivity.this, FindPwdActivity.class);
startActivity(intent);
overridePendingTransition(SwitchActivityAnim.rightIn(), SwitchActivityAnim.rightOut());
}
});
//登录按钮
btn_Login = (Button) findViewById(R.id.login_ok);
btn_Login.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String userId = etUserId.getText().toString().trim();
String password = etPassword.getText().toString().trim();
if (!"".equals(userId) && !"".equals(password)) {
Log.i(TAG, "click login");
UserInfo loginUser = new UserInfo();
loginUser = new UserInfo();
loginUser.setUserId(userId);
loginUser.setPassword(password);
// 调用函数创建新任务
newTask(loginUser);
} else {
if ("".equals(userId)) {
//输入框为空时就抖动
etUserId.startAnimation(shake);
etUserId.setHint("学号不能为空");
etUserId.setHintTextColor(Color.RED);
} else {
etPassword.startAnimation(shake);
etPassword.setHint("密码不能为空");
etPassword.setHintTextColor(Color.RED);
}
}
}
});
//下拉列表显示已登录过的用户
ib_spinner = (ImageButton) findViewById(R.id.ib_spinner);
ib_spinner.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 弹出下拉列表
ListView listView = new ListView(getApplicationContext());
listView.setCacheColorHint(0x00000000);// 滑动时 不变色
listView.setVerticalScrollBarEnabled(false);
listView.setBackgroundColor(getResources().getColor(R.color.white));
//设置透明度
listView.getBackground().setAlpha(230);
listView.setAdapter(new MyAdapter());
pop = new PopupWindow(listView, etUserId.getWidth()+ib_spinner.getWidth(),
LayoutParams.WRAP_CONTENT, true);
// pop隐藏
pop.setBackgroundDrawable(new ColorDrawable(0x00000000));
pop.setOutsideTouchable(true);
pop.setFocusable(true);
// pop.setAnimationStyle(R.style.PopupAnimation);
pop.showAsDropDown(etUserId, 0, -8);
pop.update();
}
});
}
//将耗时的操作封装后交给主服务
private void newTask(UserInfo loginUser) {
if(!MainService.isNetAvailable){
Toast.makeText(LoginActivity.this, "网络不可用!", Toast.LENGTH_LONG).show();
}else {
Map<String, Object> taskParams = new HashMap<String, Object>();
taskParams.put("loginUser", loginUser);
Task task = new Task(Task.USER_LOGIN, taskParams);
//将任务加入主服务线程
MainService.newTask(task);
showDialg();
}
}
/**
主服务处理完任务后,通过引用来调用此函数来达到更新界面的目的
* 更新登录界面,或登录成功后跳转,或显示错误信息
*/
@Override
public void refresh(Object... obj) {
progressDialog.dismiss();
if (null != obj[0]) {
if (obj[0] instanceof Exception) {
Exception exception = (Exception) obj[0];
System.out.println(exception.getMessage());
Toast.makeText(this, "登录失败!", Toast.LENGTH_SHORT).show();
return;
}
UserInfo user = (UserInfo)obj[0];
if (null == user.getUserName() || "".equals(user.getUserName())) { //用户名密码错误
Toast.makeText(this, "登录失败!", Toast.LENGTH_SHORT).show();
Toast.makeText(this, "请核查用户名密码以及网络连接是否可用", Toast.LENGTH_LONG).show();
}else { //登录成功,跳转到主界面
Toast.makeText(LoginActivity.this, "登录成功!", Toast.LENGTH_SHORT).show();
Toast.makeText(LoginActivity.this, "欢迎 "+user.getUserName()+"童鞋", Toast.LENGTH_SHORT).show();
int isRemember = cbIsRemember.isChecked() ? 1 :0 ;
int isAuto = cbIsAuto.isChecked() ? 1 :0 ;
// 跳转
Intent intent = new Intent(LoginActivity.this, HomeActivity.class);
startActivity(intent);
overridePendingTransition(SwitchActivityAnim.fadeIn(), SwitchActivityAnim.bloomOut());
if (1 == isAuto) { //自动登录则存入数据库,且写到配置文件
SharedPreferencesUtil.saveLoginUser(LoginActivity.this, user);
userInfoServices.insertUserInfo(user);
}else if (1 == isRemember) { //记住密码就写入数据库
userInfoServices.insertUserInfo(user);
}
this.finish();
}
}else {
Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_LONG).show();
}
}
private void initData(){
userIDs = new ArrayList<String>();
loginedUsers = userInfoServices.getAllLoginedUser();
String users = "";
if (null != loginedUsers && loginedUsers.size() > 0) {
for (UserInfo user : loginedUsers) {
userIDs.add(user.getUserId());
users += user.getUserId()+"\t 密码:"+user.getPassword()+"\n";
}
System.out.println(users);
}
}
//将已登录的用户列表适配到下拉列表
class MyAdapter extends BaseAdapter {
@Override
public int getCount() {
return userIDs.size();
}
@Override
public Object getItem(int position) {
return userIDs.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
LayoutInflater inflater = LayoutInflater
.from(getApplicationContext());
View view = inflater.inflate(R.layout.item_userids, parent, false);
TextView tv_name = (TextView) view.findViewById(R.id.tv_name);
ImageButton delete = (ImageButton) view.findViewById(R.id.delete);
tv_name.setText(userIDs.get(position));
tv_name.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
etUserId.setText(userIDs.get(position));
etPassword.setText(loginedUsers.get(position).getPassword());
pop.dismiss();
}
});
delete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
userIDs.remove(position);
adapter.notifyDataSetChanged();
}
});
return view;
}
}
private void showDialg() {
if (null == progressDialog ) {
progressDialog = new ProgressDialog(this);
}
progressDialog.setMessage("正在获取信息...");
progressDialog.show();
}
}
通过注释应该能够看清楚。
我是通过这个项目来学Android的,所以这里面没有太多的Android处理技巧,由于工作的原因,只是用以前的代码,并没有优化。当让这样也能让自己看到慢慢成长的过程。
本文出自 “年少的风” 博客,谢绝转载!