顯示具有 效率啊!效率! 標籤的文章。 顯示所有文章
顯示具有 效率啊!效率! 標籤的文章。 顯示所有文章

2020年3月8日 星期日

【不要仰賴Activity的Android開發】什麼事情都用CustomView解決





一般來說,製作一個這樣的介面會使用一組Activity和XML。



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main"> 

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" /> 

 <EditText
android:id="@+id/identify"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minEms="10"
android:maxLines="1"
android:hint="ID" />
<EditText
android:id="@+id/password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minEms="10"
android:maxLines="1"
android:hint="Password" />
<Button
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OK"/>
</LinearLayout>



public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { 
 super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); 

 final EditText id = findViewById(R.id.identify);
final EditText pw = findViewById(R.id.password); findViewById(R.id.login).setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View view) { 

 Log.d("Hsu", "ID:" + id.getEditableText().toString());
 Log.d("Hsu", "PW:" + pw.getEditableText().toString()); 


 }
); 
 } 
}
(因為不需要,所以OnClickListener的內容只有意思性地Log。)


接下來的做法或許會比較麻煩,但概念上來說會提供程式比較多的擴充升級彈性。

因為它完全不受限於Activity,功能和介面可以隨時彈性重組,方便調整或擴充。

首先,整個Activity會變成只剩下這樣.......


public class MainActivity extends AppCompatActivity { 
 @Override 
 protected void onCreate(Bundle savedInstanceState) {             super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main); 

 } 
}

但XML會做出比較大幅度的改變...

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"> 

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" /> 

<com.myapplication.InputText
android:id="@+id/identify"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minEms="10"
android:maxLines="1"
android:hint="ID" /> 

<com.myapplication.InputText
android:id="@+id/password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minEms="10"
android:maxLines="1"
android:hint="Password" /> 

<com.myapplication.LoginButton
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OK"/> 

</LinearLayout>


可以看到EditText和Button從Android標準元件變成APP專案客制的元件。

「com.myapplication」是專案的設定,有興趣的人可以自己彈性的修改命名,只要是「InputText」和「LoginButton」的路徑位置就好。(這兩個View物件的命名也可以自己彈性調整。)

InputText和LoginButton的內容則在下面。

public class InputText extends EditText { 
 public static InputText ID; 
 public static InputText PW; 

 public InputText(Context context, AttributeSet attrs) { 
 super(context, attrs); 
 String hint = getHint().toString();
 switch (hint){ 

 case "ID": ID = this;
 break;
 case "Password": 

 PW = this;
 break;
 } 

 } 
}



public class LoginButton extends Button implements View.OnClickListener { 
 public LoginButton(Context context, AttributeSet attrs) { 
 super(context, attrs);
 setOnClickListener(this);
 } 


 @Override
 public void onClick(View view) { 

 Log.d("Hsu", "ID:" + InputText.ID.getEditableText().toString());
 Log.d("Hsu", "PW:" + InputText.PW.getEditableText().toString()); 

 } 
}


因為這個介面還是算簡單的,所以這樣做的好處可能無法立刻顯現,要引入一些情境做說明。

這樣做的目的在於快速方便的大量產生擁有登入功能的介面。
登入這件事情越來越複雜,會產生各種登入模式,例如多帳號登入、例如彈出視窗登入、例如重新檢查使用者帳號密碼.....
所以快速的設計跟新增登入功能或許有其必要。

InputText可以確保針對登入的輸入功能可以快速重複利用,譬如「將輸入的內容加密」「將使用者帳號自動帶入ID欄」。
而LoginButton可以延生出各種版本,例如CheckPasswordButton可以用來讓使用者再次輸入密碼做保險性登入,等物件設計好後只要修改XML,將LoginButton換成CheckPasswordButton,一樣不需要修改Activity的任何內容,就可以完成新介面新功能。

用這種方式寫程式,為的是可以同時滿足快速組合出功能並達到模組化的目的。


有些人可以從附上的程式碼中快速找到一些功能上的限制,但其實這些限制都可以藉由簡單幾行程式碼擴充來破解,但以後再寫了。

2018年10月30日 星期二

演算法練習「Candidate Report: Anonymous」

解答...


這題是「Stacks and Queues」的第一題練習。

簡單來說就是「後進先出」:用一個矩陣逐一紀錄並疊加收到的資料。

例如:資料1收在矩陣0,資料2收在矩陣1...資料N收在矩陣N-1,但等到要處理資料時,先從資料N、資料N-1...逐一開始往回處理,如果臨時又有資料加入,則繼續疊加程序。


這跟一般來說的「排隊」不同,這是文本或編譯器的基礎。

例如JSON翻譯器,或程式碼編譯時用來辨識「區段」的開始與結束,例如for迴圈或類別檔的內容。

本身反而沒難度,搞懂邏輯程序、確保題目結果正確後,效能並沒有什麼難度。(因為題目本身就是個一維迴圈。)

2018年10月29日 星期一

演算法練習 「GenomicRangeQuery」 (快速計算矩陣內單位總和的方式)

題目和解法...

講義...

一連串長度為X的數值矩陣,如何知道單位M和N之間有不為零的數值?(M>N,且絕對不小於零或大於等於X,所以M和N單位絕對都在矩陣內。)


這其實是個變相計算總和的技巧。
如果把矩陣從頭(最小單位)跑一次迴圈,並且每次都把前一個單位的值和自己做加總,例如「X[A] = X[A] + X[A-1]」,則等到迴圈跑完,這個迴圈的每個單位(i)會變成「從0到i單位的總和」,如果要知道每個單位原本的值,只需要把單位(i)減去單位(i-1)就好。
如果要問「i到j之間單位的數值總和(假設j > i)」,也只需要把單位(j)減去單位(i)就好。



所以如果題目要知道ATCG在基因序列中出現的頻率,那就宣告四個和基因序列等長的矩陣,個別對應到ATCG,每次只要出現相對應的序列,就在那個矩陣單位中加一(X[A]=1)。

如果C[i] = N,而C[i + a] = N+2,這就表示在「i」到「i+a」這中間的單位裡,C出現了兩次。這個C[i] - C[i+a]如果稱為F(C, i, 2),則按照題目的要求,F(A, i, j)不為0時答案為1,F(C, j, j)不為零時答案為1......

2018年7月20日 星期五

【Java】Instanceof 的效能

Interface可以讓「無直接繼承關係」的物件之間共享相同屬性,──簡單來說,介面本身就是種屬性。

判讀這種屬性用的就是「instanceof」這個指令。


舉例:「設置一個介面稱為『Wing』,然後在怪物A的子怪物類別群中找到一隻,假設類別為怪物A2B,然後讓它擴充『Wing』介面。」如此一來,在一系列怪物中就可以跳過在「怪物A」、甚至「怪物A的父類別」中新增參數「Wing」。──雖然不一定會發生,這樣做的好處是「設計上彈性非常高」。

但是相較於判讀介面,判讀物件類別名稱只要十分之一的效能。(而且判讀物件類別名稱所消耗的效能又是直接判讀參數的一到三倍。)但最終物件類別名稱並無法達到我剛才所說的效果。

把所有都擴充了Wing介面的類別都集合在一起判斷,施作上不合理!(但......實際上可以這樣做。)


將所有屬性都集中在一個父類別,然後用子類別來「變化/初始化」這些參數,這在講求效能的情況下還是比較實在。但怎麼設計參數........每多增加一個參數,類別的物件實體在記憶體中占用的量就會增加。

所以一般來說都是使用位元運算子,一個短整數等於8bit,也就等於八個boolean值,直接宣告一個短整數省記憶體?還是宣告八個boolean省記憶體?...以後再測試。

2016年10月17日 星期一

[Codility] Training ticket -- 100%

Score 83
效能不合格....
// you can also use imports, for example:
// import java.util.*;

// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");

class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        
        int l = A.length;
        int l2 = A.length;
        
        for(int i = 0 ; i < l ;i++){
            int tmp = A[i];
            for(int j = i+1 ; j < l ;j++){
                
                if(A[j] == tmp){
                    i++;
                    A[j] += A[i];
                    A[i] = A[j] - A[i];
                    A[j] = A[j] - A[i];
                    l2--;
                }
                
            }
            
            
        }
        
        return l2;
    }
}

https://codility.com/demo/results/trainingYKSGPS-9KJ/


// you can also use imports, for example:
// import java.util.*;

// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");

class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        
        int l = A.length;
        
        for(int i = 1 ; i < l ;i++){
            for(int j = 0 ; j < i ;j++){
                
                if(A[i] == A[j]){
                    A[j] = 1000001;
                }
                if(A[j] == 1000001){
                    A[j] = A[i];
                    A[i] = 1000001;
                    
                    if(j > 0){
                        A[j-1] += A[j];
                        A[j] = A[j-1] - A[j];
                        A[j-1] = A[j-1] - A[j];
                    }
                    
                    
                    j = i;
                }
                
            }
            
        }
        
        for(int i = 0 ; i < l ;i++){
            if(A[i] == 1000001)
                return i;
        }
        
        return l;
        
    }
}

https://codility.com/demo/results/trainingZKNY6F-3GA/
成績沒有改善

// you can also use imports, for example:
// import java.util.*;

// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");

class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        
        int l = A.length;
        int count = 0;
        
        for(int i = 0 ; i < l ; i++){
            if(A[i] != 1000001){
                count++;
                for(int j = i+1; j < l ; j++){
                    if(A[j] == A[i]){
                        A[j] = 1000001;
                        if(j == l-1)
                            l--;
                    }
                }
                A[i] = 1000001;
            }
        }
        
        return count;
    }
}

https://codility.com/demo/results/training2H2FYZ-FT7/
依然沒有改善


// you can also use imports, for example:
// import java.util.*;

// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");

class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        
        int l = A.length;
        int count = 0;
        int[] A2 = new int[2000001];
        
        for(int i = 0 ; i < l ; i++){
            int tmp = A[i] + 1000000;
            if(A2[tmp] == 0)
                count++;
            A2[tmp]++;
        }
        
        return count;
        
        
    }
}
https://codility.com/demo/results/trainingCXSQ2W-JFG/
其實資料長度只有100000,並不算大!
直接計算出現次數就可以輕鬆解決效能問題!並不會造成記憶體不足的問題!
跟青蛙過河有異曲同工之妙!