Tạo Usb boot cài Win 10 theo chuẩn UEFI


Hiện nay một số dòng máy không còn dùng chuẩn BIOS nữa mà dùng chuẩn UEFI, ví dụ như các dòng Surface Pro 4, 5, 6 …. nên một số bạn cài hệ điều hành Windows 10 từ USB khóc thét mấy ngày cũng không được và cũng không hiểu vì sao nó bị lỗi.

Bài hướng dẫn nhỏ này Tui muốn trình bày về cách tạo USB boot chuẩn UEFI, rồi tùy từng dòng máy mà UEFI setting sẽ có màn hình tương tác khác nhau để lựa chọn các cấu hình boot usb (có câu hỏi nào liên quan thì các bạn chụp màn hình và comment tại post này).

BIOS: Basic Input/Output System

UEFI: Unified Extensible Firmware Interface

Bước 1: Chuẩn bị 1 USB 8GB hoặc 16GB tùy vào độ đại gia của bạn.

Bước 2: Tải file ISO Windows 10 tại đây: https://drive.google.com/file/d/1n6Y45D83VRn7jV09j0S9zrQuMfdLLERj/view?usp=sharing

Vì Windows cần bản quyền nên Tui chỉ cung cấp ISO mà không cấp Key, các bạn lấy file này tạo Usb boot sài thử, có tiền thì mua Key. Nếu là Sinh Viên thì có hệ thống Azure Teaching để lấy bản quyền miễn phí.

Bước 3: Tải phần mềm Rufus phiên bản 3.8 để tạo UEFI USB flash drive: https://github.com/pbatard/rufus/releases/download/v3.8/rufus-3.8.exe

Các version khác tại đây: https://github.com/pbatard/rufus/releases

Chạy Rufus lên và chọn lựa như hình dưới đây:

Mục 1: là thông tin USB của bạn, Khi cắm USB >=8GB vào sẽ thấy ở đây (nhỏ hơn không đủ dung lượng cài đâu nha)

Mục 2: Bấm vào Select để chọn file ISO Win 10 mà bạn đã tải về, Nó sẽ hiện thị vào mục Boot Section.

Mục 3: Image Option chọn Standard Windows Installation

Mục 4: Partition Scheme chọn GPT

Mục 5: Target system chọn UEFI(non CSM)

Mục 6: Volume label đặt tên là Win 10

Mục 7: File system chọn NTFS

Mục 8: Cluster size để mặc định 4096 bytes

Mục 9: Sau khi cấu hình mọi thứ xong thì bấm Start và chờ cho tới khi phần mềm tạo thành công đĩa Boot.

Như vậy tới đây bạn đã tạo thành công 1 USB boot, giờ có thể cài được trên các máy có chuẩn UEFI.

Tui hướng dẫn thêm về cách cấu hình UEFI Setting để boot usb cho dòng máy Surface Pro 4,5,6 hoặc ~:

  • Bước 1: Tắt máy Surface Pro đi, nhấn nút power, thường chờ khoảng 10 giây cho nó tắt hẳn (có thể hơn)
  • Bước 2: Nhấn và giữ nút loa tăng có biểu tượng +, đồng thời nhấn rồi nhả nút power
  • Bước 3: Lúc này biểu tượng UEFI sẽ hiển thị ra, tùy vào phiên bản mà ta có nhiều mục khác nhau, ở đây Tui chỉ nói cách cấu hình để chạy USB boot cài Win theo chuẩn UEFI==> chọn Boot Configuration:

Trong màn hình Boot configuration bạn có thể chọn thứ tự boot bằng cách dùng cảm ứng nhấn vào từng thiết bị rồi di chuyển lên xuống, trong trường hợp này là chọn USB Storage. Sau đó vào Exit chọn Reset khởi động lại ==> sẽ cài đặt.

Ngoài ra ta không cần thay đổi thứ tự boot, mà ta chỉ cần nhấn vào USB Storage rồi kéo qua bên trái, lúc này UEFI sẽ hiển thị 1 màn hình hỏi xác nhận Boot từ USB hay không, ta chọn yes để cài đặt Win 10 bằng USB (Khi ta nắm kéo qua trái thì thứ tự boot không bị đổi)==> Thường tui chọn cách này vì nó nhanh và tiện lợi nhất.

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

Bài 1- BackEnd là gì? Tại sao phải lập trình BackEnd


Theo thông tin từ Marketing thì hiện nay nhu cầu tuyển dụng lập trình viên BackEnd đang ngày càng mở rộng, đặc biệt là Java BackEnd, kết hợp với Microservice.

Vì vậy Tui làm chuỗi các bài hướng dẫn trên blog này cũng như sẽ sớm ra mắt khóa học bằng Video trên http://communityuni.com, hi vọng sẽ tạo thêm được nhiều cơ hội việc làm cho người học.

Chuỗi các bài hướng dẫn này sẽ tập trung vào:

  • Giới thiệu về lập trình BackEnd, JavaBackEnd và những JDK, công cụ hỗ trợ
  • Thư viện Vertx, một trong những thư viện được đánh giá là tốt nhất hiện này để triển khai BackEnd, đặc biệt hỗ trợ đắc lực cho MicroService
  • NoSQL và hệ sinh thái, trong đó tập trung chính yếu vào MongoDB
  • Cách triển khai JavaBackEnd với NoSQL
  • Cải tiến JavaBackEnd với Annotation
  • Authentication và Authorisation trong Java BackEnd
  • Cách Deploy JavaBackend

Các kiến thức trên sẽ lần lượt được làm rõ ở các bài viết tiếp theo.

Còn ở bài này Tui sẽ trình bày BackEnd, lý do vì sao lập trình BackEnd mà cụ thể là JavaBackEnd, cũng như hệ sinh thái của BackEnd, các thư viện và công cụ cần cài đặt

Các lý thuyết về BackEnd các bạn có thể tìm hiểu trên mạng, các Website đã giải thích khá chi tiết và về cơ bản thì nó giống nhau (vì là cơ sở lý thuyết). Tui tóm tắt lại như sau (Biết rồi thì khỏi đọc, đỡ hư chuột):

1. BackEnd là gì?

Back End dùng để xử lý mọi logic nghiệp vụ phức tạp ở ẩn ở phía sau, giúp cho hệ thống hoạt động hiệu quả hơn. Dữ liệu của người dùng, thuật toán phân tích … đều nằm ở back-end.

2.Tại sao phải lập trình BackEnd?

Có rất nhiều lý do khác nhau, mỗi một Công ty, tộc trưởng trong nhóm phát triển dự án sẽ có như lý do riêng để giải thích cho vấn đề này. Tuy nhiên đại khái nó như sau:

  • BackEnd viết phía Server nên thường được hệ thống máy chủ xử lý nhanh chóng và mạnh mẽ, client chỉ cần nhận kết quả
  • Chia sẻ nguồn tài nguyên máy chủ nên tiết kiệm được nhiều thứ
  • Giúp chạy đa nền tảng khi triển khai Web API: Viết 1 lần thôi nhưng có thể sử dụng trên bất kỳ nền tảng nào. Ví dụ khi ta viết Web API xong thì ta có thể dùng Mobile, Desktop, Web hay bất kỳ 1 nền tảng nào khác đều có thể sử dụng chung cái Web API đó.

3.Hệ sinh thái BackEnd

Hiện nay rất nhiều ngôn ngữ lập trình có khả năng giúp chúng ta xử lý phía Back End. Chúng tạo nên một hệ Sinh thái Backend vô cùng phong phú.
Việc nắm được các kỹ thuật xử lý BackEnd theo các ngôn ngữ khác nhau giúp chúng ta dễ dàng thích ứng trong công việc cũng như có nhiều lựa chọn trong quá trình xử lý kỹ thuật phức tạp.
Tui liệt kê 7 ngôn ngữ có thể giúp chúng ta triển khai BackEnd dễ dàng:

  • PHP
  • Python
  • Ruby
  • C#
  • Node.js
  • Java
  • RxJava

Cùng với nó là các Cơ sở dữ liệu đi kèm, chẳng hạn như:

  • Các cơ sở dữ liệu quan hệ cần quan tâm: Oracle, Microsoft SQL Server, Mysql…
  • Các cơ sở dữ liệu NoSQL: MongoDB, PostgreSql, ReThinkDB, Neo4j…

Các bài học Tui sẽ sử dụng MongoDB, một trong những NoSQL phổ biến nhất hiện nay.

4. Thư viện và công cụ lập trình cần cài đặt để làm việc với JavaBackEnd

Ta lập trình Java BackEnd nên bước đầu tiên bắt buộc phải cài đặt JDK , sẽ được hướng dẫn chi tiết ở bài học sau

Có rất nhiều công cụ lập trình Java BackEnd, chẳng hạn như:

  • Eclipse
  • Netbeans
  • IntelliJ IDEA

Các bài học sẽ sử dụng IntelliJ IDEA và được hướng dẫn chi tiết ở các bài học sau

Như vậy ta cần cài: JDK + IntelliJ IDEA

Hẹn gặp lại các bạn ở các bài hướng dẫn tiếp theo nhé!

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

Hướng dẫn sử dụng hệ thống Azure Dev Tools for Teaching



Microsoft Imagine Premium là một trong những chương trình nổi tiếng của hãng Microsoft. Năm 2019 Microsoft đã chuyển dịch vụ này thành Azure Dev Tools for Teaching.
Với chương trình “Azure Dev Tools for Teaching” thì Giảng Viên, Sinh Viên và các nhà Nghiên Cứu có tài khoản Education đều có thể tiếp cận được nhiều tiện ích từ hệ thống, chẳng hạn như:
– Tải hơn 100 phần mềm bản quyền miễn phí chính thức từ Microsoft, trong đó có bản quyền Win 10
– Sử dụng được hosting Azure, được đánh giá là một trong những hệ thống Cloud tốt nhất hiện nay. Hỗ trợ Sinh Viên rất nhiều trong việc triển khai thử nghiệm các hệ thống Thương Mại Điện Tử
– Sử dụng máy ảo
– Build được  Chatbot với Azure
– Tiếp cận Machine learning
– Và các tài nguyên Video free từ hệ thống.
Mọi thứ được tích hợp trong cùng 1 hệ thống Azure.
Ngoài ra còn có kênh https://channel9.msdn.com/ để mọi người tiếp cận nhiều kiến thức hiện đại và mới nhất

Dưới đây là hướng dẫn chi tiết cách kích hoạt tài khoản để sử dụng chương trình “Azure Dev Tools for Teaching”

(Trong quá trình kích hoạt mà bị lỗi sự cố xác thực Azure Teaching thì đọc bài của bạn Nguyễn Anh Nhật, thành viên Câu Lạc Bộ ITB của Khoa Hệ Thống Thông Tin, Đại Học Kinh Tế – Luật ở đây https://savegavinlife.wordpress.com/2019/04/18/huong-dan-sua-loi-khong-xac-thuc-duoc-he-thong-azure-dev-tools-for-teaching/)

Ta vào link sau:
https://azureforeducation.microsoft.com/devtools

Chọn nút Sign In như hình trên, lúc này Azure sẽ hiển thị cửa sổ như dưới đây:

Nếu đã có tài khoản đăng ký với Microsoft trước đó rồi (Edu) thì nhập và bấm next. Còn chưa có (mới) thì bấm Creat One!

ở màn hình trên, ta nhập chính xác email Education mà nhà trường cấp. Ở ví dụ trên Tui dùng Email của Đại Học Kinh Tế – Luật. (Dĩ nhiên Trường của bạn phải đăng ký domain edu với Microsoft trước rồi nha, còn chưa thì phải làm thủ tục đăng ký để sử dụng các tiện ích của hãng).

Sau đó bấm Next:

Màn hình trên bạn nhập mật khẩu (lưu ý mật khẩu này nó không liên can gì với mật khẩu đăng nhập vào gmail nha, tùy bạn đặt).

sau đó bấm Next:

Lúc này Microsoft sẽ gửi Key vào email của bạn để yêu cầu bạn xác thực, bây giờ bạn mở Email lên để kiểm tra:

Bạn thấy email có tiêu đề “Verify your email address”, mở email lên:

Bạn copy mã đó dán vào màn hình đang thao tác:

sau đó bấm Next:

Azure yêu cầu nhập Capcha, bạn nhập cho chính xác kể cả Hoa, thường. Sau đó bấm Next, lúc này màn hình xác thức Academic xuất hiện như dưới đây:

Ta nhập 2 lần Email (edu) của bạn, rồi checked “I agree to the …..”

sau đó bấm nút “Verify academic status and accept terms

Chờ chút xíu sẽ có thông báo xác thực email:

Bạn vào check email 1 lần nữa–> email có tiêu đề “Confirm Your Academic Status”:

Bên trong email có link bấm xác thực, bạn bấm vào link đó nha: Lúc này bạn sẽ thấy màn hình sau xuất hiện:

Hệ thống đã báo xác thực thành công, bạn checked vào “I agree to the subsription agreement…”

Rồi bấm “Accept terms“. Chương trình sẽ đưa bạn tới hệ thống Azure Education như hình bên dưới, coi như đã hoàn tất 100% phần đăng ký.

Để tải phần mềm bản quyền hoàn toàn miễn phí mà chính thức từ Microsoft, bạn vào mục Software ở trên:

Azure cung cấp khoảng hơn 100 phần mềm bản quyền ở trên. Bạn có thể tìm kiếm.

Ví dụ như tìm WIN 10 bản quyền:

Bấm vào phần mềm muốn tải, nhìn góc phải thấy mục “View key”, bận bấm vào đó để lấy Key

Bấm Download để tải về.

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

Có khó khăn gì trong vấn đề kích hoạt, cũng như cách tạo USB boot để tạo phần mềm cài đặt Win 10 thì liên hệ với Câu Lạc Bộ ITB của Khoa Hệ Thống Thông Tin (https://is.uel.edu.vn) – Đại Học Kinh Tế – Luật

Fanpage: https://www.facebook.com/itbclub.uel/

Trần Duy Thanh!

Hướng dẫn tải, cài đặt và sử dụng Visual Studio 2019


Bài này dành cho các newbie về công nghệ Microsoft, đặc biệt là Visual Studio, cũng như một số bạn đã từng cài đặt và sử dụng nhưng có một số bước bị thiếu trong quá trình cài đặt.

Hướng dẫn giúp các bạn biết cách tải, cài đặt và sử dụng Visual Studio 2019 mới ra lò ngày 02/04/2019. Phần cài đặt, tạo project nó khá khác biệt so với các version trước. Tuy nhiên về bản chất lập trình không có khác nhiều.

Các đặc điểm mới trong version này được Microsoft công bố ở đây: https://docs.microsoft.com/en-gb/visualstudio/releases/2019/release-notes.

Trong bài hướng dẫn này Tui tập trung vào các phần chính sau:

  1. Cách tải Visual Studio 2019
  2. Cách cài đặt Visual Studio 2019
  3. Cách sử dụng Visual Studio 2019 bằng bài HelloWorld
  4. Cách đăng ký bản quyền Visual Studio 2019 Enterprise

Để tải Visual Studio 2019, các bạn vào link: https://visualstudio.microsoft.com/download

Ở trên có 3 phiên bản Visual Studio 2019. Đó là: Community, Professional và Enterprise. Với Sinh Viên không có tiền thì tải bản Community là đủ rồi. Còn cách cài đặt tương tự. Trong hướng dẫn này vì Tui có bản quyền nên sẽ trình bày cách tải Enterprise, sử dụng, kích hoạt nó như thế nào (các bản khác tương tự).

Ở màn hình trên, nếu là Community thì bấm Free Download. còn 2 bản kia thì chọn Free Trial, cài xong rồi ta kích hoạt bản quyền sau.

Sau khi tải thành công ta có file chạy như dưới đây:

Tại thời điểm Tui viết hướng dẫn này là ngày 03/04/2019 (Visual Studio 2019 chính thức publish là ngày 02/04/2019). Có thể lúc bạn đọc hướng dẫn này là version tiếp theo nhưng chắc cũng không có gì khác biệt lắm.

Giờ ta double click vào Vs_enterprise mà Tui tải về ngày 03/04/2019

Tùy vào tốc độ của máy cũng như đường truyền mạng, sau khi tải xong ta sẽ có màn hình như dưới đây:

Tùy vào nhu cầu lập trình mà ta sẽ chọn các gói khác nhau. Theo kinh nghiệm làm Project thì Tui thấy đa phần chúng ta sẽ triển khai các dự án phổ biến dưới đây (nên tick vào) tùy vào dung lượng ổ cứng, RAM, và các cấu hình khác nha. Nếu yếu thì đừng ra gió, cài một vài tính năng cần thiết trong lập trình thôi.

Ví dụ trong trường hợp này Tui thường triển khai các dự án về: Deskop application, Web Application, NodeJS, Mobile Application thì ta cần tick các lựa chọn như dưới đây:

Ở màn hình trên Tui làm các dự án liên quan tới Web asp net MVC, net core và NodeJS nên Tui sẽ ticked 2 lựa chọn trên.

Tiếp tục kéo chuột xuống để lựa chọn (nếu bạn có lập trình về nó):

Ở màn hình trên Tui có lập trình Desktop application (Winform, WPF) thì Tui tick chọn nó. Tương tự cho Universal Windows Platform development , Mobile (Xamarin) thì tick vào nó.

Thêm lưu ý quan trọng là, ngay chỗ này đừng có bấm install nha. Vì còn một vài tính năng Tui thấy các bạn thường hay quên. ít nhất là 2 tính năng: Hiển thị mô hình lớp (class Diagram) và tăng tốc lập trình với LINQ:

Nhớ tick thêm 2 chức năng nữa đó là: Class Designer và LINQ to SQL Tools (xem hình trên).

Như vậy tới thời điểm này, Tui cần có tối thiểu 18.41GB để cài đầy đủ các tính năng mà Tui cần. Do đó bạn phải liệu cơm gắp mắm nha. Tùy vào cấu hình máy cũng như nhu cầu lập trình mà lựa chọn các gói cho phù hợp. Ví dụ bạn chả bao giờ lập trình mobile hay universal thì đừng có tick vào chúng để giúp hệ thống máy tính bớt “ngu” không cần thiết.

Sau đó ta bắt đầu bấm Install để cài đặt nha:

Lúc này Microsoft nhờ ta làm khảo sát, bạn “bận” quá thì bấm vào Not Now.

Sau đó chờ hệ thống cài đặt nha:

Chờ tới khi nào nó xong (tùy vào tốc độ máy):

Thấy nó báo 100% không?

Sau đó ta thấy nó ra màn hình thông báo trên:

Visual Studio Enterprise 2019. bản 16.0.0 coi như đã gần xong

Lúc này nó sẽ có màn hình dưới đây tự động xuất hiện:

Màn hình này cũng không quan trọng lắm. Nhưng nó có 3 ý nghĩa:

  • thứ nhất: Bạn không quan tâm thì bấm “Not now, maybe later”
  • thứ nhì: nếu bạn chưa có tài khoản Microsoft thì bấm vào Create one!
  • thứ ba: Nếu bạn đã có thì bấm vào sign in.

Vì Tui có tài khoản(nên là như vậy). Ta nên đăng ký để có tài khoản (Create one!). có tài khoản nó sẽ tự đồng bộ nhiều thứ vì đằng sau nó còn có hệ thống Azure Teaching nữa (tuy nhiên nếu bạn là Newbie thì tốt nhất bấm “Not now, maybe later” để khỏi nhiều chuyện, khi nào rành rồi thì làm tiếp các phần khác- không ảnh hưởng gì tới Hòa Bình Thế Giới).

Giờ Tui bấm Sign In:

Tui chọn Personal account.

Cung cấp mật khẩu rồi Sign in bình thường.

Màn hình trên thấy Tui đăng nhập thành công nha.

đây là màn hình lúc khởi động Visual Studio 2019:

Khi khởi động xong, ta có màn hình dưới đây (nó khá khác biệt với các version cũ):

Ở màn hình trên ta có 3 lựa chọn chính:

  • danh sách bên trái: chọn mở những Project cũ (cái này nếu bạn đã tạo trước đó hoặc kể cả ở các Version cũ nó cũng tự động hiển thị lên đây cho bạn). Muốn mở lại thì click vào nó là ok
  • chọn Continue without code: Chọn mục này sẽ mở Visual Studio mà không có Project nào cả
  • chọn “Create a New Project” : Chương trình sẽ hiển thị màn hình tạo Project mới.

Theo mục tiêu của hướng dẫn này, Thì Tui sẽ trình bày cách chọn “Create a new Project”:

Sau khi bấm vào chức năng này, ta có:

Rất khác biệt so với các version cũ đúng không?

ở đây bạn có thể: Tìm kiếm, lọc theo: Ngôn ngữ lập trình (C#, VB..), lọc theo Platform(Android, IOS, Windows…), theo Project Type(Cloud, Console, Machine Learning…). Việc tìm kiếm và lựa chọn giúp chúng ta dễ dàng lựa chọn đúng và nhanh chóng chủng loại dự án mà mình muốn triển khai. Ban đầu có vẻ khó chịu, nhưng sài một thời gian ta sẽ thấy sự tiện lợi này (giống như ban đầu bắt đội mũ bảo hiểm, đám đông nhao nhao chống đối, nhưng giờ ra đường mà không đội mũ bảo hiểm thì thấy nó kỳ kỳ…).

Ví dụ: Bây giờ Tui muốn tạo 1 Project tên “HelloWorld”. Viết bằng ngôn ngữ C#, platform là Windows, Project Type là Desktop. Thì Tui chọn như dưới đây:

Bước 1: Trong mục Language chọn C#

Bước 2:

Mục Platform chọn Windows

Bước 3: Mục Project Type chọn Desktop

Sau đó trong mục dưới có:

WPF – App (.Net Framework). Ta chọn nó rồi bấm Next

Lúc này màn hình “Configure your new Project” hiển thị ra như dưới đây:

Project name: Đặt tên cho dự án. Ví dụ Tui đặt “HelloWorld”

Location: Nơi lưu trữ dự án. Nên lưu khác ổ C nha, tạo thư mục không dấu Tiếng Việt để lưu trữ.

Solution name: 1 Solution có nhiều dự án (nhiều Project). Thông thường mỗi lần tạo 1 Project ta có Solution đinh kèm để quản lý nó. Nhớ rằng khi triển khai dự án thì thường chúng ta có nhiều Project. Như vậy có 1 Solution và nhiều dự án để cùng phối hợp giải quyết các vấn đề mà ta cần hoàn thành. Thông thường nó đặt tên trùng với Project đầu tiên này. Nên các bạn cứ để mặc định như hình trên.

FrameWork: Đây là version mới nhất Tui cài đặt tại thời điểm này (03/04/2019). nên nó là 4.7.2. Khi bạn đọc hướng dẫn này thì nó có thể có các version khác (không quan trọng), cứ chọn cái mới nhất để thử nghiệm.

Mọi thứ đã OK thì bấm Create để tạo Project:

Tui nó sơ qua chắc năng màn hình:

  • mục 1: Là tool box để lựa chọn các Control cho phù hợp với nhu cầu. Ta kéo thả trực tiếp vào mục số 3
  • mục 2: là XAML là nơi thiết kế màn hình bằng code XAML (tương tự XML)
  • Mục 3: Là nơi thể hiện màn hình tương tác người dùng. NÓ sẽ thay đổi theo mục 1 và mục 2 tùy ý của lập trình viên.
  • mục 4: Là nơi tổ chức sắp xếp hệ thống các lớp, tập tin, thư viện…. trong dự án
  • mục 5: Là nơi cấu hình các thuộc tính cho các đối tượng trên giao diện
  • mục 6: là các tiện ích giúp ta thao tác nhanh với hệ thống. Chưa quen thì dùng 1 chức năng đó là RUN (F5) hoặc nhấn vào nút màu xanh ngay chỗ số 6 Tui vẽ

Khi nhấn F5 chạy ta có kết quả như dưới đây:

Như vậy Tới đây ta đã biết cách tải, cài đặt, sử dụng Visual Studio 2019 rồi.


<Window x:Class="HelloWorld.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HelloWorld"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<TextBlock Foreground="Blue" Text="Lập trình WPF trong Visual Studio 2019" FontSize="35" HorizontalAlignment="Left" Margin="89,100,0,0" TextWrapping="Wrap" VerticalAlignment="Top"/>
<TextBlock Foreground="Red" Text="Trần Duy Thanh -http://communityuni.com" FontSize="35" HorizontalAlignment="Left" Margin="89,196,0,0" TextWrapping="Wrap" VerticalAlignment="Top">

</TextBlock>
<Ellipse HorizontalAlignment="Left" Height="132" Margin="306,264,0,0" Stroke="Black" VerticalAlignment="Top" Width="148" RenderTransformOrigin="0.328,0.104">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset="0.0" Color="White" ></GradientStop>
<GradientStop Offset="0.5" Color="Red" ></GradientStop>
<GradientStop Offset="1.0" Color="Blue" ></GradientStop>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>

</Grid>
</Window>

Coding mẫu tải ở đây:

https://www.mediafire.com/file/3ilmt3lfr2d57s3/HelloWorld.zip/file

Cuối cùng Tui muốn hướng dẫn các bạn cách thức đăng ký tài khoản Visual Studio 2019 Enterprise(nếu bạn có mua tài khoản)

Chỗ này nhiều bạn cũng thắc mắc, là đang chạy tự nhiên nó không cho tương tác nữa. thì nhớ đa phần do hết bản quyền sử dụng(hay hết thời gian dùng thử). Do đó không có tiền thì cứ sài Community nha.

Để đăng ký License ta vào Menu Help/ chọn Register Product:

Sau đó màn hình thông tin License hiển thị như dưới đây (thấy nói dùng thử 30 ngày không?):

Ta nhấn vào: Unlock with a Product Key

Bạn dán mã bản quyền vào đó rồi nhấn Apply. Khi nào có màn hình thông báo như dưới đây là đã kích hoạt bản quyền thành công “License: Product key applied”

Hãy cố gắng sử dụng bản quyền để bảo vệ chính mình, chính các lập trình viên.

Cám ơn các bạn đã theo dõi

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

Nhúng API Tỉ giá hối đoái của Ngân hàng Đông Á vào Website riêng – ASP.NET Core


Trong bài lấy tỉ giá hối đoái của Ngân Hàng Vietcombank, họ dùng XML để lưu trữ dữ liêu. Tui cũng đã hướng dẫn cách đọc XML từ service của Ngân hàng rồi.

Trong bài này, Tui hướng dẫn các bạn cách nhúng API tỉ giá hối đoái của Ngân Hàng Đông Á vào Website ASP .NET Core

API của họ được viết bằng JSON: http://www.dongabank.com.vn/exchange/export

Ta phân tích 1 chút xíu về cấu trúc json này của Ngân hàng Đông Á.

  • Thứ nhất:  Cấu trúc trên Ngân Hàng Đông Á đã cố tình sửa JSON bằng cách thêm ngoặc tròn bao lấy 2 đầu của dữ liệu, ta cần xóa bỏ nó đi để dữ liệu trở về đúng cấu trúc của JSON
  • Thứ 2: Ở ngoài cùng là 1 Json, bên trong là 1 mảng các tỉ giá được lưu vào biến items. Mỗi 1 phần tử trong items (Ta gọi là nó các dòng tỉ giá), nó có các thuộc tính:  type, imageurl, muatienmat, muack, bantienmat, banck
  • Thứ 3: API này Của Đông Á họ đã cấm cách truy suất thông thường, ta phải bổ sung các header là: “User-Agent” = “Mozilla/5.0 ( compatible ) ” và “Accept”] = “*/*”

Mục tiêu sau khi chạy xong Website thì nó phải nhúng được API tỉ giá của Đông Á Bank và hiển thị lên giao diện như sau:

Các bước làm làm chi tiết, các bạn thao tác theo Tui hướng dẫn:

Mở Visual Studio 2017/ chọn File/ New / Project:

Màn hình New Project sẽ hiển thị ra như dưới đây:

Chọn ASP.NET Core Web Application

đặt tên Project là “DongABank”, chọn nơi lưu trữ phù hợp rồi nhấn nút OK:

Màn hình chọn New ASP.NET Core Web Application hiển thị như dưới đây:

Ta chọn Web Application (Model – View – Controller)  và cấu hình như trên rồi nhấn nút OK để tạo Project:

Quan sát Cấu trúc JSON của Ngân Hàng Đông Á, Ta sẽ tạo 1 Lớp tên là Item (lưu ý Lớp này tên gì cũng được vì không được định nghĩa tên), thuộc tính của nó bao gồm:

Ta bấm chuột phải vào Models/Add/ Class:

Sau khi chọn Class-> màn hình sau xuất hiện:

Ta chọn Class rồi đặt tên Lớp là: Item.cs rồi bấm ADD:

Bổ sung Coding cho Item.cs dựa vào cấu trúc JSON của Ngân Hàng Đông Á Cung cấp:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DongAbank.Models
{
public class Item
{
public string type { get; set; }
public string imageurl { get; set; }
public string muatienmat { get; set; }
public string muack { get; set; }
public string bantienmat { get; set; }
public string banck { get; set; }
}
}

Tiếp tục tạo thêm 1 Lớp để lưu trữ danh sách các item: Bấm chuột phải vào models/ chọn Add/ chọn Class:

Cửa sổ tạo Class hiển thị ra:

Đặt tên lớp là TiGiaDongA (lưu ý thích đặt tên gì cũng được, miễn thuộc tính của nó phải chính xác là items)

Coding của TiGiaDongA.cs:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace DongAbank.Models
{
public class TiGiaDongA
{
public List<Item> items { get; set; }
}
}

Bước tiếp theo tạo Controller cho Website. Cụ thể là tên TiGiaDongABankController:

Bấm chuột phải vào thư mục Controller/ chọn Controller:

màn hình chọn Controller xuất hiện . Ta chọn MVC Controller – Empty:

Sau đó nhấn nút ADD:

Ta đặt tên là TiGiaDongABankController rồi bấm Add:

Hiểu chỉnh coding của Controller này để trả về Danh sách Item:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using DongAbank.Models;
using System.Net;
using System.IO;

namespace DongAbank.Controllers
{
public class TiGiaDongABankController : Controller
{
public IActionResult Index()
{
string siteContent = string.Empty;

// link JSON của DongA
string url = "http://www.dongabank.com.vn/exchange/export";

//dùng HTTPWebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
//với Đông Á Bank phải thêm 2 dòng lệnh này:
request.Headers["User-Agent"] = "Mozilla/5.0 ( compatible ) ";
request.Headers["Accept"] = "*/*";
request.AutomaticDecompression = DecompressionMethods.GZip;

//lấy đối tượng Response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
//gọi hàm GetResponseStream() để trả về đối tượng Stream
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string data = reader.ReadToEnd();
//vì dữ liệu bị bao bọc là ngoặc tròn, ta đổi nó thành rỗng để đúng cấu trúc Json
data = data.Replace(")", "").Replace("(", "");
//chuyển dữ liệu Json qua C# class:
TiGiaDongA tigia = (TiGiaDongA)JsonConvert.DeserializeObject(data,typeof(TiGiaDongA));
//trả về cho View là 1 danh sách các Item (các dòng Tỉ Giá)
return View(tigia.items);
}
}
}

Bây giờ ta tạo View cho Controller tỉ giá:

Bấm chuột phải vào hàm Index/ chọn Add View…

Màn hình Add MVC View hiển ra như dưới đây, ta chọn Template là List, Model class là Item:

Chọn xong thì bấm ADD, lúc này trang Index.cshtml được tạo ra với coding Razor như dưới đây:

Chi tiết coding cho Index.cshtml:


@model IEnumerable<DongAbank.Models.Item>

@{
ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.type)
</th>
<th>
@Html.DisplayNameFor(model => model.imageurl)
</th>
<th>
@Html.DisplayNameFor(model => model.muatienmat)
</th>
<th>
@Html.DisplayNameFor(model => model.muack)
</th>
<th>
@Html.DisplayNameFor(model => model.bantienmat)
</th>
<th>
@Html.DisplayNameFor(model => model.banck)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.type)
</td>
<td>
@Html.DisplayFor(modelItem => item.imageurl)
</td>
<td>
@Html.DisplayFor(modelItem => item.muatienmat)
</td>
<td>
@Html.DisplayFor(modelItem => item.muack)
</td>
<td>
@Html.DisplayFor(modelItem => item.bantienmat)
</td>
<td>
@Html.DisplayFor(modelItem => item.banck)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</tbody>
</table>

Bây giờ ta F5 chạy lên sẽ có được kết quả như dưới đây:

Ở đây ta cần chỉnh sửa 2 chỗ:

  • Hiển thị Hình Ảnh thay vì hiển thị link hình ảnh
  • Chỉnh tiêu đề của danh sách Tỉ giá

Ta chỉnh coding thành hiển thị hình ảnh như sau:

ở trên Tui đã thay thế thành thẻ img để hiển thị hình ảnh, và bên trong là lệnh @Url.Content để lấy hình ảnh từ Http về trình duyệt:

<img src=”@Url.Content(item.imageurl)” alt=”Image” />

Để chỉnh sửa tiêu đề thì đơn giản rồi, tự gõ vào thôi:

Bây giờ F5 chạy Website lên, ta có kết quả mới đúng như mong muốn:

Như vậy Tui đã hướng dẫn các bạn xong cách thức nhúng API Tỉ Giá Hối Đoái Của Ngân Hàng Đông Á vào Website riêng của bạn, dùng ASP .NET Core. Dữ liệu là JSON, biết cách đứa JSON thành C# class.

Coding bạn tải ở đây: Link tải coding ở đây

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

Rút trích dữ liệu Tỉ giá hối đoái của ngân hàng Vietcombank bằng ASP.NET Core


Dạo này thiết kế Website với ASP. NET Core rầm rộ, với nhiều lợi ích được mô tả ở đây: https://docs.microsoft.com/en-us/aspnet/core/?view=aspnetcore-2.1

Nên Tui cũng ngứa tay hướng dẫn các bạn 1 bài nhỏ nhỏ dùng ASP .NET Core đó là “Rút trích dữ liệu Tỉ giá hối đoái của ngân hàng Vietcombank”.

Cụ thể Ngân Hàng Vietcombank có công bố Tỉ giá hối đoái dưới dạng XML trên Website. Chúng ta có thể rút trích dữ liệu từ đây về để phục vụ cho các vấn đề khác (tra cứu tỉ giá, kết hợp du lịch)

Cụ thể các bạn vào website của Ngân Hàng: https://www.vietcombank.com.vn/

Kéo xuống dưới cùng Website, nhìn vào góc phải thấy mục “Xem thông tin tỷ giá các chi nhánh tại đây”

ta nhấn vào nút này, kết quả ta được dẫn tới trang http://www.vietcombank.com.vn/ExchangeRates/:

Nhấn vào nút XML ở trên, ta tiếp tục được dẫn tới 1 link khác : http://www.vietcombank.com.vn/ExchangeRates/ExrateXML.aspx

Bây giờ nhiệm vụ của ta là xây dựng 1 Website ASP .NET Core để truy suất và hiển thị toàn bộ tỉ giá trong này lên giao diện.

Ta khởi động Visual Studio (Tui dùng VS 2017 nha)-> rồi vào File / chọn New / chọn Project:

Lúc này màn hình tạo Project hiển thị ra như dưới đây:

Ta chọn ASP .NET Core Web Application

Đặt tên Project là “Vietcombank”, nhớ lưu vào đâu đó khác ổ C hay Desktop là OK (Desktop là ổ C đó nha) rồi bấm OK:

Lúc này màn hình tạo Project mới hiển thị ra, ta chọn Web Application (Model- View – Controllers), phía trên chọn ASP .NET Core 2.1, nhớ bỏ tick Configure for HTTPs. sau đó nhấn OK nha, Project sẽ được tạo ra như dưới đây:

Bây giờ ta tiến hành tạo các  lớp C# dạng POCO, cấu trúc của nó giống như Ngân Hàng Vietcombank cung cấp trong XML tỉ giá:

Như vậy dựa vào cấu trúc này thì ta phải tạo 2 Lớp C#. Đó là lớp Exrate và lớp ExrateList.

Exrate có các thuộc tính: CurrencyCode, CurrencyName, Buy, Transfer, Sell. Tất cả chúng đề có kiểu chuỗi là Ok (có thể Buy, Transfer, Sell ta để kiểu double cũng ngon lành (nhưng vì chả tính toán gì cả, ta phang luôn kiểu string)

ExrateList Có các thuộc tính: DateTime, List<Exrate>, Source.

Bây giờ ta lần lượt tạo các lớp:

Đầu tiên là Lớp Exrate, ta bấm chuột phải vào Models/ chọn Add/ Chọn Class:

màn hình Tạo lớp hiển thị ra như dưới đây:

Ta chọn Class, Name đặt là Exrate.cs rồi bấm Add:

Coding cho lớp Exrate này mapping với các thuộc tính, tag được định nghĩa trong XML của Ngân hàng Vietcombank:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace Vietcombank.Models
{
public class Exrate
{
[XmlAttribute(AttributeName = "CurrencyCode")]
public string CurrencyCode { get; set; }
[XmlAttribute(AttributeName = "CurrencyName")]
public string CurrencyName { get; set; }
[XmlAttribute(AttributeName = "Buy")]
public string Buy { get; set; }
[XmlAttribute(AttributeName = "Transfer")]
public string Transfer { get; set; }
[XmlAttribute(AttributeName = "Sell")]
public string Sell { get; set; }
}
}

Ở trên thấy Tui using System.Xml.Serialization, đây là thư viên liên quan XML, cho phép chuyển hóa từ XML -> C# class

Còn các [XmlAttribute(AttributeName = “CurrencyCode”)] để nói cho C# hiểu nó cần mapping đúng thuộc tính nào trong tag XML. Tên Property của C# có thể viết lung tung, nhưng trong XmlAttribute phải viết chính xác những gì Ngân Hàng Vietcombank cung cấp.

Tiếp tục lặp lại thao tác thêm lớp mới cho ExrateList:

chỉnh sửa coding cho nó như sau:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace Vietcombank.Models
{
[XmlRoot(ElementName = "ExrateList")]
public class ExrateList
{
[XmlElement(ElementName = "DateTime")]
public string DateTime { get; set; }
[XmlElement(ElementName = "Exrate")]
public List<Exrate> Exrates { get; set; }
[XmlElement(ElementName = "Source")]
public string Source { get; set; }
}
}

Bước tiếp theo là tạo 1 Controller tên là TiGiaController để rút trích dữ liệu Tỉ giá của Ngân hàng đồng thời chuyển hóa nó qua C# class để hiển thị lên Website riêng của mình:

Bấm chuột phải vào Controllers/ chọn Add/ chọn Controller…:

màn hình lựa chọn Controller xuất hiện:

Ta chọn MVC Controller Empty rồi bấm Add, màn hình yêu cầu đặt tên cho Controller xuất hiện:

ta đổi Default thành TiGia rồi bấm Add, kết quả:

Lúc này hàm Index hiển thị ra, ta bấm chuột phải vào Index để tạo View bằng cách chọn Add View… (giao diện Website cho nó):

Lúc này màn hinh tạo View hiển thị ra:

Phần Template: Chọn List (hiển thị danh sách, trong View nó là Table đó)

Phần Model calss: Chọn Exrate -> để hiển thị danh sách Exrate trong lớp ExrateList

các thông số khác để vậy nha, giờ bấm ADD:

Kết quả View hiển thị ra như dưới đây:

Coding HTML đầy đủ của Tigia/Index.cshtml


@model IEnumerable<Vietcombank.Models.Exrate>

@{
ViewData["Title"] = "Index";
}

<h2>Index</h2>

<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.CurrencyCode)
</th>
<th>
@Html.DisplayNameFor(model => model.CurrencyName)
</th>
<th>
@Html.DisplayNameFor(model => model.Buy)
</th>
<th>
@Html.DisplayNameFor(model => model.Transfer)
</th>
<th>
@Html.DisplayNameFor(model => model.Sell)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.CurrencyCode)
</td>
<td>
@Html.DisplayFor(modelItem => item.CurrencyName)
</td>
<td>
@Html.DisplayFor(modelItem => item.Buy)
</td>
<td>
@Html.DisplayFor(modelItem => item.Transfer)
</td>
<td>
@Html.DisplayFor(modelItem => item.Sell)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</tbody>
</table>

Giờ quay lại Controller: TiGiaController, tiến hành chỉnh sửa coding:


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using System.Xml.Serialization;
using Vietcombank.Models;

namespace Vietcombank.Controllers
{
public class TiGiaController : Controller
{
public IActionResult Index()
{
string siteContent = string.Empty;

// link XML của Vietcombank
string url = "https://www.vietcombank.com.vn/exchangerates/ExrateXML.aspx";

//dùng HTTPWebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;
//lấy đối tượng Response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
//gọi hàm GetResponseStream() để trả về đối tượng Stream
Stream responseStream = response.GetResponseStream();
//convert từ XML qua C# model:
XmlSerializer serializer = new XmlSerializer(typeof(ExrateList));
ExrateList exrateList =(ExrateList) serializer.Deserialize(responseStream);
//lấy danh sách Extrates truyền qua cho View
return View(exrateList.Exrates);
}
}
}

Nhấn F5 chạy lên, ta có kết quả Website như mong muốn:

Như vậy Tui đã trình bày xong cách dùng ASP .NET Core để truy suất dữ liệu Tỉ giá của ngân hàng Vietcombank, cách thức chuyển hóa từ XML thành C# class, cũng như hướng dẫn cách làm với Model – View – Controller trong ASP .NET Core.

Đây là source code của Project: Tải tại đây

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

 

Phát triển ứng dụng cơ sở dữ liệu thời gian thực với Firebase-phần 5


Trong các bài hướng dẫn trước (Xem tại đây) Tui đã trình bày hoàn chỉnh thác tác CRUD trên Realtime Database Firebase, với những ví dụ từ cơ bản đến nâng cao, nó đã giúp các bạn hiểu và tự tạo được những ứng dụng riêng để Android có thể tương tác với Realtime Database Firebase.

Ở bài này, Tui muốn hướng dẫn thêm một vài trường hợp đặc biệt đó là: Làm thể nào để Chụp hình cũng như lấy hình từ SD Card rồi đưa hình này lên Realtime Database Firebase.

Trong hệ sinh thái Firebase của Google thì họ hỗ trợ rất nhiều công cụ, trong đó có Cloud Storage For Firebase giúp bạn có thể upload/download 1 file bất kỳ lên Cloud của Google. Phần Cloud Storage Tui sẽ có những TUT hướng dẫn riêng. Còn trong bài này Tui vẫn dùng dự án từ bài số 4, tiếp tục hiệu chỉnh phần mềm để thêm các chức năng: CHỤP HÌNH + CHỌN HÌNH từ SD Card + Đưa hình lên Realtime Database Firebase + Tải hình từ Realtime Database Firebase.

Bạn nhớ mở lại Project ở phần 4 nha.

Sau đó tiến hành làm các thao tác như Tui hướng dẫn dưới này:

Tạo một màn hình mới, tên là ThemContactActivity: Bấm chuột phải vào package/ chọn new / Chọn Activit / chọn Empty Activity:

Sau đó đặt tên: ThemContactActivity

Đặt tên xong nhấn Finish để tạo màn hình, thiết kế màn hình Thêm Contact như dưới đây:

Ở trên ta có thêm 2 ImageButton: Chụp ảnh + chọn Ảnh từ SD Card

Và thêm Image View để hiển thị hình ảnh mới chụp hoặc hình ảnh lấy từ SD Card

Đây là XML layout của màn hình Thêm Contact:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ThemContactActivity">
<TextView
android:id="@+id/textView0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Contact Id:"
android:textSize="15sp" />

<EditText
android:id="@+id/edtContactId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Contact Id ở đây"
android:inputType="textPersonName"
android:textSize="15sp" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Ten:"
android:textSize="15sp" />

<EditText
android:id="@+id/edtTen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Tên ở đây"
android:inputType="textPersonName"
android:textSize="15sp" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Email:"
android:textSize="15sp" />

<EditText
android:id="@+id/edtEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Email ở đây"
android:inputType="textEmailAddress"
android:textSize="15sp" />
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Phone:"
android:textSize="15sp" />

<EditText
android:id="@+id/edtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Phone ở đây"
android:inputType="phone"
android:textSize="15sp" />
<TextView
android:id="@+id/textView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Chọn Hình:"
android:textSize="15sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >

<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnCapture"
android:src="@drawable/camera" />

<ImageButton
android:id="@+id/btnChoose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:src="@drawable/choose" />
</LinearLayout>

<ImageView
android:id="@+id/imgPicture"
android:layout_width="match_parent"
android:layout_height="150dp"
app:srcCompat="@drawable/noimage" />
<Button
android:onClick="xuLyThemMoi"
android:id="@+id/btnDongYThem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Đồng Ý Thêm"
android:textSize="15sp" />
</LinearLayout>

Chỉnh sửa coding cho ThemContactActivity để có thể đẩy hình lên Realtime Database Firebase:


package com.communityuni.advancedrealtimedatabasefirebase;

import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;

import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class ThemContactActivity extends AppCompatActivity {
ImageButton btnCapture;
ImageButton btnChoose;
ImageView imgPicture;
Bitmap selectedBitmap;
EditText edtId,edtTen,edtPhone,edtEmail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_them_contact);
addControls();
addEvents();
}
public void addControls()
{
btnCapture = findViewById(R.id.btnCapture);
btnChoose= findViewById(R.id.btnChoose);
imgPicture=findViewById(R.id.imgPicture);
edtId=findViewById(R.id.edtContactId);
edtTen=findViewById(R.id.edtTen);
edtPhone=findViewById(R.id.edtPhone);
edtEmail=findViewById(R.id.edtEmail);
}
public void addEvents() {
btnCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
capturePicture();
}
});
btnChoose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
choosePicture();
}
});
}
//xử lý chọn hình
private void choosePicture() {
Intent pickPhoto = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto , 200);//one can be replaced with any action code
}
//xử lý chụp hình
private void capturePicture() {
Intent cInt = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cInt,100);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 100&& resultCode == RESULT_OK) {
//xử lý lấy ảnh trực tiếp lúc chụp hình:
selectedBitmap = (Bitmap) data.getExtras().get("data");
imgPicture.setImageBitmap(selectedBitmap);
}
else if(requestCode == 200&& resultCode == RESULT_OK) {
try {
//xử lý lấy ảnh chọn từ điện thoại:
Uri imageUri = data.getData();
selectedBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
imgPicture.setImageBitmap(selectedBitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void xuLyThemMoi(View view) {
try {
FirebaseDatabase database = FirebaseDatabase.getInstance();
//Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
DatabaseReference myRef = database.getReference("contacts");
String contactId=edtId.getText().toString();
String ten = edtTen.getText().toString();
String phone = edtPhone.getText().toString();
String email = edtEmail.getText().toString();
myRef.child(contactId).child("phone").setValue(phone);
myRef.child(contactId).child("email").setValue(email);
myRef.child(contactId).child("name").setValue(ten);

//đưa bitmap về base64string:
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
selectedBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream .toByteArray();
String imgeEncoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
myRef.child(contactId).child("picture").setValue(imgeEncoded);

finish();
}
catch (Exception ex)
{
Toast.makeText(this,"Error:"+ex.toString(),Toast.LENGTH_LONG).show();
}
}
}

Coding ở trên có 3 điểm mới:

Thứ nhất: Chụp hình

Thứ 2: Chọn hình từ thiết bị

Thứ 3: Đưa hình về Base64String

Lưu ý rằng ta phải cấp quyền truy suất CAMERA, cũng như Storage cho phần mềm nhé, chỉnh sửa lại AndroidManifest:


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.communityuni.advancedrealtimedatabasefirebase">

<uses-feature
android:name="android.hardware.Camera"
android:required="true"></uses-feature>

<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

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

</manifest>

Sau đó bổ sung Option Menu ở màn hình MainActivity để thêm menu “Thêm Contact” cho người dùng sử dụng, bước thêm Menu xem lại phần 2:

Bổ sung coding hiển thị menu và xử lý chọn menu cho MainActivity:


@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater=getMenuInflater();
menuInflater.inflate(R.menu.main_menu,menu);
return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()==R.id.mnuAdd)
{
//mở màn hình thêm ở đây
Intent intent=new Intent(MainActivity.this,ThemContactActivity.class);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}

Chạy phần mềm lên ta có:

Xem màn hình thêm Contact có các chức năng: Chụp hình, chọn hình, đưa hình lên Realtime Database Firebase:

Lưu ý từ bản Android version 6.0 trở về đây do tính bảo mật nên những phần mềm không trực tiếp chạy từ Google Play, ngoài bước cấp quyền trong Android Manifest ra, ta còn phải cấp quyền trong thiết bị nữa mới được, nếu quên không cấp quyền thêm 1 lần nữa trong thiết bị thì ứng dụng sẽ không thể chạy được.

Ta cấp theo theo bước sau:

Quay trở lại màn hình HOME SCREEN của điện thoại, chọn phần mềm mà ta đang lập trình này-> nhấn thật lâu vào nó rồi chọn  “App Infor”:

Chọn App Infor xong ta có giao diện:

Ở trên ta thấy mục “Permissions” đang báo là chưa có quyền nào được cấp, ta nhấn vào nó:

Ta tick enable nó lên như hình ở trên-> đã thành công, giờ có thể sử dụng được phần mềm rồi nha:

Lưu ý ở trên 2 ImageButton: Chụp hình + Chọn hình tùy ta chọn nha: Muốn chụp hình Live thì bấm vào nút đầu tiên, muốn chọn 1 hình có sẵn trong máy thì chọn nút 2.

Sau khi nhập đầy đủ thông tin và hình ảnh thì bấm nút “Đồng ý thêm”, chương trình thêm thành công và quay trở về màn hình chính, lúc này ta có kết quả:

Trên Realtime Database Firebase ta có hình ảnh dưới dạng Base64String, và giao diện cũng có Contact mới này.

Như vậy là tới đây Tui đã hướng dẫn xong bước thêm 1 Contact có hình ảnh.

Bây giờ ta bổ sung chức năng cập nhập Contact. Vì trước đó ta có các Contact mà chưa có hình ảnh (tức là không có thuộc tính picture). giờ ta thêm chức năng này để cập nhật hình cho bất kỳ contact nào.

Ta tạo màn hình tên “CapNhatContactActivity”, bước làm tương tự như ThemContactActivity. ta chỉnh giao diện màn hình cập nhật như dưới đây:

Đây là XML layout của màn hình Cập nhật:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".CapNhatContactActivity">
<TextView
android:id="@+id/textView0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Contact Id:"
android:textSize="15sp" />

<EditText
android:id="@+id/edtContactId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Contact Id ở đây"
android:inputType="textPersonName"
android:textSize="15sp" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Ten:"
android:textSize="15sp" />

<EditText
android:id="@+id/edtTen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Tên ở đây"
android:inputType="textPersonName"
android:textSize="15sp" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Email:"
android:textSize="15sp" />

<EditText
android:id="@+id/edtEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Email ở đây"
android:inputType="textEmailAddress"
android:textSize="15sp" />
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Phone:"
android:textSize="15sp" />

<EditText
android:id="@+id/edtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Phone ở đây"
android:inputType="phone"
android:textSize="15sp" />
<TextView
android:id="@+id/textView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Chọn Hình:"
android:textSize="15sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >

<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnCapture"
android:src="@drawable/camera" />

<ImageButton
android:id="@+id/btnChoose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:src="@drawable/choose" />
</LinearLayout>

<ImageView
android:id="@+id/imgPicture"
android:layout_width="match_parent"
android:layout_height="150dp"
app:srcCompat="@drawable/noimage" />
<Button
android:onClick="xuLyCapNhat"
android:id="@+id/btnDongCapNhat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Đồng Ý Cập Nhật"
android:textSize="15sp" />
</LinearLayout>

Nhiệm vụ của màn hình Cập nhật là:

  • hiển thị chi tiết Contact được chọn trên giao diện ListView, bao gồm hình ảnh  Base64String được tải về từ Realtime database firebase
  • cho phép cập nhật dữ liệu cho Contact bao gồm cả hình ảnh

Chỉnh sửa coding của MainActivity: Nhấn vào 1 Contact nào trên Listview thì mở màn hình Cập nhật ra:


lvContact.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Contact data=adapter.getItem(position);
Intent intent=new Intent(MainActivity.this,CapNhatContactActivity.class);
intent.putExtra("KEY",data.getContactId());
startActivity(intent);
}
});

Tiếp tục chỉnh sửa coding của màn hình CapNhatContactActivity:


package com.communityuni.advancedrealtimedatabasefirebase;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.Toast;

import com.communityuni.model.Contact;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;

public class CapNhatContactActivity extends AppCompatActivity {

EditText edtId,edtTen,edtPhone,edtEmail;
ImageView imgPicture;
ImageButton btnCapture;
ImageButton btnChoose;
Bitmap selectedBitmap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cap_nhat_contact);
addControls();
getContactDetail();
addEvents();
}

private void getContactDetail() {
Intent intent=getIntent();
final String key=intent.getStringExtra("KEY");
final FirebaseDatabase database = FirebaseDatabase.getInstance();
//Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
DatabaseReference myRef = database.getReference("contacts");

//truy suất và lắng nghe sự thay đổi dữ liệu
//chỉ truy suất node được chọn trên ListView myRef.child(key)
//addListenerForSingleValueEvent để lấy dữ liệu đơn
myRef.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
try {
Contact contact=dataSnapshot.getValue(Contact.class);
contact.setContactId(dataSnapshot.getKey());
edtId.setText(contact.getContactId());
edtTen.setText(contact.getName());
edtEmail.setText(contact.getEmail());
edtPhone.setText(contact.getPhone());
if(contact.getPicture()!=null) {
byte[] decodedString = Base64.decode(contact.getPicture(), Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
imgPicture.setImageBitmap(decodedByte);
}
}
catch (Exception ex)
{
Log.e("LOI_JSON",ex.toString());
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w("LOI_CHITIET", "loadPost:onCancelled", databaseError.toException());
}
});
}

private void addControls() {
btnCapture = (ImageButton) findViewById(R.id.btnCapture);
btnChoose= (ImageButton) findViewById(R.id.btnChoose);
imgPicture= (ImageView) findViewById(R.id.imgPicture);
edtId=findViewById(R.id.edtContactId);
edtTen=findViewById(R.id.edtTen);
edtPhone=findViewById(R.id.edtPhone);
edtEmail=findViewById(R.id.edtEmail);
}
public void addEvents() {
btnCapture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
capturePicture();
}
});
btnChoose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
choosePicture();
}
});
}
private void choosePicture() {
Intent pickPhoto = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickPhoto , 200);//one can be replaced with any action code
}

private void capturePicture() {
Intent cInt = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cInt,100);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 100&& resultCode == RESULT_OK) {
//xử lý lấy ảnh trực tiếp lúc chụp hình:
selectedBitmap = (Bitmap) data.getExtras().get("data");
imgPicture.setImageBitmap(selectedBitmap);
}
else if(requestCode == 200&& resultCode == RESULT_OK) {
try {
//xử lý lấy ảnh chọn từ điện thoại:
Uri imageUri = data.getData();
selectedBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
imgPicture.setImageBitmap(selectedBitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void xuLyCapNhat(View view) {
try {
FirebaseDatabase database = FirebaseDatabase.getInstance();
//Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
DatabaseReference myRef = database.getReference("contacts");
String contactId=edtId.getText().toString();
String ten = edtTen.getText().toString();
String phone = edtPhone.getText().toString();
String email = edtEmail.getText().toString();
myRef.child(contactId).child("phone").setValue(phone);
myRef.child(contactId).child("email").setValue(email);
myRef.child(contactId).child("name").setValue(ten);

//đưa bitmap về base64string:
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
selectedBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream .toByteArray();
String imgeEncoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
myRef.child(contactId).child("picture").setValue(imgeEncoded);

finish();
}
catch (Exception ex)
{
Toast.makeText(this,"Error:"+ex.toString(),Toast.LENGTH_LONG).show();
}
}
}

Chạy phần mềm lên, ta chỉnh sửa dữ liệu cho contact7:

Khi cập nhật thành công, lúc này contact7 sẽ được bổ sung thêm thuộc tính picture và có giá trị là base64string cho bức hình gửi từ điện thoại lên.

Như vậy Tui đã hoàn chỉnh hướng dẫn toàn bộ chức năng CRUD nâng cao, bao gồm đưa hình ảnh lên Realtime Database Firebase và tải hình ảnh từ Realtime Database Firebase về điện thoại. Bài này khá phức tạp nhưng rất hay, Các bạn cố gắng hoàn thành nha.

Coding đầy đủ các bạn tải tại đây: Tải source code tại đây

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

Phát triển ứng dụng cơ sở dữ liệu thời gian thực với Firebase-phần 4


Như vậy Tui đã hướng dẫn xong toàn bộ CRUD trong Realtime Database Firebase, các bạn nhớ làm theo thứ tự bài 1, bài 2, bài 3 nha.

Ở bài này Tui sẽ trình bày cách sử dụng Firebase ở mức cao hơn 1 xíu đó là: Sử dụng Java model class, Custom layout, tái sử dụng lại Realtime database ở bài trước(tức là giờ có 2 App cùng sử dụng 1 CSDL). Để giúp phần mềm được chuyên nghiệp và dễ dàng hơn cho Dev cũng như Customer.

Kết thúc bài này, ta có giao diện phần mềm như sau:

Các bước làm giống như các bài trước. Tuy nhiên trong bài này ta sẽ Bổ sung Customlayout, model class.

Tui mới update Android studio version mới nhất 3.2.1 (Tính tới ngày 15/10/2018) nên Tui new lại Project từ đầu nha.

Khởi động Android Studio:

Chọn Start a new Android Studio project:

Đặt tên Project là AdvancedRealtimeDatabaseFirebase rồi bấm Next

Chọn API 26 rồi bấm Next:

Tiếp tục chọn Empty Activity trong màn hình trên rồi bấm Next:

Mặc định để MainActivity rồi bấm Finish để tạo Project:

Đợi cho Project tạo xong ta sẽ kết nối tới Firebase bằng cách vào menu Tools/ chọn Firebase:

Sau khi chọn Firebase, lúc này công cụ trợ giúp sẽ xuất hiện:

Google cung cấp rất nhiều Service, nhưng ta cũng quan tâm tới Realtime Database-> nhấn vào mục có chữ này:

Tiếp tục nhấn vào “Save and retrieve data” để kết nối Realtime Database:

Google cũng  cung cấp nhiều bước, ta nhấn vào bước 1 “Connect to Firebase”, lúc này cửa sổ kết nối Firebase xuất hiện, tại bài Advanced này Tui muốn tái sử dụng lại CSDL ở các bài trước, Tui sẽ chọn mục số 2 “Choose an existing Firebase ỏ Google Project”:

Lúc này màn hình sẽ như sau:

rõ ràng ở trên bạn thấy “RealtimeDatabaseFirebase”, là Project ở các bài trước. Giờ ta bấm “Connect to Firebase”:

Ta chờ nó kết nối nha, nếu có lỗi xảy ra nó sẽ xuất hiện thông báo như màn hình dưới đây:

Đừng lo lắng, tiếp tục bấm lại “Connect to Firebase”, lúc này màn hình sau xuất hiện:

Ta nhấn vào “Sync” để đồng bộ, kết quả sẽ thành công như dưới đây:

Tiếp tục nhấn vào “Add the Realtime Database Rules” ở bước 2:

Chương trình sẽ yêu cầu thêm một số thư viện vào build.gradle. Ta nhấn Accept Changes:

Quan sát tập tin build.gradle, có lệnh: implementation ở cuối cùng. Ta xóa :15.0.0 đi:

Sau đó nhấn vào nút Try Again ở góc trên màn hình thông báo lỗi. Sau khi thành công thì ta bắt đầu lập trình được rồi. Lưu ý là khi kết nối thành công thì trên Firebase Console ta cũng thấy xuất hiện app này nha:

Như vậy bây giờ là 2 Ứng dụng Android có thể sử dụng chung 1 cơ sở dữ liệu Realtime Database Firebase rồi.

Ta xem lại cấu trúc JSON trên Firebase:

Bây giờ ta sẽ tạo 1 java class để mapping dữ liệu: Bằng cách nhấn chuột phải vào java/ chọn New / chọn Package:

Lúc này cửa sổ tạo package sẽ show ra như dưới đây:

Ta chọn dòng giữa rồi nhấn OK:

Đặt tên Package mới rồi nhấn OK. Lưu ý model để cuối cùng nha, sao cho nó có cấu trúc như vầy cho nó khóa học:

Tiếp tục nhấn chuột phải vào model / chọn New / chọn Java Class:

Màn hình tạo Lớp mới xuất hiện ra như bên dưới. Ta đặt tên lớp là Contact:

Nhấn OK để đồng ý tạo lớp Contact:

Chỉ sửa coding cho Lớp Contact này như dưới đây:


package com.communityuni.model;

public class Contact {
private String contactId;
private String name;
private String phone;
private String email;

public String getContactId() {
return contactId;
}

public void setContactId(String contactId) {
this.contactId = contactId;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPhone() {
return phone;
}

public void setPhone(String phone) {
this.phone = phone;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}

Vì ta làm Custom Layout để hiển thị danh sách Contact như hình:

Nên ta cần tạo 1 layout như sau:

Bấm chuột phải vào layout/ chọn New / chọn Layout resource file:

Đặt tên file là item rồi bấm OK:

Sau khi bấm OK, ta có giao diện:

Chỉnh sửa layout của item.xml sao cho giao diện đáp ứng yêu cầu:

Dưới đây là file XML layout của item.xml:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:orientation="vertical">

<TextView
android:id="@+id/txtId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="@android:color/holo_red_dark"
android:textSize="25sp" />

<TextView
android:id="@+id/txtName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="?android:attr/colorActivatedHighlight"
android:textSize="25sp" />

<TextView
android:id="@+id/txtEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="@android:color/holo_green_dark"
android:textSize="25sp" />

<TextView
android:id="@+id/txtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="@android:color/holo_blue_dark"
android:textSize="25sp" />

<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="3dp"
android:background="?attr/colorControlActivated" />
</LinearLayout>

Tiếp tục lặp lại bước tạo package mới, đó là package adapter:

Bấm chuột phải vào java/ chọn New/ chọn Package:

Chọn mục số 2:

Nhấn OK để đặt tên cho Package:

package adapter cũng đồng cấp với package model:

Tiếp tục tạo một lớp tên là : ContactAdapter để vẽ giao diện theo Custom Layout

Bấm chuột phải vào thư mục adapter/ chọn New/ chọn Java Class:

Đặt tên cho Class là ContactAdapter:

Sau đó nhấn OK để đồng ý tạo class, chỉnh sửa coding cho ContactAdapter như dưới đây:


package com.communityuni.adapter;

import android.app.Activity;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.communityuni.advancedrealtimedatabasefirebase.R;
import com.communityuni.model.Contact;

public class ContactAdapter extends ArrayAdapter<Contact> {
Activity context;
int resource;
public ContactAdapter(Activity context, int resource) {
super(context, resource);
this.context=context;
this.resource=resource;
}

@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View custom=context.getLayoutInflater().inflate(resource,null);
TextView txtId=custom.findViewById(R.id.txtId);
TextView txtName=custom.findViewById(R.id.txtName);
TextView txtPhone=custom.findViewById(R.id.txtPhone);
TextView txtEmail=custom.findViewById(R.id.txtEmail);
Contact contact=getItem(position);
txtId.setText(contact.getContactId());
txtName.setText(contact.getName());
txtPhone.setText(contact.getPhone());
txtEmail.setText(contact.getEmail());
return custom;
}
}

 

OK, cũng sắp xong rồi. Bây giờ bạn quay lại MainActivity để coding:


package com.communityuni.advancedrealtimedatabasefirebase;

import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;

import com.communityuni.adapter.ContactAdapter;
import com.communityuni.model.Contact;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

public class MainActivity extends AppCompatActivity {

ListView lvContact;
ContactAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addControls();
getContactsFromFirebase();
}
private void getContactsFromFirebase() {
FirebaseDatabase firebaseDatabase=FirebaseDatabase.getInstance();
DatabaseReference myRef= firebaseDatabase.getReference("contacts");
adapter.clear();
myRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot dss : dataSnapshot.getChildren())
{
//convert ra đối tượng Contact:
Contact contact=dss.getValue(Contact.class);
String key=dss.getKey();
contact.setContactId(key);
adapter.add(contact);
}
}

@Override
public void onCancelled(@NonNull DatabaseError databaseError) {

}
});
}

private void addControls() {
lvContact=findViewById(R.id.lvContact);
adapter=new ContactAdapter(this,R.layout.item);
lvContact.setAdapter(adapter);
}
}

ở trên ta thấy dòng lệnh 37:

Contact contact=dss.getValue(Contact.class);

Dòng lệnh này để đưa dữ liệu trong HashMap về đúng kiểu Contact (nó tự mapping)

Khi có đối tượng contact rồi thì ta dán nó vào adapter là tự nhiên có giao diện như mong muốn

Chạy phần mềm lên ta sẽ có kết quả như sau:

Như vậy Tui đã hướng dẫn xong cách dùng model class, customlayout để truy suất dữ liệu từ Firebase. Cách làm cũng tương tự như loại cơ bản. tuy nhiên cách này sẽ khoa học hơn, tùy biến nhanh hơn.

Ngoài ra các thao tác Thêm, Sửa, Xóa. Các bạn có thể cho chương trình lắng nghe kết quả trả về, tương tự như:

Ví dụ: Thêm sự kiện xóa Contact khi nhấn lâu vào ListView và kiểm tra kết quả thành công hay thất bại:


protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addControls();
getContactsFromFirebase();
addEvents();
}
private void addEvents() {

lvContact.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Contact contact=adapter.getItem(position);
FirebaseDatabase firebaseDatabase=FirebaseDatabase.getInstance();
DatabaseReference myRef= firebaseDatabase.getReference("contacts");
myRef.child(contact.getContactId()).removeValue()
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(MainActivity.this,"Thành công",Toast.LENGTH_LONG).show();

adapter.remove(contact);
}})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivity.this,"Lỗi rồi :"+ e.toString(),Toast.LENGTH_LONG).show();
}
});
return false;
}
});
}

Xử lý cho Thêm Contact tương tự nha!

Đây là sourcode của chương trình: Tải ở đây

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

Phát triển ứng dụng cơ sở dữ liệu thời gian thực với Firebase-phần 3


Bài 1 các bạn đã biết cách kết nối và truy vấn Realtime Database Firebase, Bài 2 biết cách thêm mới dữ liệu vào Firbase. Trong bài này Tui sẽ hướng dẫn các bạn cách chỉnh sửa và xóa dữ liệu khỏi Realtime Database Firebase.

Tiếp tục mở lại Project ở bài 2, Ta bổ sung thêm 3 chức năng: Lấy chi tiết Cập nhật và xóa.

Ta tạo một màn hình mới tên là CapNhatContactActivity, bằng cách bấm chuột phải vào package/ chọn New / Chọn Activity/ chọn Empty Activity:

Sau khi chọn Empty Activity, ta nhập tên CapNhatContactActivity:

sau khi nhập xong, nhấn FINISH để tạo màn hình Cập nhật, thiết kế giao diện màn hình này như hình dưới đây:

Mục đích của màn hình này là:

– Truy vấn chi tiết 1 Contact trên Firebase dựa vào Contact ID được chọn trên ListView ở màn hình chính

– Cho phép Cập nhật

– Cho phép Xóa

XML Layout của màn hình này như sau:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".CapNhatContactActivity">
    <TextView
        android:id="@+id/textView0"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Nhập Contact Id:"
        android:textSize="25sp" />
    <EditText
        android:id="@+id/edtContactId"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="Contact Id ở đây"
        android:inputType="textPersonName"
        android:textSize="25sp" />
    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Nhập Ten:"
        android:textSize="25sp" />
    <EditText
        android:id="@+id/edtTen"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="Tên ở đây"
        android:inputType="textPersonName"
        android:textSize="25sp" />
    <TextView
        android:id="@+id/textView2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Nhập Email:"
        android:textSize="25sp" />
    <EditText
        android:id="@+id/edtEmail"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="Email ở đây"
        android:inputType="textEmailAddress"
        android:textSize="25sp" />
    <TextView
        android:id="@+id/textView3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Nhập Phone:"
        android:textSize="25sp" />
    <EditText
        android:id="@+id/edtPhone"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Phone ở đây"
        android:inputType="phone"
        android:textSize="25sp" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btnChinhSua"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Cập Nhật"
            android:textSize="25sp" />
        <Button
            android:id="@+id/btnXoa"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Xóa"
            android:textSize="25sp" />
    </LinearLayout>
</LinearLayout>

Tiến hành bổ sung sự kiện cho ListView ở màn hình MainActivity:

lvContact.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        String data=adapter.getItem(position);
        String key=data.split("\n")[0];
        Intent intent=new Intent(MainActivity.this,CapNhatContactActivity.class);
        intent.putExtra("KEY",key);
        startActivity(intent);
    }
});

Vì ở màn hình chính Tui hiển thị mỗi dòng là các thông số Contact Id, Phone, Email, Name được nối nhau bằng ký tự xuống dòng \n. Nên ở đây khi có được dòng đang chọn, Tui dùng hàm split để tách ra, phần tử đầu tiên là Contact ID nên lấy index là [0]

Contact ID này sẽ được gửi qua màn hình CapNhatContactActivity, Tui đặt tên nó là KEY. Bên màn hình Cập nhật sẽ dựa vào KEY này để lấy thông tin chi tiết từ Firebase cũng như dùng cho cập nhật, xóa (Các bạn đừng thắc mắc là tại sao không truyền hết qua luôn để không phải mất công truy suất lại). Ở đây Tui có 2 lý do:

  • Lý do 1: Tui muốn hướng dẫn các bạn cách lấy thông tin chi tiết từ Firebase khi có Key
  • Lý do 2: Trong thực tế dữ liệu có rất nhiều thuộc tính, trong màn hình danh sách không phải tải hết về, mà chỉ tải một số thông tin quan trọng, do đó trong màn hình chí tiết ta mới tải hết về dựa vào Key

OK, giờ quay lại màn hình CapNhatContactActivity, coding để lấy chi tiết Contact:

package com.communityuni.realtimedatabasefirebase;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.HashMap;

public class CapNhatContactActivity extends AppCompatActivity {
    EditText edtId,edtTen,edtPhone,edtEmail;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cap_nhat_contact);
        addControls();
        getContactDetail();
    }

    private void getContactDetail() {
        Intent intent=getIntent();
        final String key=intent.getStringExtra("KEY");
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        //Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
        DatabaseReference myRef = database.getReference("contacts");

        //truy suất và lắng nghe sự thay đổi dữ liệu
        //chỉ truy suất node được chọn trên ListView myRef.child(key)
        //addListenerForSingleValueEvent để lấy dữ liệu đơn
        myRef.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                try {
                    //nó trả về 1 DataSnapShot, mà giá trị đơn nên gọi getValue trả về 1 HashMap
                    HashMap<String,Object> hashMap= (HashMap<String, Object>) dataSnapshot.getValue();
                    //HashMap này sẽ có kích  thước bằng số Node con bên trong node truy vấn
                    //mỗi phần tử có key là name được định nghĩa trong cấu trúc Json của Firebase
                    edtId.setText(key);
                    edtTen.setText(hashMap.get("name").toString());
                    edtEmail.setText(hashMap.get("email").toString());
                    edtPhone.setText(hashMap.get("phone").toString());
                }
                 catch (Exception ex)
                {
                    Log.e("LOI_JSON",ex.toString());
                }
            }
            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.w("LOI_CHITIET", "loadPost:onCancelled", databaseError.toException());
            }
        });
    }

    private void addControls() {
        edtId=findViewById(R.id.edtContactId);
        edtTen=findViewById(R.id.edtTen);
        edtPhone=findViewById(R.id.edtPhone);
        edtEmail=findViewById(R.id.edtEmail);
    }
}

Lưu ý trong sự kiện lấy chi tiết, Tui dùng addListenerForSingleValueEvent, nó khác với lấy danh sách Contact trong MainActivity nha (addValueEventListener).

Chạy lên ta có kết quả:

Khi chọn 1 Contact, ví dụ như Putin–> nó sẽ mò lên Realtime Database Firebase để lấy chi tiết  và trả về cho màn hình CapNhatContactActivity.

Tiếp tục bổ sung 2 sự kiện (dùng onClick XML) Cập nhật và Xóa cho màn hình Cập Nhật:

<Button
    android:id="@+id/btnChinhSua"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="xuLySua"
    android:text="Cập Nhật"
    android:textSize="25sp" />
<Button
    android:id="@+id/btnXoa"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="xuLyXoa"
    android:text="Xóa"
    android:textSize="25sp" />

Coding cho 2 sự kiện này trong màn hình CapNhatContactActivity như sau:

Sự kiện sửa:

public void xuLySua(View view) {
    String key=edtId.getText().toString();
    String phone=edtPhone.getText().toString();
    String name=edtTen.getText().toString();
    String email=edtEmail.getText().toString();
    FirebaseDatabase database = FirebaseDatabase.getInstance();
    //Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
    DatabaseReference myRef = database.getReference("contacts");
    myRef.child(key).child("phone").setValue(phone);
    myRef.child(key).child("email").setValue(email);
    myRef.child(key).child("name").setValue(name);
    finish();
}

Ở trên biến key là ContactId, ta sửa giá trị các node bên trong của nó lần lượt có: Phone, email, name:

myRef.child(key).child(“phone”) -> truy suất tới node phone

myRef.child(key).child(“phone”).setValue(phone)–> đổi mới giá trị cho node phone.

Sự kiện Xóa:

public void xuLyXoa(View view) {
    String key=edtId.getText().toString();
    FirebaseDatabase database = FirebaseDatabase.getInstance();
    //Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
    DatabaseReference myRef = database.getReference("contacts");
    myRef.child(key).removeValue();
    finish();
}

Ta dùng hàm removeValue() để xóa, hoặc setValue(null) nha. Còn muốn cập nhập/ xóa nhiều thì dùng hàm updateChildren, truyền vào là 1 HashMap.

Cuối cùng ta có coding đầy đủ của màn hình CapNhatContactActivity như sau:

package com.communityuni.realtimedatabasefirebase;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.HashMap;

public class CapNhatContactActivity extends AppCompatActivity {
    EditText edtId,edtTen,edtPhone,edtEmail;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_cap_nhat_contact);
        addControls();
        getContactDetail();
    }

    private void getContactDetail() {
        Intent intent=getIntent();
        final String key=intent.getStringExtra("KEY");
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        //Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
        DatabaseReference myRef = database.getReference("contacts");

        //truy suất và lắng nghe sự thay đổi dữ liệu
        //chỉ truy suất node được chọn trên ListView myRef.child(key)
        //addListenerForSingleValueEvent để lấy dữ liệu đơn
        myRef.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                try {
                    //nó trả về 1 DataSnapShot, mà giá trị đơn nên gọi getValue trả về 1 HashMap
                    HashMap<String,Object> hashMap= (HashMap<String, Object>) dataSnapshot.getValue();
                    //HashMap này sẽ có kích  thước bằng số Node con bên trong node truy vấn
                    //mỗi phần tử có key là name được định nghĩa trong cấu trúc Json của Firebase
                    edtId.setText(key);
                    edtTen.setText(hashMap.get("name").toString());
                    edtEmail.setText(hashMap.get("email").toString());
                    edtPhone.setText(hashMap.get("phone").toString());
                }
                 catch (Exception ex)
                {
                    Log.e("LOI_JSON",ex.toString());
                }
            }
            @Override
            public void onCancelled(DatabaseError databaseError) {
                Log.w("LOI_CHITIET", "loadPost:onCancelled", databaseError.toException());
            }
        });
    }

    private void addControls() {
        edtId=findViewById(R.id.edtContactId);
        edtTen=findViewById(R.id.edtTen);
        edtPhone=findViewById(R.id.edtPhone);
        edtEmail=findViewById(R.id.edtEmail);
    }

    public void xuLySua(View view) {
        String key=edtId.getText().toString();
        String phone=edtPhone.getText().toString();
        String name=edtTen.getText().toString();
        String email=edtEmail.getText().toString();
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        //Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
        DatabaseReference myRef = database.getReference("contacts");
        myRef.child(key).child("phone").setValue(phone);
        myRef.child(key).child("email").setValue(email);
        myRef.child(key).child("name").setValue(name);
        finish();
    }
    public void xuLyXoa(View view) {
        String key=edtId.getText().toString();
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        //Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
        DatabaseReference myRef = database.getReference("contacts");
        myRef.child(key).removeValue();
        finish();
    }
}

Chạy phần mềm lên, giả sử chọn Contact có tên là Tám:

Ta bấm cập nhật, dữ liệu sẽ được update luôn trên Firebase Server, và bất kỳ client nào đang sài phần mềm này cũng thấy sự thay đổi đó.

Giả sử bạn nhấn nút Xóa, trên Firebase sẽ đánh dấu mà đỏ báo cho ta chuẩn bị xóa-> và xóa thành công:

Như vậy Tui đã hướng dẫn xong cách: lấy chi tiết, cập nhật và xóa, các bạn thực hành lại nha.

Đây là source code của phần này: Tải code ở đây

Bài sau Tui sẽ hướng dẫn phần nâng cao: dùng java model class, cũng như lắng nghe kết quả thực hiện, transaction… các bạn chú ý theo dõi.

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

Phát triển ứng dụng cơ sở dữ liệu thời gian thực với Firebase-phần 2


phần 1 Tui đã hướng dẫn các bạn cách thức kết nối Android Studio tới Realtime Database Firebase,  cách thao tác Cơ sở dữ liệu trên console.firebase.google.com cũng như cách thức truy suất danh sách Contact từ Realtime Database Firebase xuống Client.

Ở bài này Tui sẽ hướng dẫn các bạn cách thức thêm mới dữ liệu từ Android lên Realtime Database. Tuy nhiên Tui vẫn sử dụng cách thức cơ bản nhất, khi nào qua hết tất cả các bài cơ bản, Tui sẽ trình bày phần nâng cao đó là sử dụng Model class, Transaction…. Còn những bài này chỉ cần các bạn hiểu cơ chế hoạt động, cách thức gọi lệnh là đủ rồi.

Tiếp tục mở lại Project đã được hướng dẫn trong phần 1.

Bổ sung Option Menu có 1 MenuItem là “Thêm Contact”  như hình dưới đây:

Để them Menu ta làm như sau:

Bấm chuột phải vào thư mục res/ chọn new/ chọn Directory:

Sau khi chọn Director, Android Studio sẽ cung cấp 1 màn hình yêu cầu ta đặt tên, Ta sẽ đặt tên Directory là: menu như hình trong màn hình dưới đây:

Đặt tên xong bấm OK, ta thấy thư mục menu được tạo vào Project:

Tiếp tục bấm chuột phải vào menu/ chọn New/ chọn menu resource file:

Android Studio sẽ cung cấp màn hình cho ta đặt tên menu cũng như các thông số cấu hình khác:

Để đơn giản, ta chỉ quan tâm tới phần File Name, đặt tên là : main_menu rồi bấm OK:

Ta tiến hành kéo Menu Item ra, đổi nhãn thành Thêm Contact, đặt id là mnuAdd.

đây là main_menu.xml:


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/mnuAdd"
android:title="Thêm Contact" />
</menu>

Trong coding của màn hình MainActivity, Ta Override hàm onCreateOptionsMenu ra để tạo Menu cho Activity:

Chỉ cần gõ onCreate thì Android Studio cũng gợi ý ra hàm onCreateOptionsMenu, ta chỉ cần Enter là nó xổ hết ra cho lẹ:

Sau đó ta tiến hành cập nhật Coding như dưới đây:


@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater=getMenuInflater();
menuInflater.inflate(R.menu.main_menu,menu);
return super.onCreateOptionsMenu(menu);
}

Tiếp tục bổ sung hàm xử lý người dùng lựa chọn MenuItem – onOptionsItemSelected, ta cũng chi cần gõ 1 vài ký tự đầu onOption… nó tự xổ ra và ta chọn cho lẹ:

Ta sẽ có coding như sau:


@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()==R.id.mnuAdd) // kiểm tra người dùng chọn Menu Thêm Contact
{
//mở màn hình thêm ở đây (sẽ gọi sau)
}
return super.onOptionsItemSelected(item);
}

Giờ Ta thêm một màn hình mới để nhập liệu cho Contact: Bấm chuột phải vào Package/ chọn New/ chọn Activity/ chọn Empty Activity :

Màn hình tạo Activity hiển thị ra, ta tiến hành đặt tên cho màn hình:

Ở trên ta đặt: là ThemContactActivity rồi bấm Finish
Tiến hành thiết kế giao diện cho màn hình Thêm mới:

XML Layout của activity_them_contact.xml như sau:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ThemContactActivity">
<TextView
android:id="@+id/textView0"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Contact Id:"
android:textSize="25sp" />

<EditText
android:id="@+id/edtContactId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Contact Id ở đây"
android:inputType="textPersonName"
android:textSize="25sp" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Ten:"
android:textSize="25sp" />

<EditText
android:id="@+id/edtTen"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Tên ở đây"
android:inputType="textPersonName"
android:textSize="25sp" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Email:"
android:textSize="25sp" />

<EditText
android:id="@+id/edtEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="Email ở đây"
android:inputType="textEmailAddress"
android:textSize="25sp" />
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Nhập Phone:"
android:textSize="25sp" />

<EditText
android:id="@+id/edtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Phone ở đây"
android:inputType="phone"
android:textSize="25sp" />

<Button
android:onClick="xuLyThemMoi"
android:id="@+id/btnDongYThem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Đồng Ý Thêm"
android:textSize="25sp" />

</LinearLayout>

Để có thể lưu một dữ liệu mới từ Client lên Database Firebase thì không mấy khó khăn, do Google cung cấp cho ta phương thức đơn giản là: setValue(dữ_liệu). Nếu chưa tồn tại Name trên Firebase thì nó tự thêm mới, nếu Name đã tồn tại thì trở thành cập nhật. Một số loại dữ liệu mà Firebase hỗ trợ đó là:

  • String
  • Long
  • Double
    Boolean
  • Map<String, Object>
  • List<Object>

Object có thể là Java Object, ta đẩy luôn 1 đối tượng hoặc danh sách đối tượng lên Server Firebase được luôn nha (Sẽ trình bày chi tiết ở những bài sau).

Cái khó của phần này chắc chỉ là do ta mapping sai giữa cấu trúc JSON trên Realtime Database Firebase với các biến truyền vào trong Android mà thôi.

Chúng ta xem cái hình Tui chụp dưới này:

Hình trên là bộ 3: Giao diện tương tác – Coding – Reatime Database Firebase

Các bạn nhìn kỹ các mũi tên mà Tui  trỏ nha. Cấu trúc Cơ sở dữ liệu (JSON) trong Firebase như thế nào thì bạn phải truyền cho đúng nha.

Ở trên cấu trúc JSON ta có:

1 element contacts . Trong thẻ contacts  có rất nhiều element con contactX, Mỗi element con này lại có 3 Element con là: email, name, phone. Trong coding ta phải so khớp chính xác với các thành phần này nha. So Khớp chính xác thì tự nhiên dữ liệu sẽ được lưu thành công, và phía mobile client bất kỳ sẽ tự động cập nhật khi có dữ liệu thay đổi (Realtime)

Chi tiết Coding cho màn hình ThemContactActivity:


package com.communityuni.realtimedatabasefirebase;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;

public class ThemContactActivity extends AppCompatActivity {
EditText edtId,edtTen,edtPhone,edtEmail;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_them_contact);
addControls();
}
private void addControls() {
edtId=findViewById(R.id.edtContactId);
edtTen=findViewById(R.id.edtTen);
edtPhone=findViewById(R.id.edtPhone);
edtEmail=findViewById(R.id.edtEmail);
}

public void xuLyThemMoi(View view) {
try {
FirebaseDatabase database = FirebaseDatabase.getInstance();
//Kết nối tới node có tên là contacts (node này do ta định nghĩa trong CSDL Firebase)
DatabaseReference myRef = database.getReference("contacts");
String contactId=edtId.getText().toString();
String ten = edtTen.getText().toString();
String phone = edtPhone.getText().toString();
String email = edtEmail.getText().toString();
myRef.child(contactId).child("phone").setValue(phone);
myRef.child(contactId).child("email").setValue(email);
myRef.child(contactId).child("name").setValue(ten);
finish();
}
catch (Exception ex)
{
Toast.makeText(this,"Error:"+ex.toString(),Toast.LENGTH_LONG).show();
}
}
}

Cuối cùng chỉnh sửa sự kiện nhấn MenuItem trong màn hình MainActivity:


@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()==R.id.mnuAdd)
{
//mở màn hình thêm ở đây
Intent intent=new Intent(MainActivity.this,ThemContactActivity.class);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}

Chạy lên Ta sẽ có kết quả như mong muốn: bất kỳ 1 Thiết bị nào thêm mới 1 Contact –> nó Sẽ được lưu trên RealTime Database Firebase –> Tất cả các thiết bị khác sẽ tự động cập nhật mới khi có dữ liệu thay đổi.

Đây là Coding đầy đủ của phần này: Link tải tại đây

Phần sau Tui sẽ trình bày cách Chỉnh sửa và Xóa dữ liệu khỏi RealTime Database Firebase cũng như lắng nghe kết quả thay công hay thất bại.

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

%d bloggers like this: