顯示具有 舉一不反三 標籤的文章。 顯示所有文章
顯示具有 舉一不反三 標籤的文章。 顯示所有文章

2017年12月16日 星期六

【AWS & RDB & EC2】讓已經存在的EC2上的專案存取新建立的RDB instance

這實在是很矛盾的一件事,但RDS DB可以讓外界(非AWS的環境)存取,可是自己內部的EC2要連線卻需要設定層層關卡。

(據說,這是安全需要。其實RDS DB都有對外部連線設下層層保護,並不是單純的只靠帳號密碼和Endpoint而已。反而是內部的雲端伺服器群可能會有安全疑慮,所以反而要層層把關。)



如果沒有特別選擇,其實AWS會自動把使用者建立一組default的VPC。(不知道什麼是VPC的人就比較尷尬,因為我不知道怎麼精準正確的解釋。就先假設它是種為了使用者設計的「沙箱式」的防火牆,在這牆內的任何AWS雲端虛擬主機都可以視為在同一個子網域中。──解釋的很爛。)

官方標準Guide文件「Create VPL Connect RDS DB」並沒有提到這點,就好像它們也不會說「虛擬機建好以後不能修改VPC」。──VPC的內容可以隨意修改,Instance的各項設定也可以隨意修改,唯獨一旦指定VPC,除非Instance整個刪除否則這項設定不會再更動。


所以某些情況下,建立了一組EC2虛擬主機後也在上面安裝了資料庫的人,可能會想要改用AWS RDS DB服務,這時可能就會碰到不知從何下手的困擾。

幸運的是:建立EC2時即使沒有新建VPC,系統也會幫忙設定一組VPC,而且這組VPC內的設定一應俱全。有Subnet、也有SecurityGroup。而且在新建RDS DB Instance時也可以選用這組PVC。

所以如果想要讓EC2可以存取使用RDS DB,只要找到這組VPC即可。

(這組VPC的名稱也可以修改,修改後就可以快速找到相對的Subnet和SecurityGroup,然後進行修改。)

(修改的原則跟新建時的原則並沒有太多不同。所以可以參考剩下的官方文件、將剩餘步驟改成「修改現有EC2 Instance」和「新建RDS DB並使用現有VPC」即可。)

2015年12月7日 星期一

檢查參數內容是否是同一個物件實體?

假設物件A內有兩個參數,分別是字串B和長整數C。

物件A生成兩個實體參數,分別是實體一和實體二......

可以將實體一和實體二的B和C都設為同樣的數值內容,但如果用if(實體一 == 實體二)來檢查結果...

在Java中一定會得到false。

除非逐一針對B和C參數比對,不然永遠都會是false,──但這不是重點!



只要善用這個特性,可以輕鬆地完成「資料是否有更新」的比對。



最近碰到一個功能,(我保留了細節,只講大概,)要在Activity A中用網路去查詢資料,查詢完後將資料在Activity B鐘用列表(ListView)顯示,並且用彈出式視窗告知使用者「現在有幾筆資料」,然後在Activity C中可以看各筆資料的詳細內容.......並且重新設定查詢條件後再次查詢、查詢完後退回「上一頁(也就是Activity B)」。


用彈出式視窗告知使用者「現在有幾筆資料」是後來追加的功能,所以我設計的簡單,就是在Activity B的onResume中把列表的資料數顯示出來就是...

但問題是在Activity C中,使用者大部分只是單純的看完細節就退回Activity B,並不會重新設定查詢。

所以「判斷是否有重新設定查詢」仍是有必要的一件事。



方法很簡單。

資料要能跨三個Activity間傳遞並操作,方法就是使用一個static型態的ArrayList參數。

(在同一個APP中只要這樣做即可,Intent是很多餘的東西。)

每次只要有「查詢」,就會將這個static ArrayList參數重新產生一個實體。

然後在Activity B中設置一個物件類別專屬的ArrayList參數三,並在onResume中做if(實體一 == 實體二)的檢查,就可以快速精準地知道「使用者是否重新使用過查詢功能」。

(怕有人不知道:通常,將static ArrayList設為實體一,可以省去檢查實體二是否為null的動作。)



但如果ListView的Adapter直接使用參數三,這個方法「可能」會導致APP當機。

怕有人不知道......

安全的程序應該是再產生ArrayList參數四,然後用addAll()的方式將參數三內的資料全部倒進參數四中,然後再使用參數四來產生ListView的Adapter。

(資料量不要太誇張...一般來說這個動作是不吃什麼效能的。如果資料量很誇張,擔心記憶體,不要擔心效能。)

2014年6月28日 星期六

三張圖,讓人看懂Java Socket真正的用法

Socket的結構、特性......不難查到相關資料跟說明,例如怎樣設定它的Port、怎樣跟特定IP建立聯結、怎樣檢查連線是否成功........

但是實際上會用Socket建立TCP/IP或UDP連線的人很少,要做網路功能,URL和J2EE幾乎把這塊領域吃光光........

怎麼回事?



因為Oracle官方的教學文件本身就是塊爛帳!

要看清楚這塊爛帳,除非老師上課有講清楚、教學文寫者有意識到,不然讀的人最後都會撞死在「為什麼連線建好了卻不能用」、「為什麼連線的效率差到根本無法運作」、「為什麼最後會徹底失去建立Socket和Stream的能力」......上。

把「網際網路通訊原理」丟一邊,Java設計師/工程師其實需要理解到的本來就只有「這樣就可以跟遠端裝置進行通訊」這個概念就好,(而且這不正是「Socket的精神」嗎?)但是Oracle的官方範例僅止於「一條龍式的示範可以丟入怎樣的參數來建立Socekt,建立之後可以優先使用哪些參數或得哪些回傳物件........」但是對於真正重要的Stream使用就幾乎支字未提。

而且我可以保證同樣都是Stream,在網路跟單純的檔案管理上頭,這兩種Sream的使用與操作經驗完全不同。(我現在會這樣說,十年後還是這樣說。「這是一樣的東西啊!」那完全是老鳥的嘴砲與傲慢。)

不管是Oracle,或是網路上、課堂上無數的範例與教學,根本沒想過要讓人搞懂「Java怎麼建立連線環境」的全貌,都是不停丟出片段的知識而已。

(不知道多少初入門的Java設計師死在這上頭,最後只能一把鼻涕一把眼淚的強迫自己接受J2EE的強暴、放棄自己滿腦子本來可以用J2SE實現的應用與設計。真是殺死人的絕境、與欲哭無淚的哀愁啊!)



第一步,建立Socket。
不管是用直接指定IP的方式,或用ServerSocket。
總之,想去「取得」一個Socket。 


 從第一步中獲得的Socket產生兩個InputStream和OutputStream。
可能是Thread中產生兩個全域變數Stream;
或是直接產生兩個Thread裡面帶有Stream變數。

將兩個Stream丟給不同的Thread(不是負責生成Socket的同一個Thread),來進行資料的讀寫操作。

這裡頭牽涉到一些細節,例如負責生成Socket的Thread要怎麼管理已經生成的Socket?

提示:絕對不是馬上關掉它。Stream一樣也不用馬上關閉,除非在測試中發現機器沒辦法同時負荷那麼多Stream(原理...待查中...)否則Stream做好,除非要結束連線......建議:就放著吧。(不然連線的效能拉不起來。)



為何要獨立一個Thread來管理Socket生成?

當機器要能夠具備跟多個對象溝通的能力時,Socket絕對不會只有一組,可能最後要建立多組,特別是使用ServerSocket時,但問題是ServerSocket的avaliable()指令會霸佔住整個Thread,所以對於已經建立好的Socket,如果要保有繼續操作它們的能力,就要用另外獨立的Thread來操作,另外Socket要有建立流程、自然也要有關閉流程,一個Thread中怎麼同時管理多組Socket、操作多組InputStream/OutputStream?(神人會說「有何難?不就幾百行程式碼而已!」........想當那種神人,我就不會開這個部落格、寫這些文章分享這些經驗了。)

領悟力好的人會理解這點,根本不需要我這三張圖,.......但問題是領悟力好的人有多少呢?況且說這些人領悟力好...這些人又有多少有能力自己從底層去寫自己的Socket物件來管理網路連線?........還不提我看到一家規模中上等級的公司開出「Java工程師,懂Socket使用,會管理TCP/IP連線......」的徵人啟事,薪水45K(起跳),結果過了一個月還沒人應徵.......

2014年6月26日 星期四

Android的背景Service連續啟動、或前景Activity連續啟動,對程式中的Thread(或其他東西)造成的影響

[2017/8/24]

現在發現其實Android有些更簡單的機制可以處理這種狀況...

ActivityLifecycleCallBacks...這東西的使用機制比較複雜。

或是LifecycleObserver...但這東西我沒實用過,我習慣使用LifecycleCallbacks



 [2017/8/24 !!]
==========================================================

寫一個Activity或Service,然後在onCreate()中加入Log訊息,會發現當「程式/APP」大到某個程度時,會經常(其實是變成例行公事)一個Activity或Service連續開啟(執行「onCreate()」)兩次。

雖然第一次開啟的Activity/Service最後都會關掉(都會立刻轉到「onDestroy()」),但是程式整體結構會變得很難掌控。

開啟不是開啟,關閉不是關閉,如果有別的程序──例如等一下會講到的執行緒──要去判斷/讀取這些Activity/Service內的參數時,可能就糗了......

再講明白一點:Thread啟動、將Activity/Service當作傳入引數要求Thread判斷裡頭的參數......結果不到一秒鐘的時間,Activity/Service已經被關閉,但Thread才剛完成「生成」和「啟動」而已,結果進入執行緒的任務中要開始工作時要去判讀Activity/Service的參數......當機!



有些人會認為應該要在執行緒中加入極為精密、精準的判斷邏輯,避免掉這樣的錯誤發生,「這才是程式設計。」

我不否認「程式設計本來就是門苦工」,產品使用者不曉得在智慧型手機上按一下螢幕、或在電腦上點一下滑鼠,這個「按」與「點」,本身就包含了無數行程式碼。(像寫這個的工程師們致敬。)

但這不代表我們應該只認可「苦工」,而放棄、或否定尋找其它秘訣的機會。

(而且:最苦工的方法想也知道會讓Thread效率變差。)


其實解決方法很簡單,(這部落格講的是Java/Android,所以這些經驗主要應用在Java上,)基本上已經摸過一定程度的Java工程師都知道在Thread中的迴圈要用一個外面可以控制的參數A來決定Thread是否要繼續執行。

這個參數A可能是個Boolean值,程式進入onCreate,則Boolean轉為True,程式執行onClose,則Boolean轉為False。

但僅僅是這樣還不夠解決問題。(像如果用Activity或Service本身的物件是否還存在、是否為Null來做判斷.......抱歉!沒成功過。)

可是真的要解決問題也非常簡單......

Thread有run()函數,這個函數內的程式碼可以被無限執行、並同時排程。

在run()的最開頭,只要用排程的方式先讓它「休息0.5秒」,等到「休息0.5」秒結束後,真正要值行任務內容時,參數A已經變成了False,這個Thread自然也會跳入關閉狀態、然後乖乖等著被回收,不會干染下一個Activity/Service啟動並產生真正穩定的Thread。



應該不會有人會問「0.5秒太短了,不管用,該怎麼辦?」........



================================================

這篇文講的東西很碎,但我以為Java本來就是這樣的東西。它的學習門檻很低,應用門檻也很低,要用它的人、可以用它的地方其實都很多。

但是它的門檻低,後面卻有一階比一階高的樓梯,沒有多種其他層面知識的人跳進來學Java,其實很快就會遭遇障礙。

把程式設計的基礎,例如迴圈和判斷式的使用、物件的設計等很基本的東西講的淺白易懂,然後接下來馬上轉為「基礎教完了,要開始把你們當成專業級的對待,」然後下一個教程、範例、或項目(隨便怎麼稱呼),馬上開始用「我只講這麼多,剩下的要自己理解自己推敲」的態度........所以Java程式設計師能夠活過「初階」的很少,特別是這種語言標榜著所有人都能學。

孔子講「舉一隅不以三隅反者,吾未往也。」這是舉一反三的典故。

聽起來很了不起、很霸氣,但如果今天的「教學」都用這種態度,那小學生學會九九乘法表的一到三之後,豈不是要自己歸納出剩下的四五六七八九的訣竅?

整體的知識水平要提升、科技要進步......這種態度(期望丟出去的教學能夠有最大話的回收)就有嚴重的問題。

所以我開這個部落格、分享這些很碎很碎的技巧。

除了因為還是會有人需要用到,也是為了讓那些沒辦法第一步就達到舉一反三的人可以達到有能力舉一反三。