[Android]第四次作业
?
一、團隊成員
李怡龍 學號:1600802046 博客地址:https://www.cnblogs.com/lee-li/
劉顯云 學號:1600802048 博客地址:https://www.cnblogs.com/lxy-y/
劉志祥 學號:1600802049 博客地址:https://www.cnblogs.com/love-love/
二、APK下載地址
Android:https://github.com/leeli73/Windroid/releases/download/1.0/Windroid.apk
PC:https://github.com/leeli73/Windroid_Server_PC/releases/download/1.0/Windroid_PC.exe
Server:https://github.com/leeli73/Windroid_Server_PC/releases/download/1.0/Windroid_Server.exe
三、項目地址
Android APP:https://github.com/leeli73/Windroid.git
Server PC:https://github.com/leeli73/Windroid_Server_PC.git
四、項目介紹
名稱:Windroid
功能:主要用于共享Windows系統和Android手機的剪切板,用戶不用在通過QQ、微信發信息給PC端,手機復制的信息可以共享給PC,PC復制的信息亦可以共享給手機。
主要構成:Windows端應用程序、Android端程序、Server端程序
4.1?團隊項目的總體效果截圖
Android登錄界面
?
Android設置界面
?
PC登錄界面
?
PC工作界面
PC端當登錄成功后,便會自動隱藏窗口,在后臺運行
Server工作界面
?
4.2 實現的功能及其效果的描述
登錄
當用戶輸入用戶名密碼后,點擊登錄,驗證通過后即可進入設置頁面
點擊注冊后,即可進行注冊
設置信息(目前測試有BUG、在某些情況下會閃退,比如快速上下滑動)
在點擊允許修改的表項后,就會彈出下面的輸入框
輸入完成后,點擊確定即可更新數據
?
五、項目中的關鍵代碼
HTTP請求
使用OkHttp3庫進行請求,主要用于登錄、注冊、數據交換
String url = "http://192.168.0.102:6888/SetData";final OkHttpClient okHttpClient=new OkHttpClient();RequestBody body = new FormBody.Builder().add("UserID", Base64.encodeToString(StrUserID.getBytes(), Base64.DEFAULT)).add("Data",Base64.encodeToString(Data.getBytes(),Base64.DEFAULT)).build();final Request request=new Request.Builder().url(url).post(body).build();new Thread(new Runnable() {@Overridepublic void run() {try {Response response=okHttpClient.newCall(request).execute();if (response.isSuccessful()){String body=response.body().string();Log.i("test",body);}} catch (IOException e) {e.printStackTrace();}}}).start();?
listview生成
每行都有一個指定的view與其對應,方便修改數據等操作
AllInfo = findViewById(R.id.AllInfo);adapter = new BaseAdapter() {@Overridepublic int getCount() {return 13;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {LinearLayout linearLayout = new LinearLayout(body.this);TextView tital = new TextView(body.this);linearLayout.setOrientation(LinearLayout.VERTICAL);tital.setTextSize(25);switch (position){case 0:tital.setText("用戶信息");tital.setGravity(LinearLayout.TEXT_ALIGNMENT_CENTER);tital.setTextSize(30);linearLayout.addView(tital);break;case 1:tital.setText("用戶名ID");linearLayout.addView(tital);linearLayout.addView(UserID);break;case 2:tital.setText("用戶名");linearLayout.addView(tital);linearLayout.addView(UserName);break;case 3:tital.setText("電子郵箱");linearLayout.addView(tital);linearLayout.addView(Email);break;case 4:tital.setText("密碼");linearLayout.addView(tital);linearLayout.addView(PassWord);break;case 5:tital.setText("設置");tital.setGravity(LinearLayout.TEXT_ALIGNMENT_CENTER);tital.setTextSize(30);linearLayout.addView(tital);break;case 6:tital.setText("最大數據長度/K");linearLayout.addView(tital);linearLayout.addView(MaxDataLength);break;case 7:tital.setText("遠程存儲時間/s(<3600s)");linearLayout.addView(tital);linearLayout.addView(RomoteDataSaveDate);break;case 8:tital.setText("本地存儲時間/s(<3600s)");linearLayout.addView(tital);linearLayout.addView(LocalDataSaveTime);break;case 9:tital.setText("局域網連接");tital.setGravity(LinearLayout.TEXT_ALIGNMENT_CENTER);tital.setTextSize(30);linearLayout.addView(tital);break;case 10:tital.setText("自動掃描");linearLayout.addView(tital);linearLayout.addView(LANAutoScan);break;case 11:tital.setText("局域網IP");linearLayout.addView(tital);linearLayout.addView(LANIP);break;case 12:tital.setText("端口");linearLayout.addView(tital);linearLayout.addView(LANPort);break;}return linearLayout;}};AllInfo.setAdapter(adapter);?
初始化數據
將asset目錄下的配置讀取并處理
try{InputStreamReader inputStreamReader = new InputStreamReader(getResources().getAssets().open("UserInfo.data"));BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String line="";while((line=bufferedReader.readLine())!=null){String Temp[] = line.split(":");if(Temp[0].equals("Username")){StrUserName = new String(Temp[1]);}else if(Temp[0].equals("Password")){StrPassWord = new String(Temp[1]);}}}catch (Exception e){e.printStackTrace();}try{InputStreamReader inputStreamReader = new InputStreamReader(getResources().getAssets().open("Setting.data"));BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String line="";while((line=bufferedReader.readLine())!=null){String Temp[] = line.split(":");if(Temp[0].equals("MaxDataLength")){StrMaxDataLength = new String(Temp[1]);}else if(Temp[0].equals("LocalDataSaveTime")){StrLocalDataSaveTime = new String(Temp[1]);}else if(Temp[0].equals("RemoteDataSaveTime")){StrRomoteDataSaveDate = new String(Temp[1]);}else if(Temp[0].equals("UserID")){StrUserID = new String(Temp[1]);}else if(Temp[0].equals("Email")){StrEmail = new String(Temp[1]);}else if(Temp[0].equals("LANIP")){StrLANIP = new String(Temp[1]);}else if(Temp[0].equals("LANPort")){StrLANPort = new String(Temp[1]);}else if(Temp[0].equals("LANAutoScan")){StrLANAutoScan = new String(Temp[1]);}}}catch (Exception e){e.printStackTrace();}?
listview點擊彈出提示
根據點擊位置讀取輸入和判斷是否允許修改
AllInfo.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, final int position, long id) {final EditText MyInput = new EditText(body.this);AlertDialog.Builder builder = new AlertDialog.Builder(body.this);builder.setTitle("請輸入信息").setIcon(android.R.drawable.ic_dialog_alert).setView(MyInput).setNegativeButton("取消",null);builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {switch (position){case 0://用戶信息break;case 1://用戶名IDToast.makeText(body.this,"用戶ID不允許修改",Toast.LENGTH_SHORT).show();break;case 2://用戶名Toast.makeText(body.this,"用戶名不允許修改",Toast.LENGTH_SHORT).show();break;case 3://電子郵箱StrEmail = MyInput.getText().toString();Email.setText(StrEmail);Toast.makeText(body.this,"修改成功",Toast.LENGTH_SHORT).show();break;case 4://密碼StrPassWord = MyInput.getText().toString();PassWord.setText(StrPassWord);Toast.makeText(body.this,"修改成功",Toast.LENGTH_SHORT).show();break;case 5://設置break;case 6://最大數據長度StrMaxDataLength = MyInput.getText().toString();MaxDataLength.setText(StrMaxDataLength);Toast.makeText(body.this,"修改成功",Toast.LENGTH_SHORT).show();break;case 7://遠程存儲時間/s(<3600s)StrRomoteDataSaveDate = MyInput.getText().toString();RomoteDataSaveDate.setText(StrRomoteDataSaveDate);Toast.makeText(body.this,"修改成功",Toast.LENGTH_SHORT).show();break;case 8://本地存儲時間/s(<3600s)StrLocalDataSaveTime = MyInput.getText().toString();LocalDataSaveTime.setText(StrLocalDataSaveTime);Toast.makeText(body.this,"修改成功",Toast.LENGTH_SHORT).show();break;case 9://局域網連接break;case 10://自動掃描StrLANAutoScan = MyInput.getText().toString();LANAutoScan.setText(StrLANAutoScan);Toast.makeText(body.this,"修改成功",Toast.LENGTH_SHORT).show();break;case 11://局域網IPStrLANIP = MyInput.getText().toString();LANIP.setText(StrLANIP);Toast.makeText(body.this,"修改成功",Toast.LENGTH_SHORT).show();break;case 12://端口StrLANPort = MyInput.getText().toString();LANPort.setText(StrLANPort);Toast.makeText(body.this,"修改成功",Toast.LENGTH_SHORT).show();break;}}});builder.show();}});?
本地剪切板監控線程(存在問題,完全按照官方API編寫的讀寫剪切板,但是會閃退,API11之前和之后的方法全部嘗試,依舊無法解決)
啟動一個線程,循環監控本地剪切板
new Thread(new Runnable() {@Overridepublic void run() {try{while (true){String url = "http://192.168.0.102:6888/GetData";final OkHttpClient okHttpClient=new OkHttpClient();RequestBody body = new FormBody.Builder().add("UserID", Base64.encodeToString(StrUserID.getBytes(), Base64.DEFAULT)).build();final Request request=new Request.Builder().url(url).post(body).build();new Thread(new Runnable() {@Overridepublic void run() {try {Response response=okHttpClient.newCall(request).execute();if (response.isSuccessful()){String body=response.body().string();String Temp[] = body.split("@");if(Temp[0].equals("New")){/*//獲取剪貼板管理器:ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);// 創建普通字符型ClipDataClipData mClipData = ClipData.newPlainText("Label", Temp[1]);// 將ClipData內容放到系統剪貼板里。cm.setPrimaryClip(mClipData);*/Log.i("test","Get New Data "+ Temp[1]);}else{Log.i("test","No New Data");}}else{Log.i("test","No New Data");}} catch (IOException e) {e.printStackTrace();}}}).start();Thread.sleep(1000);}}catch (Exception e){e.printStackTrace();}}}).start();?
遠程服務器獲取數據線程(存在問題,完全按照官方API編寫的讀寫剪切板,但是會閃退,API11之前和之后的方法全部嘗試,依舊無法解決)
啟動一個線程,循環監控遠程剪切板
new Thread(new Runnable() {@Overridepublic void run() {try {String OldData = "";while (true){Log.i("test","Set");//ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);//String Data = cm.getText().toString().trim();//Log.i("test",Data);String Data = "123";if(!Data.equals(OldData)){String url = "http://192.168.0.102:6888/SetData";final OkHttpClient okHttpClient=new OkHttpClient();RequestBody body = new FormBody.Builder().add("UserID", Base64.encodeToString(StrUserID.getBytes(), Base64.DEFAULT)).add("Data",Base64.encodeToString(Data.getBytes(),Base64.DEFAULT)).build();final Request request=new Request.Builder().url(url).post(body).build();new Thread(new Runnable() {@Overridepublic void run() {try {Response response=okHttpClient.newCall(request).execute();if (response.isSuccessful()){String body=response.body().string();Log.i("test",body);}} catch (IOException e) {e.printStackTrace();}}}).start();}Thread.sleep(1000);}}catch (Exception e){e.printStackTrace();}}}).start();更換返回鍵的功能為回到桌面
Intent intent = new Intent();intent.setAction(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_HOME);startActivity(intent);Toast.makeText(body.this,"Windroid進入后臺運行",Toast.LENGTH_SHORT).show();?
六、心目中的前五名
1、季澈組?https://www.cnblogs.com/qingzhujushi/p/10200806.html
類似網易云音樂界面美觀優雅的音樂播放器
項目優點:自動搜集本地音樂,有上一曲,下一曲,開始暫停,順序播放,隨機播放,單首播放,音量的控制,進度條,歌詞,可以刪除歌曲
項目缺點:無法加載云端的音樂,不能說是一個完美的音樂播放器。沒有用戶機制,無法保存自己的歌曲列表。
我的設想:支持播放云端的音樂,爬蟲現有幾個音樂播放器的資源。加入用戶機制。
2、賀鴻琨組?https://www.cnblogs.com/hehongkun/p/10202262.html
類似QQ音樂界面,選擇圖片資源很優秀
項目優點:完成了歌曲列表與播放界面之間的切換,完成了播放過程中圖片旋轉狀態與歌曲播放狀態的綁定,還完成了歌曲進度條與歌曲進度的綁定。
項目缺點:無法加載云端的音樂,沒有用戶機制
我的設想:支持播放云端的音樂,爬蟲現有幾個音樂播放器的資源
3、李凌龍組?https://www.cnblogs.com/Trip1eL/p/10190488.html
對于我這樣愛忘事者,這是一個剛需,簡單使用
項目優點:功能齊全,界面簡單
項目缺點:沒有批量刪除功能
我的設想:支持語音助手,一句話就能設定好
4、田光欣組?https://www.cnblogs.com/tiangxin/p/10206469.html
簡單使用,沒有花里胡哨功能的記事本
項目優點:界面簡單,功能齊全
項目缺點:數據存儲在本地,更換手機后無法使用
我的設想:支持語音助手,一句話記下文本,支持圖片、音頻、視頻的記錄。將數據加密存儲在服務器上。
5、李釗組?https://www.cnblogs.com/18LZblog/p/10205321.html
功能齊全的乒乓球社區,乒乓球愛好者的必備
項目優點:功能齊全,無論是視頻、排名、照片等都能一次性了解到
項目缺點:無法聯網實時獲取最新的數據
我的設想:APP自動去互聯網上爬去最新的信息,向用戶展示最新的數據
七、遇到的問題及解決方案
7.1 讀寫剪切板(任然未解決)
李怡龍 1600802046
使用最新的API,程序運行至此處會閃退
//獲取剪貼板管理器:ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);// 創建普通字符型ClipDataClipData mClipData = ClipData.newPlainText("Label", Temp[1]);// 將ClipData內容放到系統剪貼板里。cm.setPrimaryClip(mClipData);換用老版API,程序依舊閃退
cm.setText()?
7.2 亂碼問題
李怡龍 1600802046
我們發現在傳輸中文的過程中,會出現亂碼的問題,因為我們采用POST的形式,傳輸數據,如果有&等符號也會出現問題
所以我們決定對所有通訊過程中的數據進行BASE64編碼
Android端
RequestBody body = new FormBody.Builder().add("UserID", Base64.encodeToString(StrUserID.getBytes(), Base64.DEFAULT)).build();PC端
Base64 base64;Username = base64.encode(Username.toLatin1());Password = base64.encode(Password.toLatin1());Server端
RealUsernameBase64,err := base64.StdEncoding.DecodeString(Username[0])if err != nil{w.Write([]byte("error"))return }RealPasswordBase64,err := base64.StdEncoding.DecodeString(Password[0])if err != nil{w.Write([]byte("error"))return }RealUsername := string(RealUsernameBase64)RealPassword := string(RealPasswordBase64)7.3 讀取本地Asset目錄下的配置文件
李怡龍 1600802046
因為我們存儲的數據相對較少,而且不敏感,所以采用文本的形式存儲
起初我們準備使用JSON的形式存儲,但是在解析的JSON的過程中有部分問題,最后換用自定義格式的文本
InputStreamReader inputStreamReader = new InputStreamReader(getResources().getAssets().open("UserInfo.data"));BufferedReader bufferedReader = new BufferedReader(inputStreamReader);String line="";while((line=bufferedReader.readLine())!=null){}7.4 Server中Redis的使用
李怡龍 1600802046
因為我們的數據存在一定的時效性,而且要求訪問必須做到低延時,所以我們決定使用Redis 內存K-V型數據庫
在查閱文檔后,我們采用了"github.com/garyburd/redigo/redis"包進行redis的各類操作
并建立兩張哈希表
第一張為用戶信息表
key:Username value:UserID Password Email PhoneNumber SaveTime _, err := RedisClient.Do("HMSET",Username,"UserID",UserID,"UserPassword",Password,"Email",Email,"PhoneNumber",PhoneNumber,"SaveTime",SaveTime)if err != nil {fmt.Println("redis hset error:", err)return false} else {//_,err := RedisClient.Do("expire","myKey","10")return true}?
第二張為數據表
key :UserID value:Data
_,err1 := RedisClient.Do("HMSET",RealUserID,"Data",RealData)if err1 != nil {fmt.Println("redis hset error:", err)w.Write([]byte("SetError"))} else {//_,err := RedisClient.Do("expire","myKey","10")w.Write([]byte("SetSuccess"))}7.5 因為技術上的問題,我們最早想要實現的局域網自動掃描沒有編寫出來,所以現在所有的功能必須經由服務器
?
八、分工
姓名? ? ? 分工? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?工作比例? ? ? 分數
李怡龍? 服務器、PC端、安卓端POST、剪切板操作? ? 50%? ? ? ? ? ? ?5
劉顯云? 安卓端登錄UI設計、數據讀取、存儲? ? ? ? ? ? ? ?25%? ? ? ? ? ? ?2.5
劉志祥? 安卓端listview設計及響應? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 25%? ? ? ? ? ? ?2.5
九、運行演示
啟動Server及PC(Server實際運行于服務器,這里只是用于演示)
Server工作中交換數據的輸出(實際工作中不輸出,這里只用于演示效果)
Windroid安卓端
不知什么原因,登錄界面的動畫在模擬器中無法顯示,所以這里在小米MIX(Android8.0)環境下演示
演示途中的黑屏,是應為調起小米安全鍵盤時,MIUI系統不允許錄制該部分,所以自動進行了遮擋
博客園限制無法上傳20M以上的圖片,所以這里圖片存于公共圖床,可能加載相對較慢時點擊這個鏈接前往騰訊云對象存儲下載(流量賊啦貴,不到萬不得已不要下)
轉載于:https://www.cnblogs.com/lee-li/p/10205512.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的[Android]第四次作业的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js:自动亮起100盏灯
- 下一篇: CentOS7.5下时间戳转换为时间