【助手APP】簡介及框架

最近沒有怎麼編碼,就把斷斷續續做了半年的畢業設計拿出來回顧一下。

校園助手,分爲服務器端與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處理技巧,由於工作的原因,只是用以前的代碼,並沒有優化。當讓這樣也能讓自己看到慢慢成長的過程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章