最近沒有怎麼編碼,就把斷斷續續做了半年的畢業設計拿出來回顧一下。
校園助手,分爲服務器端與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處理技巧,由於工作的原因,只是用以前的代碼,並沒有優化。當讓這樣也能讓自己看到慢慢成長的過程。