❑ Shared Preferences เป็นข้อมูลแบบ key/value เอาไว้เก็บ UI state, user preferences หรือ application settings
❑ Files เก็บลองไฟล์โดยตรง Android อนุญาติให้คุณสร้าง และโหลดไฟล์ทั้งจากในเครื่อง และการ์ด
❑ SQLite Databases ถ้าต้องการการจัดการที่สูงขึ้น structured data น่าจะดีที่สุด, Android มี library ของ SQLite relational database. ทุก ๆ application สามารถสร้าง databases ของตัวเองได้ และจัดการได้ทั้งหมด
❑ Content Providers นอกจากข้อมูลด้วยสิทธิ์ของตัวเองแล้ว, Content Providers อนุญาติให้คุณดึงข้อมูลที่ถูกสร้างไว้แล้วจาก interface ของโปรแกรมคนอื่น คุณสามารถจัดการการเข้าถึง Content Providers โดยใช้ระบบ permission
แสดงบทความที่มีป้ายกำกับ Android แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ Android แสดงบทความทั้งหมด
วันพุธที่ 22 กรกฎาคม พ.ศ. 2552
วันศุกร์ที่ 17 กรกฎาคม พ.ศ. 2552
TIP on Android Development
เทคนิคที่สำคัญที่สุดอันหนึ่งของการเขียนโปรแกรมบน Android คือการหลีกเลี่ยงการสร้าง และ ทำลาย object บ่อย ๆ ซึ่งทุก ๆ object ที่ถูกสร้างใน method onDraw จะถูกสร้างและทำลายทิ้ง ทุก ๆ ครั้งที่คุณ refresh หน้าจอ
เราจะเพิ่มประสิทธิภาำพให้โปรแกรมได้โดยการย้ายการสร้าง object พวกนี้ (โดยเฉพาะ instance ของ Paint และ Drawable) ไปใว้ใน constructor
public class MyView extends View { // Constructor required for in-code creation public MyView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { int px = 100; int py = 100; // Create the new paint brushes Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTextPaint.setColor(Color.WHITE); // Define the string. String displayText = “Hello World!”; // Measure the width of the text string. float textWidth = mTextPaint.measureText(displayText); // Draw the text string in the center of the control. canvas.drawText(displayText, px-textWidth/2, py, mTextPaint); } }ไปเป็น...
public class MyView extends View { // Constructor required for in-code creation public MyView(Context context) { super(context); // Create the new paint brushes Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } @Override protected void onDraw(Canvas canvas) { int px = 100; int py = 100; mTextPaint.setColor(Color.WHITE); // Define the string. String displayText = “Hello World!”; // Measure the width of the text string. float textWidth = mTextPaint.measureText(displayText); // Draw the text string in the center of the control. canvas.drawText(displayText, px-textWidth/2, py, mTextPaint); } }
วันพฤหัสบดีที่ 16 กรกฎาคม พ.ศ. 2552
Introducing the Android Menu System
เมนูมีอยู่ 3 ประเภท
- Icon Menu เป็นเมนูที่แสดงเมื่อกดปุ่มเมนู แสดงได้สูงสุด 6 อัน
ไม่สามารถแสดง checkbox, radio button, หรือ shortcut key ได้ จึงไม่ควรใส่พวกนั้นไว้ใน icon menu แล้วก็ถ้าใส่ item ไปมากกว่า 6 item มันจะมีปุ่ม More ขึ้นมาให้กดเพื่อให้แสดง expanded menu ถ้าจะออกจากเมนูก็กดปุ่ม back - Expanded Menu ขึ้นมาเมื่อกดปุ่ม More ที่ icon menu มันจะแสดงแสดง list ที่สามารถ scroll ได้ และแสดงเฉพาะ item ที่ไม่แสดงใน icon menu ซึ่งเมนูนี้จะแสดงทั้ง text เต็ม, short cut key, check box, radio button ได้ปกติ
ไม่สามารถแสดง icon ได้ดังนั้น เวลาเขียนโปรแกรมก็อย่าใส่ icon ให้เมนูที่คิดว่ายังไงก็ต้องมาตกใน expended menu กด back เพื่อกลับไป icon menu - Submenu เป็นเมนูพื้นฐาน ที่เปิดด้วย mouse จะแสดงเป็น floating window
กด back จะปิด floating window
ป้ายกำกับ:
Android
วันจันทร์ที่ 13 กรกฎาคม พ.ศ. 2552
Modifying Existing Views
การสร้าง widget ใหม่จาก control ที่มีอยู่แล้ว เราจะสร้าง class ขึ้นมาสืบทอดมัน
import android.content.Context; import android.util.AttributeSet; import android.widget.TextView; public class MyTextView extends TextView { public MyTextView (Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public MyTextView (Context context) { super(context); } public MyTextView (Context context, AttributeSet attrs) { super(context, attrs); } }ข้างบนนี่เป็นโครงคร่าว ๆ เราต้องมา Override method เพิ่มอีก เช่น
@Override public void onDraw(Canvas canvas) { [ ... Draw things on the canvas under the text ... ] // Render the text as usual using the TextView base class. super.onDraw(canvas); [ ... Draw things on the canvas over the text ... ] } @Override public boolean onKeyDown(int keyCode, KeyEvent keyEvent) { [ ... Perform some special processing ... ] [ ... based on a particular key press ... ] // Use the existing functionality implemented by // the base class to respond to a key press event. return super.onKeyDown(keyCode, keyEvent); }
ป้ายกำกับ:
Android
Android Layouts
Layout Manager หรือ layouts เป็นส่วนขยายของ ViewGroup class เอาไว้ควบคุมตำแหน่งของ child control บนจอภาพ สามารถ nested ได้
- FrameLayout ง่ายที่สุด มันจะเปิด child view ขึ้นมาอ้างอิงด้วยมุมบนซ้าย และจะทับอันอื่น ๆ ไปเรื่อย ๆ
- LinearLayout เพิ่ม child ในแนวเส้นตรง อาจจะแนวตั้งหรือแนวนอนก็ได้ สามารถกำหนด weight ให้ child ทุกตัวเพื่อกำหนดขนาดให้สัมพันธ์กันได้
- RelativeLayout จัดวางให้สัมพันธ์กับ child อื่นหรือขอบจอ
- TableLayout ใช้ตารางของ row และ columns
- AbsoluteLayout วางตรงไหนก็ได้ แต่มีข้อเสียคือเวลาจอภาพเปลี่ยนแปลงไป จะไม่สามารถ dynamic ได้เท่าที่ควร
ป้ายกำกับ:
Android
The Android Widget Toolbox
Android 0ะมี toolbox ที่เป็น View มาตรฐานที่จะช่วยให้คุณสร้าง User Interface ง่าย ๆ ได้โดยใช้ control พวกนี้ และยังทำให้โปรแกรม ดูเป็นมาตรฐานเดียวกันด้วย
toolbox control ที่เด่น ๆ ได้แก่
- TextView เป็น read only text label สามารถแสดงหลายบรรทัด (Multipleline), การจัดรูปแบบ (String formatting), และ ตัดคับอัตโนมัติได้ (Word Wrapping)
- EditText ช่องที่เอาไว้กรอกข้อความ สามารถ multipleline และ word wrapping
- ListView เป็น View Group ของ View ที่แสดง Item ใน List ธรรมดาแล้วจะแสดง String ของ Array ค่าหนึ่งด้วย TextView สำหรับทุก ๆ ค่า
- Spinner แสดง TextView และทำงานร่วมกันกับ ListView ซึ่งมันจะแสดง Item ที่เราเลือกขึ้นไปบน Textbox มันมาจากการรวม TextView ที่แสดง Item ปัจจุบัน และ ปุ่ม (button) ที่แสดง ListView พอกด Item ใน ListView ข้อความใน ListView ก็จะไปอยู่ที่ TextView แทน
- Button ปุ่มไว้กด
- CheckBox ปุ่มที่มี 2 สถานะคือ checked และ unchecked
- RadioButton กลุ่มของปุ่ม 2 สถานะที่เลือกได้ตัวเลือกเดียว
ป้ายกำกับ:
Android
วันอาทิตย์ที่ 12 กรกฎาคม พ.ศ. 2552
Android UI Design
Android ใช้ UI แบบใหม่ที่คิดค้นขึ้นเอง ประกอบด้วยส่วนสำคัญ 3 อย่างคือ
- View เป็น User Interface พื้นฐานสำหรับสิ่งต่าง ๆ ที่อยู่บนจอภาพ เช่น control หรือ widget ทั้งการควบคุม User Interface และ class ของ layout ก็สืบทอดจาก Views
- ViewGroup เป็นส่วนขยายของ class View ที่ประกอบไปด้วย child ของ Views หลายอัน โดยสิบทอด class Viewgroup ทำให้ View แต่ละอันใน Viewgroup สามาถติดต่อสื่อสารกันได้ รวมถึงยังมีตัวจัดการ layer เช่น LinearLayout ที่ช่วยสร้าง User Interface
- Activity เป็นตัวที่สั่งแสดงหน้าต่างหรือ screen ให้ User เห็น Activity เปรียบได้กับ form ในการที่จะแสดง User Interface เราต้องผูก View หรือ layout เข้ากับ Activity
ป้ายกำกับ:
Android
วันศุกร์ที่ 10 กรกฎาคม พ.ศ. 2552
Android Application Fundamentals
Activities
Activity คือหน้า UI ที่ user กระทำการต่าง ๆ บนนั้น อาจจะเป็นการแสดงเมนูให้เลือก, แสดงรูปภาพพร้อมคำอธิบาย, อะไรก็ตาม ฯลฯ โปรแกรม text โปรแกรมหนึ่งอาจจะมี activity นึงที่ใช้แสดงเบอร์ที่จะส่งไป และมี activity ที่สองที่จะเขียนข้อความที่จะส่ง และอีก activity ไว้ดูข้อความก่อนหน้านั้น หรือเอาไว้แก้ setting ซึ่งถึงแม้มันจะทำงานร่วมกันในหน้า UI หน้าเดียว แต่ activity แต่ละตัวก็ไม่ขึ้นต่อกัน และทุกตัวเชียนขึ้นโดนเป็น sub class ของ Class Activity
โปรแกรมเราอาจจะมี 1 activity หรือหลาย Activity ก็ได้แล้วแต่เราออกแบบ แต่ปกติแล้วจะมี Activity นึงที่เป็นหน้าแรกที่ user เห็นตอนเปิดโปรแกรมเราเข้ามา การเปลี่ยน Activity นึง ไปอีก Activity นึง ใช้การเรียก Activity จาก Activity ก่อนหน้า
ทุก Activity จะมีพื้นที่ให้ใส่อะไรลงไปข้างใน ปกติแล้วจะเต็มจอ แต่ถ้าอยากเปลี่ยนก็ปรับขนาดได้เอง หรือปรับให้อยู่บนหน้าต่างอื่นก็ได้ Activity สามารถสร้างหน้าต่างอื่นเพิ่มได้ เช่น pop up หรือหน้าต่างแสดงข้อมูลพื้นฐานเวลา user เลือกไปที่วัตถุ ๆ หนึ่งบนจอ
เนื้อหาที่แสดงบนจอมาจาก Class View และ มันจะเป็นส่วนที่ติดต่อกับผู้ใช้ เช่น อาจจะแสดงรูปเล็กๆบนจอ พอเอานิ้วกดแล้วขยายรูปเต็มเป็นต้น
View จะถูกวางไว้ใน Activity ด้วยคำสั่ง Activity.setContentView()
Services
Services ไม่มี ีuser interface แต่จะทำงานที่ background แทน ในช่วงเวลาหนึ่งๆ แล้วแต่กำหนด เช่น มี service อันนึงเล่นเพลงเป็น background ระหว่างที่ผู้ใช้งานก็ใช้งานอย่างอื่นไปด้วย หรืออาจจะเป็น service ที่ไปดึงข้อมูลจากที่อื่นใน network หรือคำนวณอะไรบางอย่างข้างหลัง และส่งค่ากลับมาให้ Activity ที่ต้องการใช้ Service ทุกตัวสืบทอดมาจาก Class Service
ตัวอย่างที่ดีที่สุดอันหนึ่งคือโปรแกรมเล่นเพลง โปรแกรมนี้จะประกอบด้วย Activity 1 หรือ 2 อันที่ให้ User เลือกเพลงกับสั่งเล่นเพลง อย่างไรก็ตาม ตัวที่จะไปเล่นเพลงจริงๆนั้นไม่ควรถูกจัดการด้วย Activity เพราะผู้ใช้น่าจะหวังไว้ว่าเพลงจะยังเล่นต่อไปในระหว่างที่เขาไปทำอย่างอื่น เพื่อที่จะให้เพลงยังเล่นต่อไปได้ Activity จะไปเรียก Service ให้ทำงานอยู่ใน background และระบบจะยังคงเก็บ Service นี้ให้ทำงานต่อ แม้ว่า Activity ที่เรียกมันจะถูกปิดไปแล้ว
เรายังสามารถที่จะติดต่อกับ Service ที่กำลังทำงานอยู่ได้ด้วย ซึ่งระหว่างที่ติดต่อนั้น เราก็จะสามารถสั่งการ Service นั้น ตามแต่ที่ Service นั้นจะได้เขียนไว้ให้ทำได้ เช่นกับ Service ที่เล่นเพลง เราก็สามารถ หยุด ย้อนกลับ หรือเล่นเพลงใหม่ได้
เช่นเดียวกันกับ Activity และ component อื่นๆ Services ทำงานใน main thread ของ application process มันจึงไม่ไป block component อื่น หรือ User interface แต่มันมักจะสร้าง thread ใหม่ เพื่อใช้สำหรับงานที่กินเวลามากๆ อย่างเช่น การเล่นเพลง
Broadcast receivers
ไม่ทำอะไรเลยนอกจาก รับ แล้วก็ตอบสนองต่อ broadcast announcement ซึ่ง boardcast ส่วนใหญ่มักมาจากโคดของระบบ เช่น ประกาศ time zone ถูกเปลี่ยน, แบตต่ำ, รูปถูกรับ หรือเปลี่ยนภาษา นอกจากนั้น โปรแกรมของเราก็สร้าง boardcasts ได้ เช่นบอกให้โปรแกรมอื่นรู้ว่าข้อมูลได้ดาวน์โหลดเสร็จแล้ว และพร้อมให้พวกมันใช้งาน
โปรแกรมหนึ่งๆ จะมีกี่ broadcast receiver ก็ได้ เพื่อตอบสนองต่อสิ่งที่มันสนใจ receivers ทุกตัวสืบทอดคลาส BroadcastReceiver
Broadcast receivers ไม่มี UI แต่มันสามารถไปเรียก Activity เพื่อตอบสนองสิ่งที่มันได้รับมาได้ หรือมันอาจจะใช้ NotificationManager เพื่อเตือนผู้ใช้ ซึ่ง Notification สามารถเรียกร้องความสนใจได้หลายแบบ เช่น แสง backlight, สั่น, เล่นเสียง เป็นต้น และมันมักจะวาง icon ไว้บน status bar เพื่อให้ user เปิดเข้าไปอ่านได้
Content providers
content provider สร้างเซ็ทข้อมูลของโปรแกรมหนึ่งๆขึ้นมา เพื่อให้โปรแกรมอื่นสามารถเอาไปใช้งานได้ อาจจะเป็นไฟล์ หรือ SQLite หรืออย่างอื่นที่มัน makes sense สืบทอดจากคลาส ContentProvider ที่ให้โปรแกรมอื่นดึงข้อมูล และเก็บข้อมูลนั้นไว้ในแบบที่ตนต้องการ แต่เราไม่ได้เรียก method นั้นตรง ๆ เราจะใช้ object ContentResolver ไปเรียก method นั้นแทน ContentResolver สามารถคุยกับ content provider ได้ทุกตัว มันทำงานร่วมกันกับ provider เพื่อติดต่อสื่อสารระหว่าง provider ด้วยกัน
Activating components: intents
Content provider ทำงานตอนที่โดน ContentResolver ส่ง request มา แต่อีก 3 ตัว activities, services, and broadcast receivers จะทำงานด้วย asynchronous messages ที่เรียกว่า intents ซึ่งเป็น object ของ Intent ที่เก็บเนื้อหาของ messege นั้นๆ สำหรับ activities และ services จะมีชื่อของ action ที่ถูกร้องขอ และ URI ของข้อมูลที่จะไปทำงานด้วย ตัวอย่างเช่น เราจะส่ง request อันนึงไปยัง activity เพื่อแสดงรูปภาพให้เห็น และยังให้สามารถเพิ่มคำอธิบายได้ สำหรับ boardcast receivers นั้น Intent object เก็บชื่อ action ที่จะถูกประกาศ เช่นมันจะประกาศข้อความเตือนเมื่อกดปุ่มถ่ายรูป
การจะเรียก component มันก็จะมีวิธีต่างๆกัน
Activity จะถูกเปิดโดยการส่ง Intent object ไปยัง Context.startActivity() หรือ Activity.startActivityForResult() แล้ว activity ที่ถูกสร้างขึ้นจะสามารถดู Intent ที่เรียกมันขึ้นมาได้ด้วย method getIntent() และ Android จะเรียก method ของ activity ชื่อ onNewIntent() เพื่อส่ง intent ให้มัน
Activity นึงมักจะเรียกอีก Activity นึง แต่ถ้าอยากให้ result กลับมายัง Activity ที่เรียกมัน จะใช้คำสั่ง startActivityForResult() แทน startActivity() เช่นตอน User เลือกรูปภาพ ผลลัพธ์จะถูกส่งกลับไปยัง Intent ที่เรียกมันด้วย method onActivityResult
Service ถูกสร้างโดยส่ง Intent obkect ไปยัง Context.startService() Android จะเรียก method ของ service ชื่อ onStart() เพื่อส่ง Intent object ให้มัน
ในทำนองเดียวกัน intent สามารถส่ง Context.bindService() เพื่อติดต่อระหว่าง component ที่ถูกเรียกอยู่ ไปยัง service เป้าหมาย service ก็จะรับ Intent object ด้วยคำสั่ง onBind() ถ้า service ไม่ได้ทำงานอยู่ ใช้คำสั่ง bindService() จะเปิดมันให้ ตัวอย่างเช่น มี activity ที่จะติดต่อกับ service ที่เล่นเพลง ทำให้เรามีหน้าจอไว้ควบคุมการเล่นเพลง ซึ่ง activity นี่ก็ควรจะ bindService เพื่อสร้างการติดต่อ จากนั้นจึงเรียก method ที่จะมีผลกับการเล่นเพลงต่อไป
Boardcast ทำโดยการส่ง Intent object ไปยัง method เช่น Context.sendBroadcast(), Context.sendOrderedBroadcast() และ Context.sendStickyBroadcast() Android ส่ง intent ต่อให้กับ boardcast reveivers ที่สนใจด้วย method onReveiver()
Shutting down components
Content provider จะทำงานก็ต่อเมื่อมันตอบสนองการร้องขอของ ContentResolver และ broadcast receiver ทำงานก็ต่อเมื่อมันตอบสนองต่อ broadcast message ดังนั้นจึงไม่ต้องมีการ shutdown component พวกนี้
Activities ไม่เหมือนกัน เพราะมันมี UI มันอาจจะทำงานไปเรื่อยๆ ตราบใดที่ยังติดต่อกับ user ได้อยู่ ส่วน service อาจจะทำงานไปเรื่อยๆ ไม่มีวันหยุด ดังนั้น Android จะต้องมี method เพื่อมาปิดการทำงานของ component พวกนี้อย่างถูกต้อง
- Activity สามารถ shutdown โดยเรียก method finish() Activity หนึ่งสามารถ shutdown อีก activity (ที่ start ด้วย startActivityForResult()) โดยเรียก finishActivity()
- Service สามารถถูกหยุดโดย mrthod ของตุวเองชื่อ stopSelf() หรือโดยเรียก Context.stopService()
Component ยังอาจจะถูกปิดโดยระบบ เมื่อมันไม่ได้ใช้งานอีกแล้ว หรือตอนที่ Android ขอ memory คืนเพื่อไปเปิด component อื่น ไปศึกษาต่อเรื่อง Component Lifecycle
The manifest file
ก่อนที่ Android จะสามารถ start component ของ application ของเราได้นั้น มันต้องรู้ก่อนว่ามี component นั้นอยู่ด้วย ดังนั้น application จะประกาศ component ของมันเอาไว้ใน manifest file ที่ผูกติดไปกับไฟล์ .apk ที่เก็บ code ของ application, file, resources
manifest เป็น structured XML file และจะชื่อ AndroidManifest.xml เสมอ ทุกๆ application มันทำหน้าที่หลายอย่าง นอกจากประกาศ component ที่ application ใช้ เช่นบอกชื่อ libraries ที่ application ต้องการติดต่อด้วย (นอกจาก default Android library) และ บอกระดับการอนุญาติที่ application ต้องการจะได้
แต่งานหลัก ๆ ก็คือการประกาศ component ของ application นี่แหละ ตัวอย่างเช่น activity จะถูกประกาศแบบนี้
. . .
ส่วน service ก็ใช้ , สำหรับ broadcast receivers, สำหรับ content provider; Activities, services, และ content provider ที่ไม่ประกาศใน manifest ระบบจะมองไม่เห็น และมันก็จะทำงานไม่ได้ อย่างไรก็ตาม broadcast reveiver สามารถประกาศใน manifest หรือสร้างขึ้นมาแบบ dynamic ใน code (เป็น BroadcastReceiver object) และ register เข้ากับ system โดยเรียก Context.registerReceiver()
Intent filter
Intent object สามารถประกาศชื่อ component ได้เลยตรง ๆ ถ้าเป็นอย่างนั้น Android ก็จะหา component นั้นเจอแล้วก็ activate มันได้เลย (ตามที่เซ็ตไว้ใน manifest file) แต่ถ้าเราไม่ได้ประกาศไว้อย่างชัดเจน Android จะต้องหา component ที่จะมาตอบสนอง intent อันนั้น การที่จะทำแบบนั้นได้ มันจะที่การเปรียบเทียบ intent object อันนั้น กับ intent filters ที่เป็นไปได้ filters ของ component จะบอกให้ Android รู้ถึงชนิดของ intent ที่ component สามารถจัดการได้ เช่นเดียวกันกับข้อมูลพื้นฐานอื่นๆของ component เราจะประกาศมันไว้ใน manifest file นี่คือตัวอย่างของการเพิ่ม intent filters 2 อันไปยัง activity
. . .
filter แรกในตัวอย่าง -- action "android.intent.action.MAIN" และ categoty "android.intent.category.LAUNCHER" -- มันจะ mark activity เป็นตัว application launcher
filter ที่สองประกาศ action ที่ activity สามารถจัดการได้บน data แต่ละชนิด
component นึงมีกี่ intent filter ก็ได้ filter แต่ละตัวก็ประกาศความสามารถต่างๆกัน ถ้าไม่มี filter เลย มันก็ยังสามารถถูก activate ได้จาก intents ที่ประกาศชื่อ component อย่างชัดเจนเท่านั้น
สำหรับ broadcast receiver ที่ถูกสร้างขึ้นและ register ภายใน code, intent filter ถูกประกาศตรงๆเลยเป็น IntentFilter object ส่วน filter อื่นๆ จะต้องประกาศใน manifest
Activities and Tasks
Activity อันนึงสามารถเริ่ม activity อีกอันได้ รวมถึง activity ที่อยู่ใน application อื่น เช่นคุณอยากแสดงชื่อถนนของสถานที่หนึ่งบนแผนที่ มันมี activity ที่ทำหน้าที่อย่างนั้นอยู่แล้ว สิ่งที่คุณต้องทำก็คือ เอา Intent object กับ ข้อมูลที่จำเป็นรวมเข้าด้วยกัน แล้วผ่านมันไปยัง startActivity() ตัวแสดงแผนที่ก็จะแสดงแผนที่ จากนั้นพอ user กด back ก็กลับมาที่ activity เดิมของคุณ
สำหรับ user แล้วมันเหมือนเปิดอยู่ในโปรแกรมของคุณ แต่จริงๆแล้วมันไปเปิด application อื่น แต่ run อยู่บน application ของคุณ Android ทำให้เกิดเหตุการณ์แบบนี้ได้โดยรวม 2 activity เข้าไว้ใน Task เดียวกัน, พูดให้ง่าย ๆ Task คือสิ่งที่ user เห็นว่ามันคือ 1 application ซึ่งมันจะประกอบไปด้วยกลุ่มของ activity ที่เกี่ยวข้องกัน จัดเรียงอยู่บน stack, ถ้าอันนึงเป็น running activity, activity อันก่อนหน้าก็จะถูกวางลงบน stack พอ user กด back, activity ปัจจุบันก็ถูกดึงทิ้ง แล้วอันก่อนหน้าก็จะขึ้นมาทำงานแทน
Task อันนึงก็คือ stack ของ activity หลายๆอัน ไม่ใช่ class หรือ element ใดๆใน manifest file ดังนั้นจึงไม่มีทางที่เราจะ set ค่าของ task หนึ่งๆแยกจาก activity ได้ ค่าของ task หนึ่งๆ ที่มองเห็นได้ทั้งหมดอยู่ที่ root activity
ทุกๆ activity ใน task ทำงานร่วมกันเหมือนเป็น unit เดียวกัน, ทั้ง task (ทั้ง activity stack) สามารถถูกดึงมาด้านหน้า หรือส่งไป background ได้ เช่น task หนึ่งมี 4 activity, 3 อันกำลังทำงาน พอ user กด home-> ไปที่ application launcher และเลือก application อื่น task เก่าก็จะไปที่ background และ root activity ของ task ใหม่ก็แสดงขึ้นมา หลังจากนั้นไม่นาน user กด back กลับไปยัง home แล้วเลือก application ที่เคยเปิดครั้งแรก, task เก่าที่มี 4 activity ค้างอยู่บน stack กลับขึ้นมาข้างหน้า พอ user กด back, หน้าจอจะไม่ได้แสดง activity ที่ user เพิ่งปิดไป (ของ task ที่สอง) แต่ กลับกัน activity บนสุดของ stack ถูกลบทิ้ง และ activity ข้างล่างใน task เดียวกันจะถูกแสดงขึ้นมาแทน
สิ่งที่อธิบายไปข้างบนคือลักษณะปกติที่ activity และ task ทำงาน แต่ก็ยังมีทางที่จะแก้ไขการทำงานของมันอยู่ ความข้องเกี่ยวกันของ task และ ลักษณะการทำงานของ activity ใน task สามารถควบคุมได้โดย flag ที่ set ใน intent object ที่ start activity และ element ใน manifest จากที่กล่าวไป Intent flags คือ
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP
ส่วน attribute คือ
taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch
Affinities and new tasks
โดยปกติแล้ว activity ทุกตัวใน application มีความเกี่ยวดอง (affinity) ซึ่งกันและกัน หมายความว่า มีสิทธิพิเศษภายใน task เดียวกัน อย่างไรก็ตาม ความเกี่ยวดองโดยเฉพาะก็สามารถสร้างขึ้นเองได้ สำหรับทุก activity ด้วย attribute ชื่อ taskAffinity ใน element , Activity ต่าง application สามารถแบ่งปันความเกี่ยวดองกันได้ หรือความเกี่ยวดองใน application เดียวกันสามารถใช้ได้โดย affinity อื่นได้, affinity นี้จะถูกนำมาใช้ใน 2 สถานการณ์ 1. เมื่อ intent object ที่เริ่ม activity มี FLAG_ACTIVITY_NEW_TASK flag และเมื่อ activity มี allowTaskReparenting attribute เป็น true
The FLAG_ACTIVITY_NEW_TASK flag
ตามที่ได้อธิบายไปว่า activity โดยปกติแล้วจะเริ่มทำงานด้วยการเรียก startActivity() มันจะถูก push ขึ้นไปบน stack เดียวกับตัวเรียก อย่างไรก็ตาม ถ้า intent object ส่ง startActivity ที่มี FLAG_ACTIVITY_NEW_TASK flag ระบบจะมองหา task ใหม่ที่จะเก็บ activity ใหม่ ส่วนใหญ่แล้วจะเป็นไปตามชื่อ flag คือมันจะเป็น task ใหม่ อย่างไรก็ตามไม่จำเป็นต้องเป็นเช่นนั้น ถ้ามันมี task ที่มี affinity เดัยวกันเปิดอยู่แล้ว activity จะเปิดบน task นั้น ถ้าไม่มีมันถึงจะเปิด task ใหม่
The allowTaskReparenting attribute
ถ้า activity มี allowTaskReparenting attribute เป็น true มันสามารถเคลื่อนย้ายจาก task ที่มันเริ่ม start ไปยัง task ที่มันมี affinity เดียวกันได้เมื่อ task นั้นอยู่ข้างหน้า เช่น มี activity ที่รายงานสภาพอากาศในเมืองที่เลือกอยู่ซึ้งถูกกำหนดเป็นส่วนหนึ่งของโปรแกรมท่องเที่ยว และมันมี affinity เดียวกับอีก activity ที่อยู่บน application เดียวกัน (default affinity) และมันอนุญาติการ reparent และมี activity หนึ่งของคุณเปิด การรายงานสภาพอากาศ ที่มันเริ่มโดย task เดียวกันกับ activity ของคุณ อย่างไรก็ตามเมื่อ โปรแกรมท่องเที่ยวของคุณกลับมาอยู่ด้านหน้า การรายงานสภาพอากาศก็ถูกตั้งใหม่ให้มาอยู่ใน task นั้นแทน
ถ้า .apk file หนึ่งมีหลาย application ในมุมมองของ user คุณควรจะต้อง assign affinity ให้กับ activity ตามความสัมพันธ์ของพวกมัน
Launch modes
เป็น attribute ของ element
"standard" (the default mode)
"singleTop"
"singleTask"
"singleInstance"
1. activity ไหนตอบสนองกับ intent
2. activity สามารถมีหลาย instance ได้หรือไม่
3. instance สามารถมี activity อื่นใน task ได้มั้ย
4. instance ใหม่จะเริ่มเพื่อทำงาน intent ใหม่หรือไม่
.........................
Clearing the stack
ถ้า user ไม่ทำอะไรกับ task นานๆ ระบบจะ clear ทุกๆ activity ใน task ยกเว้น root activity เมื่อ user กลับมาที่ task อีกครั้ง มันก็จะกลับมาเหมือนเดิม ยกเว้นแต่ว่า activity แรกสุดเท่านั้นที่แสดงขึ้นมา มันเป็นไอเดียที่คิดว่ามันนานจน user ลืมสิ่งที่ตัวเองกำลังจะทำไปแล้ว และกพลังจะเริ่มทำอะไรใหม่แล้วล่ะ
ข้างบนคือ default แต่เราสามารถควบคุม activity โดย set attribute และควบคุมมันได้
1. alwaysRetainTaskState attribute ถ้าเป็น true ใน root activity, มันจะเก็บทุกๆ activity เอาไว้ไม่เหมือนแบบ default พอ user กลับมามันก็จะเป็นเหมือนเดิม
2. clearTaskOnLaunch ถ้าเป็น true ใน root activity, stack จะลบ activity ไปจนถึง root เมื่อไร่ก็ตามที่ user ออกจาก task ไม่ว่าจะแป๊บเดียวก็ตาม
3. finishOnTaskLaunch เหมือน clearTaskOnLaunch แต่มันทำบน activity ใด activity หนึ่ง ไม่ใช่กับทั้ง task คือมันสามารถลบ activity ใดๆก็ได้รวมถึง root ด้วย ถ้ามันเป็น true พอ user กลับมาอีกที activity นั้นจะหายไปแล้ว
มีอีกวิธีที่จะลบ activity ออกจาก stack, ถ้า Intent object มี FLAG_ACTIVITY_CLEAR_TOP flag และ task เป้าหมายมี instance ของ activity ที่สามารถจัดการ intent นี้ได้อยู่ใน stack, activity ทั้งหมดที่อยู่บน instance นั้นจะถูกลบออก แล้ว instance นั้นจะขึ้นมาอยู่บนสุดของ stack และตอบสนองต่อ intent นั้นแทน ถ้า launch mode คือ "standard" มันก็จะถูกลบออกจาก stack ด้วย และ instance ใหม่จะถูกสร้างขึ้นมาทำงานกับ intent ที่เข้ามาแทน เพราะ instance ใหม่จะถูกสร้างทุกครั้งสำหรับ launch mode "standard"
FLAG_ACTIVITY_CLEAR_TOP มักใช้บ่อยๆ ควบคู่กับ FLAG_ACTIVITY_NEW_TASK เมื่อใช้ร่วมกัน flag พวกนี้จะสามารถใช้เพื่อ locating activity ที่มีอยู่แล้วใน task อื่น และวางมันลงบนตำแหน่งที่มันสามารถตอบสนองต่อ intent นั้นได้
Starting tasks
activity หนึ่งจะถูก set up เป็นจุดเริ่มต้นของ task โดยใส่ filter "android.intent.action.MAIN" และ category เป็น "android.intent.category.LAUNCHER", filter แบบนี้สร้าง icon และ ชื่อของ activity แสดงในการเปิด application ทำให้ user สามารถเปิดมัน และกลับมายังมันได้หลังจากเปิดไปแล้ว
ความสามารถที่ user สามารถออกจาก task และกลับมาหามันได้อีกนั้นสำคัญ ดังนั้น "singleTask" และ "singleInstance" ซึ่งจะสร้าง task ใหม่จึงสามารถระบุได้แต่ใน activity ที่มี filter MAIN และ LAUNCHER เท่านั้น ถ้าไม่มี filter พวกนี้ แล้ว intent หนึ่งเกิด แล้ว user ใช้เวลากับ task นั้นสักพัก แล้ว user กด HOME แล้ว task นั้นก็ไปอยู่ด้านหลัง HOME screen แต่ user จะกลับไปไม่ได้อีกแล้ว เพราะมันไม่ได้อยู่ใน application launcher
เรื่องยากอีกอย่างของ FLAG_ACTIVITY_NEW_TASK ก็คือ ถ้า flag นี้ทำให้ activity เริ่ม task ใหม่ และ user กด HOME มันจะต้องมีทางที่ user สามารถกลับมายังที่เดิมได้ บาง entity เช่น notification manager จะเริ่ม activity ใน task อื่นเสมอ และจะไม่เริ่มใน task ตัวเองเด็ดขาด มันจึงส่ง FLAG_ACTIVITY_NEW_TASK ในทุกๆ intent ที่มันส่งไปยัง startActivity() ถ้าคุณมี activity ที่เรียกใช้ entity ภายนอกและต้องการใช้ flag นี้ อย่าลืมที่จะให้ user มีวิธีที่จะกลับมายังที่ที่ task เริมทำงาน
ถ้าคุณไม่อยากให้ user กลับมาได้ ให้ set ด้วย finishOnTaskLaunch เป็น true
Processes and Threads Processes
.......................
Threads
......................
Remote procedure calls
android มี remote procedure call เรียกว่า (RPCs) ซึ่ง method จะถูกเรียกแบบ local แต่ executed แบบ remote (ในอีก process) และผลลัพธ์กลับสู่ผู้เรียกใช้
.............................
การ connect ระหว่าง client และ service
- client implement onServiceConnected() และ onServiceDisconnected() method ซึ่งทำให้มีการแจ้งเตือนเมื่อสามารถเชื่อมต่อสำเร็จ และ disconnect จากนั้นมันก็เรียก bindService() เพื่อเริ่มการ connect
- method onBind() ของ service จะทำงานว่าจะ accept หรือ reject connection ตาม intent ที่มันได้รับ (intent ที่ถูกส่งให้ bindService() ) ถ้า accept มันจะ return instance ของ Stub subclass
- ถ้า service accept connection, Android จะเรียก method onServiceConnected() ของ client และส่ง IBinder object และ proxy สำหรับ Stub subclass คืนไปให้ client, client สามารถเรียก call บน service ได้ผ่าน proxy นั้น
Thread-safe methods
method ที่คุณสร้างขึ้นอาจจะถูกเรียกใช้งานได้จากหลาย thread พร้อมกัน ดังนั้นต้องเขียนขึ้นในลักษณะที่ thread-safe
โดยเฉพาะ method ที่สามารถถูกเรียกแบบ remote ................................... IBinder method ถูกเรียกจากหลาย client พร้อมกัน มันจึงต้องเขียนแบบ thread-safe
เช่นเดียวกับ ContentResolver และ ContentProvider method "query(), insert(), delete(),
Component Lifecycles
.................
Activity lifecycle
.................
void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()
Calling into the superclass
การแก้ไข method ที่เกี่ยวกับ activity lifecycle method ควรต้องเรียก method ของ superclass ก่อน เช่น
protected void onPause() {
super.onPause();
. . .
}
ทั้ง 7 method ที่กำหนด lifecycle ทั้งหมดของ activity หนึ่งๆ มันจะมีอยู่ 3 loop ที่คุณจะต้องตรวจสอบเพื่อใช้งานมันได้
1. entire lifetime อยู่ระหว่าง onCreate() จนถึง onDestroy(), activity จะทำการ initial setup ของ global ที่ onCreate() และ release resource ทั้งหมดที่ onDestroy() เช่น มี thread หนึ่ง ดาวน์โหลดข้อมูลจาก network, มันจะสร้าง thread นั้นที่ onCreate และหยุด thread นั้นที่ onDestroy()
2. visible lifetime เกิดขึ้นระหว่าง onStart() จนถึง onStop() ระหว่างช่วงเวลานั้น user จะเห็น activity บนจอภาพ, แม้มันอาจจะไม่ได้อยู่บนสุด หรือสามารถตอบสนองได้, ในระหว่าง 2 method นี้ คุณสามารถจัดการกับ resource ที่จำเป็นที่จะใช้แสดง activity ให้ user เห็นได้ เช่น คุณสามารถ register BroadcastReceiver ที่ onStart() เพื่อ monitor การเปลี่ยนแปลงที่กระทำต่อ UI ของคุณ และ unregister มันที่ onStop() เมื่อ user มองไม่เห็นสิ่งที่คุณแสดงอีกแล้ว onStart() และ onStop() สามารถถูกเรียกได้หลายครั้ง เปรียบได้กับ activity ต่างๆ ที่ผลัดกันระหว่าง visible กับ hidden แสดงให้ user มองเห็น
3. foreground lifetime อยู่ระหว่าง onResume() จนถึง onPause() ระหว่างเวลานี้ activity จะอยู่หน้าสุดของ activity อื่นๆ และจะตอบสนองกับ user, ปกติแล้ว activity มักจะสามารถสลับระหว่าง resumed และ paused ได้บ่อยๆ เช่น onPause() ถูกเรียกเมื่อ มือถือ sleep หรือเมื่อ activity ใหม่เริ่มทำงาน, onResume() ถูกเรียกเมื่อ ผลของ activity หรือ intent ใหม่ถูกส่งเข้ามา ดังนั้น code ใน 2 method นี้ควรจะ lightweight
รูปต่อไปนี้แสดง loop และ path ของ activity, ที่เป็นรูปวงรีแสดง major state ที่ activity ทำงาน ส่วนสี่เหลี่ยมแสดง callback method ที่คุณสามารถ implement มันได้ เมื่อ activity เปลี่ยน state
ตาราง method
onCreate() เรียกเมื่อ activity ถูกเรียกครั้งแรก ที่นี่คุณควรทำ static set up ทั้งหมด เช่น สร้าง views, bind data to list, และอื่นๆ เราสามารถส่ง object ของ state ของ activity ก่อนหน้ามาที่ method นี้ได้
onRestart() เรียกเมื่อ activity ถูกหยุดไปครั้งก่อน จากนั้นถูกเปิดอีกครั้ง
onStart() ถูกเรียกเมื่อ activity ขึ้นมาให้ user ได้เห็น ไปต่อ onResume() เมื่อ activity ขึ้นมาอยู่หน้าสุด หรือ onStop() ถ้ามัน hidden
onResume() ถูกเรียกก่อนที่ activity จะเริ่มตอบสนองกับ user, ณ จุดนี้ activity จะอยู่บนสุดของ stack และรับ user input ไปต่อ onPause()
onPause() ถูกเรียกเมื่อระบบจะ resume activity อื่น, ปกติแล้ว method นี้จะถูกใช้เพื่อ commit การเปลี่ยนแปลงที่ไม่ได้ save ไว้เพื่อ persistent ข้อมูล, หยุด animations และสิ่งอื่นๆ ที่จะกิน CPU และ resource, และมันควรทำทุกอย่างด้วยความรวดเร็ว เพราะ activity อื่นจะไม่เปิดขึ้นมาจนกระทั่ง method นี้ return ไปต่อ onResume() ถ้ากลับมาข้างหน้า หรือ onStop() ถ้า user มองไม่เห็นอีกแล้ว
onStop() ถูกเรียกเมื่อ activity ไม่สามารถมองเห็นได้โดย user อีก อาจจะเพราะกำลังถูก destroy หรือเพราะ activity อื่น (ไม่ว่ามีอยู่แล้วหรือสร้างใหม่) ถูกเปิดขึ้นมาแล้วกำลังจะ cover มันหมด ไปต่อ onRestart() ถ้ามันกลับมาตอบสนองกับ user หรือ onDestroy() เมื่อ activity จะจบลง
onDestroy() ถูกเรียกก่อนที่ activity จะถูกทำลาย นี่เป็นการเรียกครั้งสุดท้ายที่ activity จะได้รับ อาจจะเพราะ activity เสร็จสิ้น (มีการเรียก finish() บนมัน) หรือเพราะระบบต้องการ destroy instance ของ activity นี้ชั่วคราวเพื่อต้องการพื้นที่ คุณสามารถแยกระหว่างการปิด 2 แบบนี้ได้ด้วย isFinishing()
Note! Killable - No, No, No, No, Yes, Yes, Yes
Killable บอกว่าระบบสามารถ kill process ที่ host activity "ได้ตลอดเวลาหลังจาก method return, โดยไม่ต้อง execute code อื่นๆของ activity อีก", onPause(), onStop(), onDestroy() ถูก mark ว่า Yes เพราะ onPause() เป็น method แรกที่สามารถการันตีว่าจะถูกเรียกก่อนที่ process จะถูก kill, และคุณสามารถ write ข้อมูลที่ persistent (เช่น user edit) ลงบนหน่วยความจำได้ทัน ซึ่ง onStop() และ onDestoy() ก็เช่นเดียวกัน แต่ 2 อันหลังไม่สามารถการันตีได้ คุณจึงควร save งานที่ onPause()
No ที่ Killable ป้องกัน process จากการที่ activity ถูก kill ในระหว่างที่กำลังถูกเรียก หรือระหว่างกำลังทำงาน ดังนั้น activity ที่ตอนแรกอยู่ที่ onPause() แล้วถูกเรียก onResume() จะไม่สามารถถูก kill ได้จนกว่าจะถึง onPause() อีกครั้ง
แต่อย่างไรก็ตาม activity ที่ไม่สามารถถูก kill ได้ในทางเทคนิค ก็ยังสามารถ kill ได้โดยระบบ แต่จะเกิดในกรณีเฉพาะจริงๆ และเหตุการณ์ที่ไม่มี resource อื่นให้ใช้งานอีกแล้วเท่านั้น
Saving activity state
เมื่อระบบ shut down activity อัตโนมัติเพื่อขอ memory โดยไม่ได้มาจากความต้องการของ user, user ก็จะต้องสามารถกลับไปยัง activity ก่อนหน้าได้
เพื่อจับ state ก่อนหน้าก่อนที่ activity จะโดน kill คุณสามารถ implement method ชื่อ onSaveInstanceState() เพื่อ activity นั้นได้, Android จะเรียก method นี้ก่อนที่จะทำให้ activity สามารถ destroy ได้ นั่นคือ ก่อนที่ onPause() จะถูกเรียก มันจะส่ง Bundle object ที่คุณสามารถบันทึก dynamic state ของ activity เป็นแบบคู่ของ name-value ไว้ได้ เมื่อ activity จะเริ่มทำงานอีกครั้ง Bundle นี้จะถูกส่งมาที่ onCreate() และ method ที่ถูกเรียก หลัง onStart(), onRestoreInstanceState() ดังนั้น method อันใดอันนึงหรือทั้งคู่สามารถกลับไปสร้าง state เดิมได้
ต่างจาก onPause() และ method อื่นๆข้างบน, onSaveInstanceState() และ onRestoreInstanceState() ไม่ใช่ lifecycle method มันไม่ได้ถูกเรียกทุกครั้ง เช่น Android จะเรียก onSaveInstanceState() ก่อนที่ activity จะสามารถถูก destroy โดยระบบได้ แต่จะไม่เรียกเมื่อ จะถูก destroy โดยการกระทำของ user เช่น กด BACK ในกรณีนี้ user ไม่ต้องการกลับไป activity นั้นอีกจึงไม่มีเหตุผลที่ต้อง save state
เพราะ onSaveInstanceState() ไม่ได้ถูกเรียกทุกครั้ง, คุณควรใช้มันเพื่อการบันทึก state ชั่วคราวไม่ใช่ บันทึก persistent data, แต่ให้ใช้ onPause() แทนเพื่อการนั้น
Coordinating activities
เมื่อ activity หนึ่งเรียกอีก activity หนึ่งมันทั้งคู่จะเจอการเปลี่ยน lifecycle, อันนึง pause และอาจจะ stop อีกอัน start ในกรณีนี้คุณอาจจำเป็นจะต้อง ให้มันประสานงานกันจากอันนึงไปอีกอันนึง
ลำดับของ lifecycle callback ถูกกำหนดไว้อย่างดี โดยเฉพาะเมื่อทั้งสอง activity อยู่บน process เดียวกัน
1. activity แรกเรียก onPause()
2. activity สองเรียก onCreate(), onStart() และ onResume()
3. เมื่อ activity สองไม่สามารถมองเห็นได้จากจอแล้วจะถูกเรียก onStop()
Service lifecycle
service สามารถถูกใช้ได้ 2 ทาง
1. start และทำงานจนกระทั่งมีคนไป stop หรือมันหยุดตัวเอง ถ้าแบบนี้มันจะเริ่มด้วย Context.startService() และหยุดด้วย Context.stopService() หรือหยุดตัวเองโดย Service.stopSelf() หรือ Service.stopSelfResult, แค่ stopService() อันนเดียวก็พอที่จะถูกเรียกในการหยุด service หนึ่งๆ ไม่ว่าจะถูกเรียก startService() กี่ครั้ง
2. ทำงานแบบสามารถโปรแกรมได้โดยใช้ interface ที่มัน define และ export, Clients จะสร้าง connection ไปยัง object ของ Service object และใช้ connection นั้นเรียกไปยัง service การสร้าง connection โดยเรียก Context.bindService() และปิดโดย Context.unbindService() หลาย client สามารถ bind ไปยัง service เดียวกัน ถ้า service ยังไม่ทำงาน bindService() สามารถสั่งให้มันทำงานได้
2 mode นี้ไม่ได้แยกจากกันโดยสิ้นเชิง คุณสามารถ bind service ที่เริ่มโดย startService() ได้ เช่น เล่นเพลงด้วยการเรียก startService() ด้วย intent object ที่บอกให้เล่นเพลง แล้วซักพัก user อยากควบคุม หรือรู้รายละเอียดของเพลง ก็จะมี activity มาสร้าง connection กับ service ด้วย bindService() ในกรณีนี้ stopService() จะไม่สามารถหยุด service ได้จริงๆ จนกว่าการ bind ครั้งสุดท้ายจะ close
เช่นเดียวกับ activity, service ก็มี lifecycle แต่มีแค่ 3 อัน
void onCreate()
void onStart(Intent intent)
void onDestroy()
มี 2 loop ที่จะ implement service ได้
1. entire lifetime อยู่ในระหว่าง onCreate() และ return ของ onDestroy() เช่นเดียวกับ activity มันจะทำ set up ครั้งแรกที่ onCreate() และปล่อย resource ทั้งหมดที่ onDestroy() ตัวอย่างเช่น service ที่ใช้เล่นเพลง จะสร้าง thread ไว้เล่นเพลงที่ onCreate()
2. active lifetime อยู่หลัง onStart()
standard และ singleTop เป็นตัวเริ่ม intent startActivity() ส่วน singleTask และ singleInstance เป็น root ของ task เสมอและไม่สามารถเปิดได้จาก task อื่น
standard และ singleTop สามารถมีหลาย instance ได้
singleInstance และ singleTask เป็น activity ที่อยู่บน task เดียวเท่านั้น ถ้ามันไปเปิด activity อื่น มันจะไปเปิด task อื่น
standard จะมี instance ใหม่เกิดขึ้นทุก ๆ intent แต่ละ instance จัดการแค่ intent เดียว สำหรับ singleTop, instance ที่มีอยู่แล้วจะถูกใช้จัดการ intent ใหม่ถ้ามันอยู่บนสุดของ stack ถ้าไม่ก็สร้าง instance ใหม่อยู่ดี

ป้ายกำกับ:
Android
State Change
import android.app.Activity; import android.os.Bundle; public class MyActivity extends Activity { // Called at the start of the full lifetime. @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); // Initialize activity. } // Called after onCreate has finished, use to restore UI state @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // Restore UI state from the savedInstanceState. // This bundle has also been passed to onCreate. } // Called before subsequent visible lifetimes // for an activity process. @Override public void onRestart(){ super.onRestart(); // Load changes knowing that the activity has already // been visible within this process. } // Called at the start of the visible lifetime. @Override public void onStart(){ super.onStart(); // Apply any required UI change now that the Activity is visible. } // Called at the start of the active lifetime. @Override public void onResume(){ super.onResume(); // Resume any paused UI updates, threads, or processes required // by the activity but suspended when it was inactive. } // Called to save UI state changes at the // end of the active lifecycle. @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Save UI state changes to the savedInstanceState. // This bundle will be passed to onCreate if the process is // killed and restarted. super.onSaveInstanceState(savedInstanceState); } // Called at the end of the active lifetime. @Override public void onPause(){ // Suspend UI updates, threads, or CPU intensive processes // that don’t need to be updated when the Activity isn’t // the active foreground activity. super.onPause(); } // Called at the end of the visible lifetime. @Override public void onStop(){ // Suspend remaining UI updates, threads, or processing // that aren’t required when the Activity isn’t visible. // Persist all edits or state changes // as after this call the process is likely to be killed. super.onStop(); } // Called at the end of the full lifetime. @Override public void onDestroy(){ // Clean up any resources including ending threads, // closing database connections etc. super.onDestroy(); } }
ป้ายกำกับ:
Android
Activity States
การเปลี่ยน state ของ Activity ใน stack
- Active อยู่บนสุดของ stack
- Paused อาจจะมองเห็นอยู่ แต่ไม่ได้ถูก focus จะเกิดตอนที่มี transparent หรือ non-fullscreen อยู่ข้างบน แต่ Activity ยังถือว่า Active อยู่ แต่จะไม่รับ user input event
- Stopped ไม่เห็น Activity นั้นอีกแล้ว แต่มันจะยังคงอยู่ใน memory จนกว่า Android จะเคลียร์ทิ้ง ดังนั้นควรจะ save ข้อมูล และ UI ปัจจุบันเอาไว้ด้วย เวลากลับมาจะได้กลับมาหน้าเดิม
- Inactive หมายถึงโดน kill process ไปแล้ว การจะเปิดอีกครั้งต้อง restart application เท่านั้น
ป้ายกำกับ:
Android
Creating Resource for Different Language and Hardware
ในโฟลเดอร์ res/ สามารถกำหนดภาษา, สถานที่, ลักษณะของจอ ฯลฯ ได้โดย
สร้างโฟลเดอร์เพิ่ม เช่น
Project/ res/ values/ strings.xml values-fr/ strings.xml values-fr-rCA/ strings.xmlและสามารถปรับแต่ง resource ได้อีกหลายอย่าง คือ
- Language ใช้ISO 639-1 ที่เป็นตัวย่อ 2 ตัวอักษร เป็นตัวอักษรตัวเล็ก เช่น en, th
- Region ใช้ "r" ตัวเล็ก ตามด้วยตัวอักษรใหญ่ 2 ตัว ISO 3166-1-alpha-2 เช่น rUS, rGB
- Screen Orientation มี 3 อย่างคือ port (แนวตั้ง), land(แนวนอน), square(สี่เหลี่ยม)
- Screen Pixel Density pixel ต่อนิ้ว เช่น 92dpi, 108dpi
- Touchscreen Type มี nothouch, stylus, finger
- Keyboard Availability มี keysexposed, keyhidden
- Keyboard Input Type มี nokeys, qwerty, 12key
- UI Navigation Type มี notouch, dpad, trackball และ wheel
- Screen Resolution เช่น 320x240
drawable-en-rUS drawable-en-keyshidden drawable-land-notouch-nokeys-320x240 ถ้าแบบนี้จะผิด X drawable-rUS-en (ไม่เรียง) X drawable-rUS-rUK (ซ้ำ)Runtime Confi guration Changes ปกติจะเปลี่ยน config พวกนี้ต้องปิดโปรแกรมแล้วเปิดใหม่ แต่ Android สามารถเปลี่ยน config พวกนี้ได้ในระหว่าง run time คือพอ user พลิกมือถือ หรือ เลื่อนคีย์บอร์ดออกมา ก็เปลี่ยนรูปแบบ แต่ต้องกำหนดไว้ใน manifest file โดยเพิ่ม android:configChange เข้าไป สิ่งที่จะเปลี่ยนได้ก็คือ
- orientation แนวตั้ง แนวนอน
- keyboardHidden แสดงคีย์บอร์ดหรือซ่อน
- fontScale ขนาดฟอนท์
- locale ภาษา
- keyboard เช่น 12ปุ่มของโทรศัพท์เปลี่ยนเป็นคีย์บอร์ด
- touchscreen หรือ navigation ประเภทของ keyboard หรือ navigation
<activity name=".MyActivity" label="@string/app_name" configchanges="orientation|keyboard"> </activity>พอมีการเปลี่ยนแปลง มันจะไปเรียก method ชื่อ onConfigurationChanged ใน Activity เราต้อง override method นี้ โดยรับ object ของ Configuration ที่จะบอกค่า configuration ใหม่มาให้ อย่าลืมเรียก super class และ เรียก resource ให้ครบ
@Override public void onConfigurationChanged(Configuration _newConfig) { super.onConfigurationChanged(_newConfig); [ ... Update any UI based on resource values ... ] if (_newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) { [ ... React to different orientation ... ] } if (_newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) { [ ... React to changed keyboard visibility ... ] } }
ป้ายกำกับ:
Android
สมัครสมาชิก:
บทความ (Atom)