最近没有怎么编码,就把断断续续做了半年的毕业设计拿出来回顾一下。

校园助手,分为服务器端与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处理技巧,由于工作的原因,只是用以前的代码,并没有优化。当让这样也能让自己看到慢慢成长的过程。