跳轉到內容

Android/Android 應用程式

來自華夏公益教科書

Android 應用程式的結構

[編輯 | 編輯原始碼]

Android 應用程式(通常縮寫為應用程式)駐留在副檔名為.apk的檔案中。這是傳統上用於 Java 應用程式的.jar檔案格式的擴充套件。此檔案的內容包括

  • AndroidManifest.xml- 應用程式清單,它告訴 Android 系統有關應用程式元件的資訊,它將在哪些 Android 版本上執行,以及它需要的哪些硬體功能和許可權。特別是,許可權會在使用者從 Google Play 商店安裝應用程式時顯示給使用者,因此他們可以選擇接受或拒絕您的應用程式。如果某個特定的 Android 系統服務受許可權控制,而您的清單中沒有列出該許可權,那麼您的應用程式將被阻止訪問該服務。
  • 編譯的 Java 位元組碼。但是,它沒有使用 Sun 的JVM.class格式,而是使用Dalvikclasses.dex格式。
  • (可選)本地機器程式碼。由於這必須是特定於體系結構的,因此 APK 格式允許提供此程式碼的替代版本,位於名為armeabi, mips等的子目錄下。
  • 應用程式資源。這可能包括屏幕布局、文字字串(允許針對不同語言/區域進行本地化)、圖示、顏色規格、樣式定義以及其他各種內容,大多數以 XML 格式提供。這些內容大多數可以在執行時直接在程式碼中建立,但將它們儲存在靜態形式中通常可以更輕鬆地管理。特別是,它允許 Android 系統自動從替代資源中進行選擇,而無需在程式碼中包含特殊情況。

應用程式和活動的區別

[編輯 | 編輯原始碼]

使用者在應用程式托盤中看到的圖示不是對應於應用程式或.apk檔案本身,而是對應於活動。基本上,活動是使用者互動的單個螢幕。如果活動在清單中被標記為已匯出,那麼啟動器將能夠向用戶顯示該活動的圖示,使用者可以點選該圖示來啟動該活動。應用程式可能包含其他未匯出的活動,這些活動僅在內部啟動,可能是(直接或間接地)響應使用者在已匯出活動中的操作。如果應用程式具有多個已匯出的活動,那麼啟動器中將顯示相應的多個圖示。

ELF 可執行檔案

[編輯 | 編輯原始碼]

Android 基於 Linux 核心構建,可以執行常見的 Linux 格式的可執行檔案。但是,您會注意到,APK 格式沒有規定安裝此類檔案的條款,並且此類可執行檔案無法輕鬆訪問常見的 Android 類庫。每個 Android 系統都包含一些標準可執行檔案,包括工具箱,這是一個非常基本的命令列 shell。您可以在連線到 PC 的 SDK 上使用“adb shell”命令訪問它。還可以實現執行在 Android 裝置本身的終端視窗;有關如何執行此操作的示例,請參閱ConnectBot的原始碼。

安全模型

[編輯 | 編輯原始碼]

APK 檔案必須由開發者進行數字簽名才能安裝到 Android 裝置上。您無需在 Google 或任何其他人那裡正式註冊您的簽名金鑰:簽名金鑰只是允許裝置判斷兩個不同的 APK 檔案是否來自同一個開發者。

安裝到裝置後,應用程式將被分配自己的(動態生成的)Linux 使用者 ID。這使系統能夠防止應用程式訪問彼此的資料,除非以經過仔細授權的方式進行訪問。

程序概念

[編輯 | 編輯原始碼]

基於 Linux 核心,Android 支援標準的 POSIX 風格的程序和執行緒。但是,使用者通常不會從這些概念的角度看待應用程式;相反,Android UI 使用任務和活動來工作。

通常,應用程式定義的所有活動都執行在單個程序中,而不同的應用程式執行在不同的程序中。但是,程式設計師可以透過多種方式控制這一點,例如指定launchModetaskAffinity用於活動。此外,應用程式 process 屬性允許兩個相互信任的應用程式(由相同的私鑰簽名)在程式設計師需要時執行在同一個程序中。

請注意,在 Android 文件中,當說活動在後臺“停止”時,這隻意味著它的onStop方法已被呼叫,並且其 UI 不再被認為是活動的。與該活動相關的任何程序和執行緒都會繼續正常執行,並且可以繼續執行任何他們喜歡的操作,當然,唯一推薦的 UI 相關操作是傳送通知,表明他們想要一些使用者關注。

當然,此類後臺程序/執行緒在系統資源不足時被殺死的優先順序佇列中處於較高位置。

UI(主)執行緒

[編輯 | 編輯原始碼]

請注意,您的應用程式程序最初只使用一個執行緒啟動。特別是,所有 UI 呼叫都必須在此執行緒上發生。除了相關的 Handler 方法Activity.runonUiThread之外,Android UI 類(檢視、視窗小部件等)不是執行緒安全的,並且不能在任何其他執行緒上呼叫。您可以自由地建立額外的程序和執行緒;管理需要與 UI 協調的後臺活動的最佳方法(顯示進度更新、處理取消時的清理等)是使用AsyncTask

UI 執行緒執行一個 Looper,您也可以例項化它在自己的執行緒上執行。如果 UI Looper 在使用者事件發生後的 5 秒內沒有獲得一些 CPU 時間,您會看到令人恐懼的“應用程式無響應”(ANR) 警報。

如果您需要執行不會長時間佔用 UI 執行緒的短任務,可以透過 Handlers 將它們排隊到 Looper(請參閱postpostAtTime方法)。更耗時的操作,無法拆分成短時任務,應該委託給後臺執行緒。

熟悉其他平臺 Java 的程式設計師可能習慣於使用 TimerTask 來排程定時事件,但這些事件在自己的執行緒上執行,因此它們安全用於直接進行 UI 呼叫。但是,您可以從後臺執行緒呼叫 Activity.runonUiThread

任務和後退棧

[編輯 | 編輯原始碼]

任務 是透過點選啟動器中的圖示啟動的任何內容。啟動器的應用程式托盤會自動填充所有已安裝應用程式的適當條目(即主活動),這些條目可以複製到主螢幕。也可以在主螢幕上新增快捷方式。通常,任務在新的程序中啟動,如果此類程序已經在執行,則點選圖示只會將現有程序帶到最前面。但是,可以更改這兩種行為。

任務中的第一個(根)活動可以根據需要啟動其他活動。實際上,除了最簡單的應用程式之外,您編寫的任何應用程式可能都包含多個活動。任務還可以啟動其他完全獨立的任務,區別在於這些任務在最近的任務列表中顯示為單獨的條目,而應用程式內部活動則不會。隨著每個新活動的啟動,它將成為對使用者可見的最頂層的活動,而先前最頂層的活動將停用其 UI。這些附加活動通常在啟動它們的程序中執行,但同樣,這種行為可以改變。

按下標準 Android 後退鍵通常會終止最頂層的活動,並將先前最頂層的活動啟用。終止任務的根活動將終止該任務並返回使用者到之前執行的任何任務(可能是啟動器)。

只要活動在執行,任務內的活動永遠不會重新排序;將不在任務後退棧頂部的活動帶到頂部,唯一的方法是終止該任務中所有位於它上方的活動。但是,任務可以重新排序,因為最近啟動的八個任務中的任何一個都可以隨時透過按 Home 鍵並點擊出現的條目之一來帶到最前面。

活動是透過 Context(包括您自己的活動)的子類的某些變體呼叫啟動的。startActivity這些呼叫中的主要引數是意圖

記憶體使用

[編輯 | 編輯原始碼]

在未經 root 的 Android 裝置上,Java 程式碼在記憶體使用量方面受到嚴格限制。Java 物件的堆大小限制為大約 20 MB,而 Bitmap 物件的堆大小限制為類似的大小。哦,與該頁面上關於recycle方法是“高階呼叫,通常不需要呼叫”的說法相反,我建議您始終呼叫recycle在您完成點陣圖操作時,否則您的應用程式可能會在某個時刻崩潰並顯示令人恐懼的訊息“java.lang.OutOfMemoryError: bitmap size exceeds VM budget”。

本機程式碼的記憶體使用量不受任意限制,可以自由分配所有可用記憶體。

儲存/恢復例項狀態

[編輯 | 編輯原始碼]

活動和檢視可以實現呼叫來儲存和恢復它們的“例項狀態”。這同於儲存/恢復使用者資料;這純粹是機制的一部分,可以讓您的程序看起來一直在執行,即使系統需要殺死它,無論是由於記憶體不足還是由於重新啟動它以進行方向更改。

如果您的活動處於最前面,使用者按下後退按鈕,那麼這通常被認為是終止該活動的請求。下次使用者啟動您的活動時,他們通常不會期望它恢復到好像從未終止過的狀態。在這種情況下,onSaveInstanceStateonRestoreInstanceState被呼叫。

如果您的活動處於最前面,使用者在它之上啟動了其他活動,那麼您的onSaveInstanceState方法將與onPause一起呼叫。如果使用者在您的活動仍在執行時返回到您的活動,則onResume將按通常方式呼叫,但無需呼叫onRestoreInstanceState.

但是,如果您的活動不在最前面時系統記憶體不足,它可能會在使用者未注意到的情況下被殺死。然後,當用戶返回它時,它將重新啟動,並且onRestoreInstanceState將被呼叫,以便您可以使其看起來像您一直在執行。

此外,如果您的活動處於最前面時裝置在縱向和橫向之間切換方向,則如果您的程式碼沒有專門處理它,預設操作是系統殺死並重新啟動您。只要您的佈局經過適當的設計以處理這兩種情況,這通常就足夠了。

請注意,“例項狀態”是什麼完全取決於您。例如,地圖檢視器應用程式可能每次使用者啟動時都恢復到完全縮小的檢視。因此,滾動位置和縮放倍率將作為例項狀態的一部分儲存和恢復。或者,您可能會決定應用程式每次退出和重新啟動時都會記住其滾動偏移量和縮放倍率,在這種情況下,儲存/恢復例項狀態根本無關緊要。作為應用程式的編寫者,這是您的選擇。

您無法殺死執行緒

[編輯 | 編輯原始碼]

請注意,可能透過 Java API 殺死或中止另一個執行緒:相關的 Thread.stop/destroy 方法未實現,因為它們可能會使 Dalvik VM 處於不一致狀態。

這也適用於基於 Thread 的類,例如 AsyncTask:一旦 doInbackground 方法開始在後臺執行緒上執行,它將執行到完成,無論您是否傳遞truecancel 還是不傳遞。

當然,本機程式碼可以繞過此限制,但這會帶來所有隱含的危險。此外,程序始終可以整體被殺死,因為一旦整個程序狀態消失,我們就不會關心其一致性。

使用 Java 編寫 Android 應用程式

[編輯 | 編輯原始碼]

Android 應用程式主要使用 Java 程式語言編寫,並設計為相互隔離執行,以維護安全的操作環境。每個應用程式都在其自己的 Dalvik 虛擬機器例項中執行,並在其自己的 Linux 使用者下執行。

與大多數(如果不是全部)其他移動平臺相比,Android 真正支援多工/多執行緒;因此,多個應用程式可以同時執行,每個應用程式可以同時執行多個操作。這意味著使用者可以開啟其郵件/新聞/等應用程式,並在收到新郵件時獲得通知,而不是不斷地自己檢查。

Android 應用程式以 .apk 檔案的形式交付(使用 jartool 簽名的 zip 檔案,只是字尾不同)。這些軟體包包含應用程式執行所需的所有檔案,其中有 classes.dex 檔案,該檔案是在 Dalvik VM 內部執行的檔案,以及 AndroidManifest.xml 檔案,它是純文字 XML 清單的二進位制表示。通常還有其他資源,如可繪製物件(影像/精靈/圖示)和 XML 佈局。

編寫 Android 應用程式的受支援 IDE 是 Eclipse,但使用它並非強制性。

Android(Java)應用程式本身包含多個子類化 Intent 和 Activity 類(包括服務和內容提供者)的類。

Android 應用程式被編譯成 .dex 檔案格式的二進位制檔案,然後打包到 apk(zip 存檔)檔案中。

替代程式語言

[編輯 | 編輯原始碼]

人們使用多種語言為 Android 編寫程式。

我們將在本書的另一章中討論使用 JavaScript、HTML5 和 CSS3 為 Android 編寫程式 - Android/PhoneGap

Android 指令碼層 (SL4A) [1] 支援多種指令碼語言。

有些人使用 Python For Android [2] 與 SL4A 一起為 Android 編寫 Python 應用程式。

其他人使用 Kivy [3] 為 Android 編寫 Python 應用程式。

替代 IDE

[編輯 | 編輯原始碼]

有些人使用在 Android 裝置本身執行的編輯器和編譯器開發 Java 應用程式。我們將在後面的章節中討論終端 IDE - Android/Terminal IDE

實用程式庫

[編輯 | 編輯原始碼]

一些可能有助於編碼的庫;有關測試庫和系統,請參閱測試章節。

  • ActionBarSherlock - 支援早期 Android 版本上的現代(4.x)操作欄樣式介面,允許一個應用程式服務所有版本。
  • AndroidAnnotations - 程式碼生成器,允許程式設計師避免編寫許多 Android UI 和非同步程式碼的樣板程式碼。
  • SlidingMenus - 提供“滑動面板向右顯示選單”功能。
  • android-query - 簡化 UI 和非同步編碼。
  • Lars Vogel。 "Android 開發教程":如何使用 Eclipse 建立 Android 應用程式。
  • Android 門戶 在嵌入式 Linux Wiki 上有一個 Android 應用程式開發教程集。


UserProfile 類 :-

package com.mock.denethanjanaperera.mymock;

import android.provider.BaseColumns;

public final class UserProfile {

   private UserProfile(){
   }
   public class Users implements BaseColumns{
       public final static String TABLE_NAME = "UserInfo";
       public final static String COLUMN_USERNAME = "username";
       public final static String COLUMN_PASSWORD = "password";
       public final static String COLUMN_GENDER = "gender";
       public final static String COLUMN_DOB = "dateofBirth";
   }


}


DBhelper 類 :-

package com.mock.denethanjanaperera.mymock.database;

import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper;

import com.mock.denethanjanaperera.mymock.User; import com.mock.denethanjanaperera.mymock.UserProfile;

import java.util.ArrayList;

public class DBHelper extends SQLiteOpenHelper {

   private final static String DATABASE_NAME = "UserInfo.db";
   public DBHelper(Context context) {
       super(context, DATABASE_NAME,null, 1);
   }


   @Override
   public void onCreate(SQLiteDatabase sqLiteDatabase) {
       String CREATE_TABLE = "CREATE TABLE " + UserProfile.Users.TABLE_NAME +" (" +
               UserProfile.Users._ID + " INTEGER PRIMARY KEY," +
               UserProfile.Users.COLUMN_USERNAME + " TEXT," +
               UserProfile.Users.COLUMN_DOB + " TEXT," +
               UserProfile.Users.COLUMN_GENDER + " TEXT," +
               UserProfile.Users.COLUMN_PASSWORD + " TEXT )";
       sqLiteDatabase.execSQL(CREATE_TABLE);
   }
   @Override
   public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
   }
   public Long addInfo(String username, String password){
       SQLiteDatabase sqLiteDatabase = getWritableDatabase();
       ContentValues cv = new ContentValues();
       cv.put( UserProfile.Users.COLUMN_USERNAME, username);
       cv.put( UserProfile.Users.COLUMN_PASSWORD, password );
       Long rowId = sqLiteDatabase.insert(UserProfile.Users.TABLE_NAME, null,cv);
       return rowId;
   }


   public int updateInfo(String userId, String username, String password, String dob, String gender ){
       SQLiteDatabase sqLiteDatabase = getWritableDatabase();
       ContentValues cv = new ContentValues();
       cv.put( UserProfile.Users.COLUMN_USERNAME, username);
       cv.put( UserProfile.Users.COLUMN_PASSWORD, password );
       cv.put( UserProfile.Users.COLUMN_GENDER, gender);
       cv.put( UserProfile.Users.COLUMN_DOB, dob);
       String select = UserProfile.Users._ID + " = ?";
       String args[] = {userId};
       int count = sqLiteDatabase.update(UserProfile.Users.TABLE_NAME, cv, select,args);
       return count;
   }
   public ArrayList readAllInfo(){
       SQLiteDatabase sqLiteDatabase = getReadableDatabase();
       String[] projection = {
               UserProfile.Users._ID,
               UserProfile.Users.COLUMN_USERNAME,
               UserProfile.Users.COLUMN_DOB,
               UserProfile.Users.COLUMN_GENDER,
               UserProfile.Users.COLUMN_PASSWORD
       };
       String sortOrder = UserProfile.Users._ID + " DESC";
       Cursor cursor = sqLiteDatabase.query(
               UserProfile.Users.TABLE_NAME,
               projection,
               null,
               null,
               null,
               null,
               sortOrder
       );
       ArrayList<User> list = new ArrayList<>();
       if (cursor.getCount() > 0){
           while(cursor.moveToNext()){
               User newUser = new User();
               int id = cursor.getInt(cursor.getColumnIndexOrThrow(UserProfile.Users._ID));
               String user = cursor.getString(cursor.getColumnIndexOrThrow(UserProfile.Users.COLUMN_USERNAME));
               String date = cursor.getString(cursor.getColumnIndexOrThrow(UserProfile.Users.COLUMN_DOB));
               String gen = cursor.getString(cursor.getColumnIndexOrThrow(UserProfile.Users.COLUMN_GENDER));
               String pass = cursor.getString(cursor.getColumnIndexOrThrow(UserProfile.Users.COLUMN_PASSWORD));
               newUser.setUserId(id+"");
               newUser.setUserName(user);
               newUser.setDateOfBirth(date);
               newUser.setGender(gen);
               newUser.setPassword(pass);
               list.add(newUser);
           }
       }
       return list;
   }
   public ArrayList readAllInfo(String userId, String userName){
       String selection;
       String[] args = {""};
       if(userId == null){
           selection = UserProfile.Users.COLUMN_USERNAME + " LIKE ?";
           args[0] = userName;
       }
       else
       {
           selection = UserProfile.Users._ID + " = ?";
           args[0] = userId;
       }
       SQLiteDatabase sqLiteDatabase = getReadableDatabase();
       String[] projection = {
               UserProfile.Users._ID,
               UserProfile.Users.COLUMN_USERNAME,
               UserProfile.Users.COLUMN_DOB,
               UserProfile.Users.COLUMN_GENDER,
               UserProfile.Users.COLUMN_PASSWORD
       };


       String sortOrder = UserProfile.Users._ID + " DESC";
       Cursor cursor = sqLiteDatabase.query(
               UserProfile.Users.TABLE_NAME,
               projection,
               selection,
               args,
               null,
               null,
               sortOrder
       );
       ArrayList<User> list = new ArrayList<>();
       if (cursor.getCount() > 0){
           while(cursor.moveToNext()){
               User newUser = new User();
               int id = cursor.getInt(cursor.getColumnIndexOrThrow(UserProfile.Users._ID));
               String user = cursor.getString(cursor.getColumnIndexOrThrow(UserProfile.Users.COLUMN_USERNAME));
               String date = cursor.getString(cursor.getColumnIndexOrThrow(UserProfile.Users.COLUMN_DOB));
               String gen = cursor.getString(cursor.getColumnIndexOrThrow(UserProfile.Users.COLUMN_GENDER));
               String pass = cursor.getString(cursor.getColumnIndexOrThrow(UserProfile.Users.COLUMN_PASSWORD));
               newUser.setUserId(id+"");
               newUser.setUserName(user);
               newUser.setDateOfBirth(date);
               newUser.setGender(gen);
               newUser.setPassword(pass);
               list.add(newUser);
           }
       }
       return list;
   }
   public int deleteInfo(String username){
       SQLiteDatabase sqLiteDatabase = getReadableDatabase();
       String select = UserProfile.Users._ID + " = ?";
       String [] args = {username};
       int deleteRows = sqLiteDatabase.delete(UserProfile.Users.TABLE_NAME, select, args);
       return deleteRows;
   }
   }



Home 類 :-

package com.mock.denethanjanaperera.mymock;

import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast;

import com.mock.denethanjanaperera.mymock.database.DBHelper;

import java.util.ArrayList;

public class Home extends AppCompatActivity {

   private Button login, reg;
   private EditText uname, password;
   private DBHelper dbHelper;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_home);
       dbHelper = new DBHelper(this);
       login = findViewById(R.id.btnLogin);
       reg = findViewById(R.id.btnReg);
       uname = findViewById(R.id.etHUname);
       password = findViewById(R.id.etHPassword);


       login.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               ArrayList<User> list = dbHelper.readAllInfo();
               for(User u : list){
                   if(u.getUserName().equals(uname.getText().toString())){
                       if(u.getPassword().equals(password.getText().toString())){
                           Intent intent = new Intent(Home.this, ProfileManagement.class);
                           intent.putExtra("id", u.getUserId());
                           startActivity(intent);
                       }else{
                           Toast.makeText(Home.this, "Invalid Username and Password", Toast.LENGTH_SHORT).show();
                       }
                   }
               }
           }
       });


       reg.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               String user = uname.getText().toString();
               String passwrd = password.getText().toString();
               if ((user.isEmpty() || passwrd.isEmpty())) {
                   Toast.makeText(Home.this, "Enter Registration Info", Toast.LENGTH_SHORT).show();
               } else {
                   dbHelper.addInfo(user, passwrd);
                   Toast.makeText(Home.this, "User Registered!", Toast.LENGTH_SHORT).show();
               }
           }
       });


   }

}


profilManagemant 類 :-


package com.mock.denethanjanaperera.mymock;

import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.RadioButton;

import com.mock.denethanjanaperera.mymock.database.DBHelper;

import java.util.ArrayList;

public class ProfileManagement extends Activity {

   private Button update;
   private EditText uname, dob, pass;
   private RadioButton male, female;
   private DBHelper dbHelper;
   private String userId;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_profile_management);
       dbHelper = new DBHelper(this);
       Intent intent = getIntent();
       userId = intent.getStringExtra("id");
       uname = findViewById(R.id.etUuser);
       dob = findViewById(R.id.etUdob);
       pass = findViewById(R.id.etUdob);
       update = findViewById(R.id.btnUpdate);
       male = findViewById(R.id.radioMale);
       female = findViewById(R.id.radioFe);
       ArrayList<User> list =  dbHelper.readAllInfo(userId, null);
       for (User u : list){
           uname.setText(u.getUserName());
           pass.setText(u.getPassword());
           dob.setText(u.getDateOfBirth());
           if(u.getGender() != null){
               if(u.getGender().equals("Male")){
                   male.setChecked(true);
               }
               else
               {
                   female.setChecked(true);
               }
           }
       }
       update.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               Intent intent = new Intent(ProfileManagement.this, EditProfile.class);
               intent.putExtra("id", userId);
               startActivity(intent);
           }
       });
   }

}


EditProfile 類 :-


package com.mock.denethanjanaperera.mymock;

import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.Toast;

import com.mock.denethanjanaperera.mymock.database.DBHelper;

import java.util.ArrayList;

public class EditProfile extends AppCompatActivity {

   private Button edit, delete, search;
   private EditText uname, dob, pass;
   private RadioGroup radioGroup;
   private RadioButton male, female;
   private String gender;
   private DBHelper dbHelper;
   private String userId;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_edit_profile);


       dbHelper = new DBHelper(this);
       Intent intent = getIntent();
       userId = intent.getStringExtra("id");
       Toast.makeText(EditProfile.this, "User Id: " + userId, Toast.LENGTH_SHORT).show();
       uname = findViewById(R.id.etEUser);
       dob = findViewById(R.id.etEdob);
       pass = findViewById(R.id.etEpassword);
       edit = findViewById(R.id.btnEdit);
       delete = findViewById(R.id.btnDelete);
       search = findViewById(R.id.btnSearch);
       radioGroup = findViewById(R.id.radio);
       male = findViewById(R.id.radEmale);
       female = findViewById(R.id.radEfemale);
       ArrayList<User> list = dbHelper.readAllInfo(userId, null);
       if (!list.isEmpty()) {
           for (User u : list) {
               uname.setText(u.getUserName());
               pass.setText(u.getPassword());
               dob.setText(u.getDateOfBirth());
               if (u.getGender() != null) {
                   if (u.getGender().equals("Male")) {
                       male.setChecked(true);
                   } else {
                       female.setChecked(true);
                   }
               }
           }
       }


       radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
           @Override
           public void onCheckedChanged(RadioGroup radioGroup, int view) {
               if(view == R.id.radEfemale){
                   gender = "Female";
               }
               else{
                   gender = "Male";
               }
           }
       });
       search.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               ArrayList<User> urs = dbHelper.readAllInfo(null, uname.getText().toString());
               for (User u : urs){
                   userId = u.getUserId();
                   uname.setText(u.getUserName());
                   pass.setText(u.getPassword());
                   dob.setText(u.getDateOfBirth());
                   if(u.getGender() != null){
                       if(u.getGender().equals("Male")){
                           male.setChecked(true);
                       }
                       else
                       {
                           female.setChecked(true);
                       }
                   }
               }
           }
       });
       edit.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               String userName = uname.getText().toString();
               String date = dob.getText().toString();
               String pwrd = pass.getText().toString();
               if(female.isChecked()){
                   gender = "Female";
               }
               else{
                   gender = "Male";
               }
               int count = dbHelper.updateInfo(userId, userName, pwrd, date, gender);
               if(count > 0){
                   Toast.makeText(EditProfile.this, "Updated!", Toast.LENGTH_SHORT).show();
               }
               else{
                   Toast.makeText(EditProfile.this, "Error in data Sending!", Toast.LENGTH_SHORT).show();
               }
           }
       });


       delete.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               int count = dbHelper.deleteInfo(userId);
               if(count > 0){
                   Toast.makeText(EditProfile.this, "Deleted!", Toast.LENGTH_SHORT).show();
               }
               else{
                   Toast.makeText(EditProfile.this, "Something went wrong!", Toast.LENGTH_SHORT).show();
               }
           }
       });
   }

}


User 類 :-

package com.mock.denethanjanaperera.mymock;

public class User {

   private String userId;
   private String userName;
   private String dateOfBirth;
   private String gender;
   private String password;
   public User(){
   }
   public String getUserId() {
       return userId;
   }
   public void setUserId(String userId) {
       this.userId = userId;
   }
   public String getUserName() {
       return userName;
   }
   public void setUserName(String userName) {
       this.userName = userName;
   }
   public String getDateOfBirth() {
       return dateOfBirth;
   }
   public void setDateOfBirth(String dateOfBirth) {
       this.dateOfBirth = dateOfBirth;
   }
   public String getGender() {
       return gender;
   }
   public void setGender(String gender) {
       this.gender = gender;
   }
   public String getPassword() {
       return password;
   }
   public void setPassword(String password) {
       this.password = password;
   }



}

華夏公益教科書