Bài 5 – Android: hướng dẫn load dữ liệu từ resource

Resources là gì?

  • Là các tệp và nội dung tĩnh được tải trực tiếp vào package: bitmaps, layouts, strings, themes , styles, animations…
  • Đặt resources trong các thư mục con nằm trong thư mục res
  • Truy cập tới resources thông qua IDs của nó

Cách load resource thông qua code

// Read data directly from resource CharSequence[] productBasePrices; Resources res = getResources();
// base_prices is array of string which defined in strings.xml productBasePrices = res.getTextArray(R.array.base_prices);

Các phương thức để load Resources object:

  • getBoolean() // lấy resource kiểu boolean
  • getDrawable() // lấy resource kiểu drawable (images)
  • getInteger() // lấy resource kiểu int
  • getText() // lấy resource kiểu string
  • getTextArray() // lấy resource kiểu array

Trong ví dụ sau đây tôi sẽ hướng dẫn mọi người thực hiện theo kịch bản

  • Danh sách product gồm: tên, giá, mô tả… được lưu trên resources
  • Load lên và hiển thị danh sách tên product ở tab Catalog

Bước 1: thêm vào trong res/values/strings.xml các string-array sau (nằm trong thẻ

  • Các category của product

 

<string-array name="product_category_options">
    <item>Saws</item>
    <item>Wrenches</item>
    <item>Pliers</item>
    <item>Hammers</item>
    <item>Screwdrivers</item>
    <item>Files and Chisels</item>
    <item>Planers</item>
    <item>Measuring Tools</item>
    <item>Miscellaneous</item>
</string-array>
  • Danh sách product
<string-array name="product_names">
    <item>Chainsaw</item>
    <item>Circular Saw</item>
    <item>Hacksaw</item>
    <item>Hand Saw</item>
    <item>Jigsaw</item>
    <item>Adjustable Wrench</item>
    <item>Open-End Wrench</item>
    <item>Pipe Wrench</item>
    <item>Combination Pliers</item>
    <item>Crimping Pliers</item>
    <item>Diagonal Pliers</item>
    <item>Tongue-and-Groove Pliers</item>
    <item>Machinist\'s Hammer</item>
    <item>Claw Hammer</item>
    <item>Rubber Mallet</item>
    <item>Flat-Head Screwdriver (Large)</item>
    <item>Flat-Head Screwdriver (Small)</item>
    <item>Phillips-Head Screwdriver (Large)</item>
    <item>Phillips-Head Screwdriver (Small)</item>
    <item>Flat File</item>
    <item>Round File</item>
    <item>Hand Chisel</item>
    <item>Power Chisel</item>
    <item>Hand Planer</item>
    <item>Power Planer</item>
    <item>Level</item>
    <item>Square</item>
    <item>Tape Measure</item>
    <item>Hand Axe</item>
    <item>Drill</item>
    <item>Gloves</item>
    <item>Paint Roller</item>
    <item>Scissors</item>
    <item>Toolbox</item>
    <item>Utility Knife</item>
</string-array>
  • Danh sách mapping product với category nào
<string-array name="product_categories">
    <item>Saws</item>
    <item>Saws</item>
    <item>Saws</item>
    <item>Saws</item>
    <item>Saws</item>
    <item>Wrenches</item>
    <item>Wrenches</item>
    <item>Wrenches</item>
    <item>Pliers</item>
    <item>Pliers</item>
    <item>Pliers</item>
    <item>Pliers</item>
    <item>Hammers</item>
    <item>Hammers</item>
    <item>Hammers</item>
    <item>Screwdrivers</item>
    <item>Screwdrivers</item>
    <item>Screwdrivers</item>
    <item>Screwdrivers</item>
    <item>Files and Chisels</item>
    <item>Files and Chisels</item>
    <item>Files and Chisels</item>
    <item>Files and Chisels</item>
    <item>Planers</item>
    <item>Planers</item>
    <item>Measuring Tools</item>
    <item>Measuring Tools</item>
    <item>Measuring Tools</item>
    <item>Miscellaneous</item>
    <item>Miscellaneous</item>
    <item>Miscellaneous</item>
    <item>Miscellaneous</item>
    <item>Miscellaneous</item>
    <item>Miscellaneous</item>
    <item>Miscellaneous</item>
</string-array>
  • Danh sách images, description và price của product
<string-array name="product_images">
    <item>chainsaw</item>
    <item>circular_saw</item>
    <item>hacksaw</item>
    <item>hand_saw</item>
    <item>jigsaw</item>
    <item>adjustable_wrench</item>
    <item>open_end_wrench</item>
    <item>pipe_wrench</item>
    <item>combination_pliers</item>
    <item>crimping_pliers</item>
    <item>diagonal_pliers</item>
    <item>tongue_and_groove_pliers</item>
    <item>machinists_hammer</item>
    <item>claw_hammer</item>
    <item>rubber_mallet</item>
    <item>screwdriver_flat_lg</item>
    <item>screwdriver_flat_sm</item>
    <item>screwdriver_phillips_lg</item>
    <item>screwdriver_phillips_sm</item>
    <item>flat_file</item>
    <item>round_file</item>
    <item>hand_chisel</item>
    <item>power_chisel</item>
    <item>hand_planer</item>
    <item>power_planer</item>
    <item>level</item>
    <item>square</item>
    <item>tape_measure</item>
    <item>axe</item>
    <item>drill</item>
    <item>gloves</item>
    <item>paint_roller</item>
    <item>scissors</item>
    <item>toolbox</item>
    <item>utility_knife</item>
</string-array>

<string-array name="product_descriptions">
    <item>This gas-powered chainsaw is perfect for limbing and other light-duty work. It features a 16\" steel guide bar and an automatic chain oiler. Its ergonomic design makes it easy to maneuver and comfortable to operate for extended periods of time.</item>
    <item>This lightweight 7-1/4\" circular saw makes wood cutting a breeze! The high-accuracy laser beam guide will keep your cuts straight and true, while the integrated dust blower will clear your cutting area of debris. Although designed to be compact, this saw features a powerful 5,000 RPM motor with a maximum of 2,000 watts output.</item>
    <item>This is the kind of precision hacksaw that every woodworker needs in their toolkit. The saw\'s 12\" steel blade is held at high tension, ensuring that your cuts are always on target. The handle grip makes operating the saw hassle free, while at the same time preventing your hand from slipping.</item>
    <item>This 15\" hand saw has been an old standby ever since it was introduced into our catalog decades ago. Recent modifications have increased its sharpness by a factor of 60%, giving you that much-needed edge without compromising its legendary durability. Like all of our handheld saws, this one features a handle grip that improves both comfort and safety.</item>
    <item>Our powered jigsaw is ideal for any woodworker who needs to cut precise straight lines. Adjusting speeds on-the-fly is simple\u2014the saw works for you, not the other way around! The frame is sturdy and enables you easily swap out new blades when needed.</item>
    <item>This is an 8\" wrench made of stainless steel that belongs in every home, not just woodworking enthusiasts. Its jaw width is easily adjustable and can grip a wide variety of nuts, bolts, and other fasteners.</item>
    <item>This double-ended wrench features a 5/16 x 3/8\" opening on one end, and a 7/16 x 1/2\" opening on the other. A chromium-vanadium steel alloy has made our wrenches the most durable on the market for years.</item>
    <item>This 14\" heavy-duty pipe wrench features carbon steel jaws and a strong iron handle. The adjustable jaws support a wide range of fastener sizes\u2014all the way up to 1-3/4\". Its unique teeth design guarantees a non-slip grip even on smooth surfaces.</item>
    <item>Our combination pliers are great for any job that requires cutting wires and cables. The teeth provide enough torque to cut through thick cable, and the needle nose tip is excellent for precision cuts. The pliers\' ergonomic design makes operating the tool easy and comfortable.</item>
    <item>When you need to fold a wire instead of cut it, our crimping pliers are the right tool for the job. The stainless steel jaws feature a unique teeth design that maximizes pivoting, enabling you to easily manage stranded wire.</item>
    <item>These ultra-sharp pliers are perfect for slicing right through wires made of copper, brass, steel, and more. Their lightweight and comfortable handle enables you to cut wires quickly without straining your hand.</item>
    <item>The adjustable jaws on these pliers are made of a carbon steel alloy that is tough and minimizes slippage. These pliers are perfect for applying torque to any number of fasteners, and excel at gripping irregularly shaped objects.</item>
    <item>This 12-ounce machinist\'s hammer is designed to absorb vibrations during impact, minimizing discomfort. The head is made of a carbon steel alloy and is perfect for working strong materials, while the rubber grip ensures that your hand will never slip during use.</item>
    <item>Our no-frills claw hammer has been a customer favorite ever since it was the first item to be put up for sale in our store decades ago. This 16-ounce hammer features a heat-treated stainless steel head and a shock-absorbing hardwood handle.</item>
    <item>This 16-ounce mallet features a solid rubber head that provides a durable, yet softened strike to any number of surfaces. The hardwood handle is designed to be held comfortably with one or two hands, and absorbs the shock of repeated and forceful strikes.</item>
    <item>This 3/16\" flat-head screwdriver features a long, narrow body for an improved reach. The blade is a stainless steel alloy with a hardened tip that will fit any flat-head screw, even ones that have been stripped. Its soft-grip handle will prevent slippage no matter how much pressure is applied.</item>
    <item>This 1/4\" flat-head screwdriver features a small, stubby body for easy maneuverability and portability. The blade is a stainless steel alloy with a hardened tip that will fit any flat-head screw, even ones that have been stripped. Its soft-grip handle will prevent slippage no matter how much pressure is applied.</item>
    <item>This #2 Phillips-head screwdriver features a long, narrow body for an improved reach. The blade is a stainless steel alloy with a hardened tip that will fit any Phillips-head screw, even ones that have been stripped. Its soft-grip handle will prevent slippage no matter how much pressure is applied.</item>
    <item>This #3 Phillips-head screwdriver features a small, stubby body for easy maneuverability and portability. The blade is a stainless steel alloy with a hardened tip that will fit any Phillips-head screw, even ones that have been stripped. Its soft-grip handle will prevent slippage no matter how much pressure is applied.</item>
    <item>This 6\" flat file is great for any job that requires removing fine amounts of wood, metal, and other surfaces. The blade is a carbon steel alloy with sharpened teeth for extra durability and dependability. Its fiberglass handle is contoured for maximum grip.</item>
    <item>This 6\" round file is great for any job that requires removing scalloped edges from wood, metal, and other surfaces. The blade is a carbon steel alloy with sharpened teeth for extra durability and dependability. Its fiberglass handle is contoured for maximum grip.</item>
    <item>Our hand chisel features an incredibly sharp carbon steel alloy that will retain its edge even in the most extreme circumstances. The blade itself is 1-1/4\" wide and 5-1/2\" long. The handle is a soft fiberglass that provides a sure grip and comfortable operation.</item>
    <item>This air-powered chisel is ideal for intense carving work that a hand chisel can\'t keep up with. The chromium-vanadium alloy blade is among our sharpest ever, cutting through even the most hardened of surfaces. This unit is rated at 12,500 cuts per minute, yet remains completely stable throughout operation.</item>
    <item>Our adjustable hand planer features an ultra-sharp 2\" cutter, perfect for stripping and shaping any type of wood. The cutter is tempered for increased durability, lasting years even with heavy usage. For precise control, the cutter can be easily adjusted for both alignment and depth.</item>
    <item>Our powered planer is a precision machine that can smooth any wooden surface quickly and easily. It has a speed of 17,000 RPMs and features a 6 amp motor. Depth adjustment and alignment are simple with the calibration knob.</item>
    <item>This level guarantees a high degree of accuracy when straight lines are a must. The horizontal, vertical, and diagonal bubbles are fine-tuned to maximize their sensitivity. The body is a non-abrasive aluminum that won\'t damage even the softest of woods or other surfaces.</item>
    <item>This square features a 11\" blade made of hardened wood and a 7\" tongue made of stainless steel. It is ideal for working with straight edges, but the blade also features an inch and centimeter ruler for accurate measurement.</item>
    <item>This 30\' tape measure includes a 1-1/4\" tape rule with metal clip. The locking mechanism ensures that the tape rule remains steady even when exposed to vigorous movement. The tempered spring supports a smooth, gradual recoil action.</item>
    <item>This 14\" axe is perfect for light-duty wood chopping. It features an ultra-sharp tempered steel edge that won\'t dull under continued use. The handle is a comfortable, grip-resistant fiberglass material designed to absorb impact vibrations.</item>
    <item>Our cordless drill features an adjustable RPM range up to 1,500, ensuring that the right amount of force is applied to the situation. Its ergonomic design and lightweight frame helps to maximize user comfort while minimizing strain. Comes with two USB-rechargeable batteries.</item>
    <item>These work gloves are made from an ultra-grip nylon polymer that is resistant to tears, punctures, and other damage. The inside is soft, comfortable, and keeps the hand cooled with room to breathe. One size fits all.</item>
    <item>This 9\" paint roller package comes with both frame and cover. The heavy-duty frame is a 6-wire design that ensures smooth, yet sturdy application on any surface. At the bottom of the frame is a threaded grip to accommodate an extension pole. The included cover is made of a consistent polyester.</item>
    <item>These 8\" titanium-bonded heavy-duty scissors can easily cut through upholstery, thick rubber, and many other tough materials. The handle is designed to accommodate any size and shape of fingers without losing its grip.</item>
    <item>This 16\" portable toolbox is made of a lightweight plastic polymer that keeps the inside of the box insulated from debris and water leakage. The handle makes toting the toolbox with one hand easy, and the steel latches and hinges keep it secure. Inside of the toolbox is a removable tray to help keep tools organized.</item>
    <item>This retractable utility knife features a sharp carbon steel blade that is great for cutting drywall, thin strips of wood, and much more. The blade is housed in the handle when not in use, and is easy to extend when needed. The nose has an interlocking mechanism for keeping the blade secure.</item>
</string-array>

<string-array name="product_prices">
    <item>$105.95</item>
    <item>$74.99</item>
    <item>$19.99</item>
    <item>$17.75</item>
    <item>$89.95</item>
    <item>$9.95</item>
    <item>$4.45</item>
    <item>$17.75</item>
    <item>$22.25</item>
    <item>$11.95</item>
    <item>$8.85</item>
    <item>$14.45</item>
    <item>$9.95</item>
    <item>$8.49</item>
    <item>$6.99</item>
    <item>$1.99</item>
    <item>$1.25</item>
    <item>$1.99</item>
    <item>$1.25</item>
    <item>$3.55</item>
    <item>$3.55</item>
    <item>$10.99</item>
    <item>$145.55</item>
    <item>$31.99</item>
    <item>$160.55</item>
    <item>$5.25</item>
    <item>$7.75</item>
    <item>$8.99</item>
    <item>$20.99</item>
    <item>$80.15</item>
    <item>$6.65</item>
    <item>$12.25</item>
    <item>$9.95</item>
    <item>$26.99</item>
    <item>$9.95</item>
</string-array>
  • Giao diện của tab Catalog đơn giản chỉ chứa một list view để load dữ liệu danh sách product lên
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ourcompany.catalog.CatalogFragment">

    <!-- TODO: Update blank fragment layout -->
    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/productList"
        android:layout_gravity="center_vertical|top">

    </ListView>

</FrameLayout>
  • Bước tiếp theo chúng ta viết code để đọc dữ liệu từ strings.xml resource lên và nạp vào list view. Khai báo các biến trong class CatalogFragment để chứa dữ liệu
// Parallel arrays to hold prouct data for quick lookup
CharSequence[] productNames;
CharSequence[] productDescriptions;
CharSequence[] productCategories;
CharSequence[] productPrices;
CharSequence[] productImages;
  • Trong hàm onCreateView của CatalogFragment, thực hiện load dữ liệu từ strings resource lên
// Get Product data from resources
Resources res = getResources();
productNames = res.getStringArray(R.array.product_names);
productCategories = res.getStringArray(R.array.product_categories);
productDescriptions = res.getStringArray(R.array.product_descriptions);
productPrices = res.getStringArray(R.array.product_prices);
productImages = res.getStringArray(R.array.product_images);
  • Sau khi load dữ liệu, chúng ta tham chiếu lại list view và đưa dữ liệu vào list view bằng cách tạo một ArrayAdapter cho nó.
// Reference to ListView
ListView productListView = (ListView) view.findViewById(R.id.productList);

ArrayAdapter<CharSequence> productListAdapter = ArrayAdapter.createFromResource(view.getContext(),
        R.array.product_names, android.R.layout.simple_list_item_1);
productListView.setAdapter(productListAdapter);
  • Ở ví dụ này để cho đơn giản tôi chỉ lựa chọn xây dựng ArrayAdapter là mảng chuỗi, và lựa chọn layout cho các phần tử trên list dạng mặc định simple_list_item_1.
  • Các bạn build và chạy thử chương trình thành công sẽ load lên tab Catalog của ứng dụng danh sách các product

Chúc các bạn thành công!

Advertisements

Bài 4: Navigation giữa các Acitivities trong Android

1. Cơ chế Stack – based Navigation trong Android

Screen Shot 2018-06-10 at 7.45.50 AM

2. Phương thức Navigation tới Activity khác

  • Internal: Activity trong cùng Module
    // Khởi tạo Intent và điều hướng sang Product Activity
    
    Intent i = new Intent(“.ProductActivity”);
    // Hoặc khởi tạo Intent từ class
    Intent I = new Intent(getContext(), ProductActivity.class)
    
    startActivity(i);
  • External: Gọi Activity của hệ thống
    // Gọi ứng dụng phone để quay số
    Intent phoneIntent = new Intent(Intent.ACTION_DIAL); 
    phoneIntent.setData(Uri.parse(“tel:”+”+84 97 595 1910”)); 
    if(phoneIntent.resolveActivity(getPackageManager()) != null){
         startActivity(phoneIntent);
    }
    
    // Gọi ứng dụng Google Maps thông qua package name
    Uri intentUri = Uri.parse("geo:43.095, -77.5736?Z=20");
    Intent mapIntent = new Intent(Intent.ACTION_VIEW, intentUri);
    mapIntent.setPackage("com.google.android.apps.maps");
    startActivity(mapIntent);
  • Implicit Intent vs Explicit Intent
    • Explicit Intent: chính là các internal intent, chỉ sử dụng trong nội bộ ứng dụng
    • Implicit Intent: chính là external intent, sử dụng để thực hiện các action bên ngoài, như gửi email, thực hiện phone call…
    • Các activities có thể bị giả mạo intent >> Các ứng dụng độc hại khởi chạy 1 activity ở ứng dụng khác bởi việc giả mạo intent.
    • Mặc định explicit intent filter sẽ thiết lập thuộc tính android:exportedtrue >> Có nghĩa là bất kỳ app nào có thể gọi activity này nếu biết được đầy đủ tên của Activity đó (ex: com.ourcompany.catalog.NewsActivity)
    • Nếu ứng dụng chỉ cần các internal intent hoặc có Activity xử lý các dữ liệu nhạy cảm (sensitive information) thì phải đảm bảo intent filter của activity đó có thuộc tính android:exportedfalse

3. Các loại Common Intent

Screen Shot 2018-06-10 at 7.51.22 AM

4. Truyền dữ liệu giữa các Acitivty thông qua Intent Extras

  • Trước khi khởi chạy activity có thể truyền thêm dữ liệu cho activity thông qua phương thức putExtra()
    // Gửi thêm dữ liệu trước khi chạy activity
    Intent i = new Intent(“.CatalogDetailActivity”);
    i.putExtra(“price”, selectedPrice);
    startActivity(i)
    
    
    // Lấy thông tin về giá của sản phẩm khi CatalogDetailActivity được khởi chạy
    
    Intent i = getIntent();
    String productPrice = i.getExtras().getString(“price”);

5. Intent Flags

// Code xử lý khi nhấn button Return to Main từ các activity detail ở các level sau Intent i = new Intent(“.Main”);
 i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
 startActivity(i);
  • FLAG_ACTIVITY_CLEAR_TOP: cờ này thực hiện theo cơ chế: nếu Main activity đang được chạy thì thay vì khởi tạo 1 instance mới, tất cả các activities ở stack trên Main activity sẽ bị đóng hết >> Quay trực tiếp về Main activity
  • Simple Flow

Screen Shot 2018-06-10 at 7.56.05 AM

  • Complex Flow

Screen Shot 2018-06-10 at 7.56.14 AM

Bài 3: Hướng dẫn tạo ứng dụng Android có nhiều Tab bằng ViewPager, Fragment và Tablayout

Mục tiêu:

  • Biết cách tạo giao diện ứng dụng dạng Tab

1. Lớp Fragment

  • Được tích hợp vào API level 4 support libraries nên có thể sử dụng ở các thiết bị cũ
  • Nhúng Fragment vào Activity bằng việc kế thừa Activity từ FragmentActivity hoặc AppCompatActivity
  • Thêm Fragment thông qua XML thẻ <fragment>
  • Hoặc thêm động trên code thông qua FragmentManager và FragmentTransaction

Ví dụ:

FragmentManager fm = getFragmentManager();

FragementTransaction ft = fm.beginTransaction();

SalesFragment sf = new SalesFragment();

ft.add(R.id.salesChart, sf);

ft.commit();

  • Giao tiếp giữa các Fragments
    • Fragment chỉ nên giao tiếp qua lại với parent Activity
    • Không nên giao tiếp trực tiếp giữa các Fragment với nhau

Ví dụ:

// Truy cập tới activity từ Fragment thông qua getActivity()

ListView employeeNames = (ListView) getActivity().findViewById(R.id.namesList);

// Fragment gửi thông tin cho activity bằng việc cài đặt hàm onItemSelectedListener()

// Khi đó Activity phải implement listener đó ở mức class

// Đây cũng là cách gián tiếp các fragment có thể giao tiếp với nhau

// Activity truy cập tới fragment thông qua tham chiếu trực tiếp

SalesFragment salesFragment = (SalesFragment) getFragmentManager().findFragmentById( R.id.SalesFragment );

  • Sử dụng Fragment như là Tab trong Activity
    • fragmenttabs
    • Để nhúng fragments là tab trong activity có thể sử dụng ViewPager
    • Khi đó mỗi fragment sẽ là 1 page
    • ViewPager quản lý layout và cho phép chuyển qua lại giữa các page
  • Thiết lập Action bar
    • actionbarsetup
    • ActionBar class có thể được sử dụng để thiết lập action bar
    • Tuy nhiên để điều khiển các action overflow dễ dàng hơn thì nên sử dụng Toolbar class
    • Dùng Toolbar cho phép thay đổi giao diện action bar: thêm logo, nút Up, tiêu đề cho activity…
    • Để dùng được Toolbar và loại bỏ ActionBar thì app cần extend AppCompatActivity và sử dụng theme NoActionBar

2. Action Overflow

  • Các tính năng ít dùng có thể đưa vào overflow
  • Cài đặt onCreateOptionsMenu() để inflate XML menu định nghĩa các item cho mỗi tuỳ chọn.
  • Cài đặt code tương ứng trong sự kiện khi item được chọn: onOptionsItemSelected()

3. Thực hành

Mở Android Studio và tạo project với Empty Activity, chỉnh sửa các nội dung như hướng dẫn sau

a. Trong res/layout

Mở activity_main.xml – layout của MainActivity

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.ourcompany.catalog.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/appbar_padding_top"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/AppTheme.PopupOverlay">
        </android.support.v7.widget.Toolbar>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>

Thêm fragment_catalog.xml – layout cho tab Products

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.ourcompany.catalog.CatalogFragment">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="Catalog" />

</FrameLayout>

Tương tự fragment_news.xml, fragment_sales.xml và fragement_maps.xml lần lượt cho các tab News, Sales và Maps

b. Trong res/menu thêm main_menu.xml để chứa các action overflow có nội dung như sau

<menu 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"
    tools:context="com.ourcompany.catalog.MainActivity">

    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:title="@string/action_settings"
        app:showAsAction="never" />

</menu>

c. Trong package source code, thêm các lớp cho các Fragment tương ứng

public class CatalogFragment extends Fragment {

    public CatalogFragment() {
        // Required empty public constructor
    }

    /**
     * Create new instance of CatalogFragment
     * @return
     */
    public static CatalogFragment newInstance(){
        CatalogFragment fragment = new CatalogFragment();
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//        return super.onCreateView(inflater, container, savedInstanceState);
        // inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_catalog, container, false);
    }
}

Tương tự cho NewsFragment.java, SalesFragment.java và MapsFragment.java

d. Trong MainActivity.java, thêm vào inner class SectionPagerAdapter để làm Adapter cho ViewPager

/**
 * Adapter that represents each page in the app as a fragment
 */
public class SectionsPagerAdapter extends FragmentPagerAdapter{

    public SectionsPagerAdapter(FragmentManager fm){
        super(fm);
    }

    /**
     * Return the fragment with the position you specify
     * @param position
     * @return
     */
    @Override
    public Fragment getItem(int position) {
        // getItem is called to instantiate the fragment for the given page
        switch (position){
            case 0:
                return CatalogFragment.newInstance();
            case 1:
                return NewsFragment.newInstance();
            case 2:
                return MapsFragment.newInstance();
            case 3:
                return SalesFragment.newInstance();
        }
        return null;
    }

    /**
     * Return the total number of views that are available to the SectionsPagerAdapter
     * @return
     */
    @Override
    public int getCount() {
        // show 4 total pages
        return 4;
    }

    /**
     * Set the label of the tab in a string format, depending on the tab view's position
     * @param position
     * @return
     */
    @Override
    public CharSequence getPageTitle(int position) {
        switch (position){
            case 0:
                return "Catalog";
            case 1:
                return "News";
            case 2:
                return "Maps";
            case 3:
                return "Sales";
        }
        return null;
    }
}

Trong lớp MainActivity, khai báo 2 biến sau

private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;

e. Bổ sung thêm code vào hàm onCreate của MainActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // set up the toolbar
    // create toolbar using the layout
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    // set as action bar
    setSupportActionBar(toolbar);

    // Create adapter that will return a fragment for each of three primary sections of the activity
    mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());

    // Set up ViewPager with the sections adapter
    mViewPager = (ViewPager) findViewById(R.id.container);
    mViewPager.setAdapter(mSectionsPagerAdapter);

    // Set up tab layout with the ViewPager
    TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
    tabLayout.setupWithViewPager(mViewPager);
}

f. Thực hiện override hàm onCreateOptionsMenu của MainActivity để load các action overflow từ menu_main.xml

/**
 * Create action overflow menu
 * @param menu
 * @return
 */
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    //return super.onCreateOptionsMenu(menu);
    // inflate the action overflow based on a menu_main.xml layout file and add items to the menu
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

Chỉnh sửa thuộc tính android:theme của MainActivity trong AndroidManifest để sử dụng  tuỳ chọn NoActionBar

<activity
    android:name="com.ourcompany.catalog.MainActivity"
    android:label="@string/app_name"
    android:theme="@style/AppTheme.NoActionBar">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Lưu ý: build.gradle (Module:app) có các thư viện cần thiết (version có thể khác)

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:26.0.2'
    compile 'com.android.support:design:26.0.2'
    compile 'com.android.support:support-v4:26.0.2'
}

OK, giờ bạn có thể chạy thử ứng dụng trên Emulator và kết quả như sau

Screen Shot 2018-06-09 at 2.32.08 AM

———_END ————-

Bài 2: Làm việc với Framework của Android

Mục tiêu bài học

  • Hiểu cấu trúc ứng dụng dự án Android
  • Sử dụng các tài liệu hỗ trợ trong quá trình phát triển ứng dụng Android
  • Hiểu vòng đời của ứng dụng
  • Thiết kế ứng dụng đáp ứng yêu cầu và mong đợi của người dùng

1. Cấu trúc project Android

androidprojectstructure

2. Activity

  • Đại diện cho 1 màn hình người dùng sẽ tương tác với
  • Thường một ứng dụng có nhiều activities
  • Có 1 main activity sẽ được khởi chạy lần đầu
  • Mỗi Activity thông thường có 2 file gắn với nó: Java class kế thừa từ Activity class dùng để khởi tạo và xử lý các sự kiện tương tác. Và 1 file XML mô tả layout của nó.

3. Layout

  • Layout: cách UI được khởi tạo, các thành phần được hiển thị trên màn hình, kích thước, vị trí, màu sắc, viền, font chữ và các thuộc tính khác…
  • Có 2 cách để định nghĩa layout của Activity: qua code hoặc qua XML sau inflate trên code
  • Cách tạo layout trên XML cho phép bạn tách việc dựng layout khỏi hành vi, thay đổi layout động theo cấu hình thiết bị, dễ bảo trì, chuyên môn hoá…

4. View Group

androidviewgroup

5. View Objects

androidviewobjects

6. View Object Attributes

androidviewobjectattributes

7. Layout Measurements

androidlayoutmeasurement

8. Intent và Bundle

  • Bundle: là container sử dụng để truyền dữ liệu giữa các activities
  • Khi activity được khởi tạo hay huỷ, nó được đính với bundle lưu trữ và truy xuất trạng thái được cất giữ (frozen/saved state) và nội dung hiện tại của các components của actvity đó.
  • Intent: là đối tượng gửi thông điệp để ra lệnh chạy activity
  • Một cách dùng khác của bundle là lưu trữ thông tin trạng thái của activity khi nó bị suspend (vd: người dùng chuyển sang app khác…) và khi người dùng quay lại app thì OS có thể lấy lại thông tin trạng thái trước đó thông qua bundle để tiếp tục làm việc.

9. Common Resource Directories

commonresourcedirectory

10. Resource Variants

  • Android cho phép cung cấp các lựa chọn resources thông qua các suffix
  • Languages: value-es, value-fr…
  • Graphic images: drawable-ldpi, drawble-mdpi, drawable-hdpi…
  • Screen Orientation: landscapes or portrait

11. Android Manifest

androidmanifest

  • Permissions:
    • Xin cấp quyền tương tác với app khác, cung cấp khi tải và cài đặt app.
    • Từ API 23 trở lên: hỏi cấp quyền khi runtime
    • Chỉ khai báo xin quyền khi trong app thực sự sử dụng
  • android:exported trong thẻ <activity> = true cho phép khởi chạy từ activity khác ngoài app, = false chỉ các activities trong app mới chạy được. Nếu không chỉ định thì sẽ phụ thuộc vào ngữ cảnh.

12. Gradle

  • Công cụ được sử dụng cho quá trình tự động hoá build ứng dụng Android
  • Gradle(Project): mức toàn bộ dự án, áp dụng cho tất cả các modules trong dự án
  • Gradle(Module): mức độ module, hầu hết sẽ cấu hình build trên file này vì thông thường một app có 1 module

androidgradle

13. Code completion & Quick Fix

  • Android Studio hỗ trợ tự động suggest code khi đang gõ dở code thông qua tổ hợp phím
    • Windows: Ctrl + Space
    • MacOS: control + Space
    • codecompletion
  • Hỗ trợ Fix nhanh cú pháp/import code thông qua tổ hợp phím
    • Windows: Alt + Enter
    • MacOS: option + return
    • quickfix

14. Tài liệu và cộng đồng Android

androidreferencedocument

15. Các thành phần chính trên Android

androidorganization

  • Activity = customer service department
  • Fragment = customer service representative
  • Service = back office workers
  • Content provider = librarian or bookkeepers, manage storage of application data.
  • Intents = business partnerships
  • Broadcast receivers =network operators
  • Widgets = marketing department
  • Notifications = public relations department

16. Activity Lifecycle

  • Active or running: activity được nạp vào bộ nhớ, hiển thị cho người dùng thao tác
  • Paused: activity được nạp vào bộ nhớ, hiển thị một phần nhưng tạm thời người dùng không tương tác được
  • Stopped: activity được nạp vào bộ nhớ, nhưng không hiển thị cho người dùng. Ở trạng thái này activity vẫn lưu trữ trạng thái và dữ liệu
  • Killed: Nếu hệ thống thiếu bộ nhớ, activity ở trạng thái stopped và paused có thể bị kill. Khi quay lại activity đã bị kill thì sẽ phải restart và restore lại state của nó.

activitylifecycle

Mô tả các hàm callback

activitylifecyclemethods

Ghi chú: các task thông thường ở từng callback

  • onCreated: khởi tạo, load dữ liệu, tạo view
  • onResume: khôi phục các hoạt động bị tạm dừng khi onPause
  • onPause: tạm dừng các hoạt động như chơi nhạc, chơi video, animation. Giải phóng các hoạt động tốn CPU và power. Giải phóng tài nguyên mà activity sử dụng như GPS, camera, sensor. Commit các thay đổi chưa được lưu trữ. Lưu trữ trạng thái dữ liệu cần xử lý cho lần chạy tiếp theo và giải phóng các tài nguyên cần cho activity khác.
  • KHÔNG NÊN chạy các tác vụ tốn thời gian, tài nguyên ở onPause >> NÊN để ở onStop

17. Fragment Lifecycle

fragmentlifecycle.png

18. Các cách lưu trữ dữ liệu trên Android

External storage Nếu là ứng dụng client làm việc với web service thì app có thể lưu trữ và truy xuất dữ liệu từ mạng ở External storage
Preferences Khi cần lưu trữ và truy xuất dữ liệu nhỏ thì có thể dùng Preference. Dữ liệu có thể chỉ được dùng trong 1 activty hoặc có thể được chia sẻ giữa các thành phần trong ứng dụng
Local file hoặc content provider App sử dụng file local hoặc content provider như SQLite database để lưu trữ dữ liệu. Dữ liệu sẽ được lưu trữ ngay mỗi thao tác, khi nhận được sự kiện onPause sẽ thực hiện commit để tránh mất dữ liệu người dùng đã tạo ra/thay đổi.

19. Quản lý bộ nhớ và multitasking trên Android

  • Khi sử dụng thiết bị android người dùng có thể chuyển qua lại nhiều app mà không biết viêc hệ thống sẽ bị chậm đi hoặc tốn pin
  • Hệ thống tự động suspend, terminate và khởi động lại app ở background khi cần thêm bộ nhớ hoặc thấy bị tiêu hao pin mà người dùng không để ý đến.
  • Khi lập trình bạn cần nắm được cách quản lý resource thông qua lifecycle của activity

20. UX trên Android

  • Sử dụng Material Design
  • Giao diện và hành xử giống như các app Android thông thường
  • Không phụ thuộc vào thiết bị (kích thước màn hình, rotation…)
  • Chạy mượt mà.
  • Cung cấp phản hồi khi thích hợp.
  • Cung cấp các tuỳ chỉnh thiết lập.
  • Tương tác với các ứng dụng khác của hệ thống và phần cứng trên thiết bị.
  • Tối ưu hoá không gian màn hình thích hợp theo thiết bị.
  • Không có lỗi về ngữ pháp và chính tả.
  • Thẩm mỹ hài hoà.

21. Ràng buộc khi thiết kế UI trên mobile

  • Small screen: nhiều thiết bị có kích thước màn hình nhỏ. Giải pháp có thể là chia thành nhiều màn hình thao tác >> người dùng có thể mất thời gian hơn >> thiết kế phải đảm bảo cân bằng
  • Mobile data connection: thiết bị có thể sử dụng cellular data để truy cập dữ liệu web, sẽ có độ trễ nhất định >> cần được thiết kế đáp ứng vấn đề này
  • Low power consumption: Android tự động suspend các app chạy ở background để tiết kiệm nguồn. Người dùng dễ để ý tới các app sử dụng tốn tài nguyên và từ bỏ nó. Do vậy cần thiết kế đảm bảo tiết kiệm tài nguyên
  • Laborious text entry: Thiết kế tối thiểu việc nhập liệu bằng text. Nên sử dụng các dữ liệu mặc định, dữ liệu chọn, autocomplete…

 

Ref: giới thiệu một số công cụ để thiết kế prototype, thiết kế UI

Online tool: https://cacoo.com

Offline: MacOS Sketch, Windows: Visio/Photoshop

—————-END—————–

Bài 1: Bắt đầu với Android Studio

Mục tiêu

  • Nắm được kiến thức cơ bản về hệ điều hành Android
  • Tạo thử 1 project
  • Cấu hình môi trường phát triển
  • Tạo Emulator để chạy thử chương trình

1. Hệ điều hành Android

  • Dựa trên linux
  • Phát triển bởi Android Inc.
  • Google mua lại vào năm 2005
  • Mã nguồn mở, giấy phép Apache
  • Hơn 2 triệu ứng dụng ở nhiều hạng mục khác nhau

2. Các phiên bản

androidversion

 

 

 

3. Ảnh hưởng gì tới DEV

  • Không thể chỉ dựa vào API level hỗ trợ tính năng gì
  • Cần phải có kế hoạch cụ thể
    • Kiểm tra sự hiện diện của tính năng
    • Xử lý runtime error nếu hàm bị fail và cung cấp các lựa chọn khác

4. Phần cứng hỗ trợ

  • ARM processor
  • Intel Atom line of x86 Processor

5. API level

  • Là phiên bản cụ thể các API của Android framework
  • Việc chỉ ra ứng dụng phát triển trên API phiên bản nào phụ thuộc vào mong muốn các features trên API đó có thể dùng trong app, bao gồm
    • Packages và classes có thể dùng
    • XML elements & attributes
    • Activities có thể được gọi
    • Các Permissions app có thể yêu cầu
    • Cách thức app phải yêu cầu permission (trước khi cài đặt hay trong khi chạy)
  • API level mới thì sẽ hỗ trợ nhiều tính năng mới nhưng app có thể không tương thích với các máy chạy OS cũ
  • Các bản cập nhật của Android đảm bảo tương thích ngược (các hàm được nâng cấp không bị remove đi mà đánh dấu là deprecated >> app vẫn sử dụng được API cũ)
  • Vấn đề lựa chọn API level sẽ đáp ứng nào rất quan trọng

6. Các thư viện hỗ trợ (support libraries)

  • Có một số APi mới quan trọng được đóng gói trong các thư viện hỗ trợ để cho phép các thiết bị chạy ở phiên bản cũ hơn có thể chạy được các API mới này.
  • Ex: Fragment giới thiệu trong API level 11 nhưng có thể được sử dụng ở thiết bị chạy OS thấp hơn thông qua việc sử dụng thư viện hỗ trợ

7. Kiến trúc Android

androidarchitecture

  • Inter-application communication: thông qua rich messaging system
  • Ví dụ: khi app muốn đáp ứng tính năng phone call thì không cần viết code từ đầu trên APP mà gọi sang phone app để thực hiện

8. Android Runtime

androidruntime

  • Mỗi ứng dụng chạy trên 1 Linux process
  • Mỗi Android process chạy trên 1 thực thể ART
  • Một app bị crash không ảnh hưởng tới app khác
  • Đảm bảo security hơn, khó khăn hơn để 1 process này truy cập vào tài nguyên của process khác nếu không được phép

9. Máy ảo Dalvik

  • ART: Ahead Of Time compiler
  • Dalvik: runtime environment, Just In Time compiler (compile khi ứng dụng thực thi)
  • Từ Android 5.0 ART thay thế hoàn toàn Dalvik
  • Android 7.0 Google bổ sung JIT compiler vào ART >> giảm thời gian cài đặt và kích thước mã nguồn được biên dịch

10. Android Multitasking

  • UI component người dùng đang tương tác trực tiếp sẽ được focus
  • UI ngoài view sẽ bị tự động suspend để tối ưu tài nguyên
  • Android hỗ trợ chạy đa luồng thông qua background thread và callback functions
  • Có notify khi app bị suspend >> cho phép xử lý cất lại trạng thái
  • Nên cài đặt các tác vụ mất thời gian ở background
  • Nếu luồng chính của app có tác vụ mất nhiều thời gian xử lý thì hệ thống sẽ tự động tắt tiến trình app đó và hiển thị message Application Not Respoding (ANR) cho người dùng.

11. Các công cụ để phát triển

  • Java SE Development Kit (JDK)
  • Android SDK
  • Android Studio
  • Android Virtual Device Manager

Ref: https://developer.android.com/studio/

12. Android studio

  • Phát hành lần đầu năm 2014
  • Thay thế Eclipse và ADT
  • Tích hợp trong 1 IDE, không phải tải nhiều plugin

adroidstudio

Android studio Menus

adroidstudiomenu

Android studio Tool Windows

adroidstudiotools

Emulator

androidemulator

  • Cung cấp giao diện như thiết bị thật
  • Cho phép thao tác gestures: tap, swipes, pinches…
  • Cho phép thực hiện các tính năng vật lý: quay thiết bị…
  • Cho phép cấu hình giả lập phần cứng: SD card, GPS, Camera…
  • Có thể chạy ở các chế độ bộ nhớ khác nhau
  • Thiết lập ở các chế độ kích thước màn hình khác nhau

13. Android SDK Manager

adnroidsdkandroidsdkdefault

14. Command line tools

  • Đi kèm với SDK Manager
  • Độc lập với API
  • Thao tác nhanh hơn: check & update, create emulator, format emulator’s SD card, build release package…

15. Android studio setting

androidstudiosetting

  • Appearance & Behavior
  • Keymap
  • Editor
  • Plugins
  • Version Control
  • Build, Execution,
  • Deployment
  • Languages & Frameworks
  • Tools

16. AVD Manager

avdmanager

  • Tool cho phép tạo emulator để test ứng dụng
  • Chỉ định các đặc tính: hardware profile, device model, API platform, ABI (application binary interface) của virtual image
  • Cấu hình: device’s name, emulated camera, network performance, Graphic performance, Memory…

17. Emulator controls

emulatorcontrols

  • Set GPS location for device.
  • Change status of device’s cellular connection.
  • Change status of device’s battery.
  • Place a phone call.
  • Send an SMS message.
  • Set miscellaneous AVD settings.

———————- END ————————–