T ổng h ợp các k ĩ thu ật Android nâng cao
tác gi ả:V ũXuân Tr ườ
ng
Google Store: />Bài 1: Gi ới thi ệu chung v ề Android
1. Android là gì?
-Là một hệ điều hành trên các thiết bị di động smartphone
được phát triển bới Google dựa trên hệ điều hành Linux.
-Các ứng dụng Android đều phát triển dựa trên ngôn ngữ
Java
2. Tại sao phải học Android?
-Ngày nay thiết bị di động sử dụng Android phát triển ngày
càng mạnh mẽ
3. Những kiến thức căn bản để học Android
-Căn bản về kĩ thuật lập trình
-Java căn bản
-Chịu khó
Bài 2: Cách cài máy ảo chính thống Emulator của Android
Studio
Bước 1: Tải và cài Android Studio trên trang
chủ của
Android( />o)
Bước 2: Tải phần mềm hỗ trợ tăng tốc đồ họa
cho cấu hình máy tính Identification Utility:
-Lên Google search từ khóa:"intel® processor
identification utility":
-chọn phiên bản phù hợp với cấu hình máy tính và tải về
cài đặt:
-sau khi cài đặt phần mềm chạy Android Studio và tiến
hành cài máy ảo Emulator bình thường
Bài 4:Hiển thị danh sách đối tượng trên ListView dùng
Custom ArrayAdapter
Bước 1: item xml:
<?xml version="1.0" encoding="utf-8" ?>
-
"match_parent" android:layout_height="match_parent" a
ndroid:orientation="vertical">
ayout_width="150dp" android:layout_height="170dp" app:
srcCompat="@drawable/bimatinhyeu" />
dth="match_parent" android:layout_height="wrap_conte
nt" android:text="TextView" android:textSize="26dp" />
dth="match_parent" android:layout_height="wrap_conte
nt" android:text="TextView" />
</LinearLayout>
Bước 2: Class Sach{}
public class Sach implements Serializable {
private int id;
private String tenSach;
private String giaSach;
private String emailDangNhap;
private int hinhAnh;
}
Bước 3: ArrayAdapter:
public class SachAdapter extends ArrayAdapter<Sach> {
Activity context;
int resource;
public SachAdapter(@NonNull 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
customView=this.context.getLayoutInflater().inflate(this.res
ource,null);
TextView
txtTenSach=(TextView)customView.findViewById(R.id.txtT
enSach);
TextView
txtGiaSach=(TextView)customView.findViewById(R.id.txtGi
aSach);
ImageView
imgHinhAnhSach=(ImageView)customView.findViewById(
R.id.imgHinhAnhSach);
Sach sach=getItem(position);
txtTenSach.setText(sach.getTenSach());
txtGiaSach.setText(sach.getGiaSach()+"đồng");
imgHinhAnhSach.setImageResource(sach.getHinhAnh());
return customView;
}
}
Bài 5: Giới thiệu menu NavigationBottom thường dùng
trong các App
-Là loại Template thông dụng thường dùng trong rất nhiều các ứng dụng khác nhau
-Trong Android Studio:
File=>New=>New Project=> Bottom Navigation Activity:
- Phiên bản mới các menu là các Fragment:
Đây là UI của menu Navigation Bottom
Bài 6: Truy ền d ữ li ệu gi ữa các Fragment trong menu
Navigation Bottom
Dùng EventBust:
Vào trang chủ của
EventBust( để copy thư
viện và đọc cách sử dụng, ở đây tôi dùng phiên bản 2.4:
thư viện:
implementation 'de.greenrobot:eventbus:2.4.0'
Đối tượng truyền:
SinhVien{
ptivate int id;
private String name;
private String phone;
}
+Truyền dữ liệu:
SinhVien sinhVien=new SinhVien(01,Quyen,098);
EventBus.getDefault().postSticky(sinhVien);
+Nhận dữ liệu:
Override hai hàm onStart() và onStop();
@Override
public void onStart() {
super.onStart();
EventBus.getDefault().registerSticky(this);
}
@Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
// hàm này dùng để nhận đối tượng truyền có kiểu
SinhVien
public void onEventMainThread(SinhVien event) {
SinhVien sinhVienNhan=event;
Bài 7: Điều hướng giữa các Fragment trong menu
Navigation Bottom
Điều hướng giữa các Fragment trong menu Navigation Bottom:
- Tôi khai báo một Button ở menu Fragment Home;
Button btnChuyenSangNotify;
btnChuyenSangNotify=findviewbyid(R.id.btnChuyenSang
Notify);
-Muốn khi nhấn vào button chuyển sang menu Fragment
NoTifyCation tôi làm như sau:
btnChuyenSangNotify.setOnClickListener(){
Navigation.findNavController(btnChuyenSangNotify).navig
ate(R.id.navigation_notify);
}
trong đó, R.id.navigation_notify và id của menu navigation
notify:
Điều này giúp chúng ta thuận tiện hơn
VD: khi nhấn button đăng nhập sẽ chuyển sang menu mặt
hàng
Bài 9: Cách mở một Activity từ một Fragment và đồ ng thời
truyền dữ liệu
Cách 1:Dùng hàm getActivity để lấy Activity
hiện tại sau đó dùng hàm setContenView để
mở layout Activity
Class Sach{
private int id;
private String name;
private String gia;
}
Truyền đối tượng sach qua tham số vào hàm:
moChiTiet(Sach sach){
getActivity.setContentView(R.layout.item);
//Dùng getActivity để lấy Activity hiện tại và
findViewbyId
TextView txtId=getActivity().findViewbyId(R.id.txtId);
TextView txName=getActivity().findViewbyId(R.id.txtName);
TextView txtGia=getActivity().findViewbyId(R.id.txtGia);
txtId.setText(sach.getId());
txtName.setText(sach.getName());
txtGia.setText(sach.getGia());
}
Cách 2:
Bước 1: mở Activity từ Fragment:
Intent intent=new Intent(Fragment,Activity);
startActivity(intent);
Bước 2: Truyền dữ liệu:
Dùng EventBust ở bài 6
Bài 9: Cách m ở m ột Activity t ừ m ột Fragment và đồ ng th ời
truy ền d ữ li ệu
Cách 1:Dùng hàm getActivity để lấy Activity
hiện tại sau đó dùng hàm setContenView để
mở layout Activity
Class Sach{
private int id;
private String name;
private String gia;
}
Truyền đối tượng sach qua tham số vào hàm:
moChiTiet(Sach sach){
getActivity.setContentView(R.layout.item);
//Dùng getActivity để lấy Activity hiện tại và
findViewbyId
TextView txtId=getActivity().findViewbyId(R.id.txtId);
TextView txName=getActivity().findViewbyId(R.id.txtName);
TextView txtGia=getActivity().findViewbyId(R.id.txtGia);
txtId.setText(sach.getId());
txtName.setText(sach.getName());
txtGia.setText(sach.getGia());
}
Cách 2:
Bước 1: mở Activity từ Fragment:
Intent intent=new Intent(Fragment,Activity);
startActivity(intent);
Bước 2: Truyền dữ liệu:
Dùng EventBust ở bài 6
Bài 11: Mutiple Item RecyclerView, s ử d ụng cùng m ột lúc
nhi ều custom item trên RecyclerView
Ta có 2 xml item1, item2
Ta có Class sau:
public class Text1 {
private int viewType;
private String text;
private int hinhAnh;
}
Ta khai báo Adapter như sau:
public class ManHinhChatAdapter extends
RecyclerView.Adapter<RecyclerView.ViewHolder> {
List<Text1> mTests=new ArrayList<Text1>();
private LayoutInflater mLayoutInflater;
private Context context;
public ManHinhChatAdapter(List<Text1>
mTests,Context context) {
this.mTests=mTests;
this.context=context;
}
// khai báo lớp hiển thị item1
class ViewHolder0 extends RecyclerView.ViewHolder {
ImageView imgHinhAnh;
public ViewHolder0(View itemView){
super(itemView);
imgHinhAnh=itemView.findViewById(R.id.imgHinhAnh);
}
}
// khai báo lớp hiển thị item2
class ViewHolder2 extends RecyclerView.ViewHolder {
ImageView imgHinhAnh2;
TextView txtText2;
public ViewHolder2(View itemView){
super(itemView);
imgHinhAnh2=itemView.findViewById(R.id.imgHinhAnh2);
txtText2=itemView.findViewById(R.id.txtTextView2);
}
}
@Override
public int getItemViewType(int position) {
switch(mTests.get(position).getViewType()){
// nếu getViewType() là 0 trả về 0
case 0:
return mTests.get(position).getViewType();
// nếu getViewType() là 1 trả về 1
case 1:
return mTests.get(position).getViewType();
default:
return -1;
}
}
@NonNull
@Override
public RecyclerView.ViewHolder
onCreateViewHolder(@NonNull ViewGroup parent, int
viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
switch (viewType){
// nếu viewType là 0 trả về class hiển thị item1
case 0:
View item0 =
inflater.inflate(R.layout.item1,parent,false);
return new ViewHolder0(item0);
// nếu viewType là 1 trả về class hiển thị item2
case 1:
View item2 =
inflater.inflate(R.layout.item2,parent,false);
return new ViewHolder2(item2);
default:
return null;
}
}
@Override
public void onBindViewHolder(@NonNull
RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()){
// nếu viewType là 0 lấy đối tượng và xử lý
case 0:
ViewHolder0 viewHolder0 =
(ViewHolder0)holder;
int
hinhANh1=mTests.get(position).getHinhAnh();
((ViewHolder0)
holder).imgHinhAnh.setImageResource(hinhANh1);
break;
// nếu viewType là 1 lấy đối tượng và xử lý
case 1:
ViewHolder2 viewHolder2 =
(ViewHolder2)holder;
String text1=mTests.get(position).getText();
int hinhAnh2=mTests.get(position).getHinhAnh();
((ViewHolder2) holder).txtText2.setText(text1);
((ViewHolder2)
holder).imgHinhAnh2.setImageResource(hinhAnh2);
break;
}
}
@Override
// tổng số phần tử của mảng cần hiển thị
public int getItemCount() {
return mTests.size();
}
}
Ở MainActivity:
RecyclerView recyclerView;
ManHinhChatAdapter manHinhChatAdapter;
ArrayList<Text1>danhSachs=new ArrayList<Text1>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView=findViewById(R.id.rcDanhSach);
LinearLayoutManager linearLayoutManager = new
LinearLayoutManager(this);
manHinhChatAdapter=new
ManHinhChatAdapter(danhSachs,MainActivity.this);
recyclerView.setAdapter(manHinhChatAdapter);
recyclerView.setLayoutManager(linearLayoutManager);
// khởi tạo các phần tử của mản hiển thị lên RecyclerView
danhSachs.add(new Text1(0,"Book
1",R.drawable.cungcontruongthanh));
danhSachs.add(new Text1(1,"Book
2",R.drawable.mackethienha));
danhSachs.add(new Text1(0,"Book
3",R.drawable.bimatinhyeu));
danhSachs.add(new Text1(1,"Book
4",R.drawable.dambinghet));
danhSachs.add(new Text1(0,"Book
5",R.drawable.damuocmo));
danhSachs.add(new Text1(1,"Book
6",R.drawable.kynangditruocdamme));
danhSachs.add(new Text1(0,"Book
7",R.drawable.nghethuatdamphan));
danhSachs.add(new Text1(1,"Book
8",R.drawable.danhthucnanglucvohan));
danhSachs.add(new Text1(0,"Book
9",R.drawable.doingandungngudai));
danhSachs.add(new Text1(1,"Book
10",R.drawable.mackethienha));
danhSachs.add(new Text1(0,"Book
11",R.drawable.mackethienha));
Một cách khác truyền dữ liệu giữa các Activity và Frafment:
đó là dùng biến static
public static Sinhvien sv;
lấy biến
Fragment.sv hoặc Activity.sv
Bài 13: Cách thêm dữ liệu vào RealTime Database Firebase
Khai báo 2 biến:
FirebaseDatabase firebaseDatabase;
// khai báo biến đường dẫn databaseReference
DatabaseReference databaseReference;
firebaseDatabase=FirebaseDatabase.getInstance();
// thêm nút ChoBayBan vào đường dẫn
databaseReference=firebaseDatabase.getReference().child("Cho
BayBan");
// khởi tạo một mảng ArrayList
ArrayList<MatHang>dsMatHangs=new
ArrayList<MatHang>();
// thêm một mặt hàng vào dsMatHangs
dsMatHangs.add(matHang);
// thêm mảng ArrayList vào đường dẫn
databaseReference.add(dsMatHangs);
Bài 14: Cách đọc mảng đối tượng từ RealTime Database để
thêm vào ListView, GridView, RecyclerView
Fragment, Activity kế thừa phương thức implements ValueEventListener
khai báo 2 biến:
FirebaseDatabase firebaseDatabase;
DatabaseReference databaseReference;
firebaseDatabase=FirebaseDatabase.getInstance();
databaseReference=firebaseDatabase.getReference().child("ChoBayBan");
// thêm sự kiện addValueEventListener
databaseReference.addValueEventListener(this);
Override 2 hàm sau:
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
// khởi tạo một mảng ArrayList ds1 để chứa các phần tử từ đường dẫn
ArrayList<HangBayBan> ds1=new ArrayList<HangBayBan>();
Iterable<DataSnapshot>dataSnapshots=dataSnapshot.getChildren();
for(DataSnapshot dataSnapshot1:dataSnapshots){
// ép kiểu về HangBayBan
HangBayBan hangBayBan=dataSnapshot1.getValue(HangBayBan.class);
ds1.add(hangBayBan)
}
// hàm clear() để xóa toàn bộ phần tử của mảng và adapter
hangBayBans.clear();
hangBayBanAdapter.clear();
// thêm các phần tử từ đường dẫn vào adapter để hiển thị
hangBayBans.addAll(ds1);
hangBayBanAdapter.addAll(hangBayBans);
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
Bài 15: Cách s ử d ụng l ưu tr ữ file Storage, ImageView,
VideoView
Muốn sử dụng Storage thì thư viện Storage và thư viện
Autithencation phải cùng một phiên bản, ở đây mình lấy
phiên bản 16.1.0:
Khai báo hai biến sau:
FirebaseStorage firebaseStorage;
StorageReference storageReference;
firebaseStorage=FirebaseStorage.getInstance();
storageReference=firebaseStorage.getReference();
Dùng hình ảnh:+Download:
// trỏ đến thư mục photos và download hình ảnh
hangBayBan.getHinhAnh1().jpg hiển thị lên ImageView
imgHinhAnhChiTiet1:
StorageReference
storageReference1=storageReference.child("photos/"+han
gBayBan.getHinhAnh1()+".jpg");
long mega=1024*1024;
storageReference1.getBytes(mega).addOnSuccessListen
er(new OnSuccessListener<byte[]>() {
@Override
public void onSuccess(byte[] bytes) {
Bitmap bitmap=
BitmapFactory.decodeByteArray(bytes,0,bytes.length);
imgHinhAnhChiTiet1.setImageBitmap(bitmap);
}
})
+Tải hình ảnh lên:
// tải hình ảnh bitmap1 lấy từ đa phương tiện tải lên với
tên hangBayBans.size()+intbitmap1 + ".jpg"
int intbitmap1 = random.nextInt();
ByteArrayOutputStream
byteArrayOutputStream = new ByteArrayOutputStream();
bitmap1.compress(Bitmap.CompressFormat.JPEG, 100,
byteArrayOutputStream);
byte[] data =
byteArrayOutputStream.toByteArray();
storageReference.child(hangBayBans.size()+intbitmap1 +
".jpg").putBytes(data);
Dùng VideoView:+Download video hiển thị
lên videoView:
// trỏ đến thư mục videos và download video có tên
baiHoc.avi, sau đó hiển thị lên VideoView
btnPlay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
storageReference.child("videos/"+baiHoc+".avi").getDownl
oadUrl().addOnSuccessListener(new
OnSuccessListener<Uri>() {
@Override
public void onSuccess(Uri uri) {
Toast.makeText( ItemChiTiet.this,"Đang
chạy videos/"+baiHoc+".avi, xin chờ trong giây
lát!",Toast.LENGTH_SHORT).show();
videoView.setVideoURI(uri);
videoView.setMediaController(new
MediaController(ItemChiTiet.this));
videoView.start();
}
});
}
});
Bài 16: Cách sử dụng Notifycation trong Firebase
Muốn sử dụng Notifycation thì tất cả các thư
viện Autithencation, database, core, message
đều phải cùng một phiên bản, ở đây mình lấy
phiên bản 10.2.1:
implementation 'com.google.firebase:firebase-auth:10.2.1'
implementation 'com.google.firebase:firebasedatabase:10.2.1'
implementation 'com.google.firebase:firebase-core:10.2.1'
implementation 'com.google.firebase:firebasemessaging:10.2.1'
Lớp MessagingService dùng để put một
notifycation
public class MessagingService extends
FirebaseMessagingService {
private static final String TAG = "MyFirebaseService";
public void onMessageReceived(RemoteMessage
remoteMessage) {
super.onMessageReceived(remoteMessage);
sendNotification(remoteMessage.getNotification().getBody
());
}
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
sendRegistrationToServer(token);
}
private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to
your app server.
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
String channelId = getString(R.string.project_id);
Uri defaultSoundUri =
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_
NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_launcher_background)
.setLargeIcon(BitmapFactory.decodeResource(getResour
ces(), R.drawable.ic_launcher_background))
// tiêu đề của mã text
.setContentTitle("Shoppe Demo, Khuyến
Mãi Khủng!")
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
.setDefaults(Notification.DEFAULT_ALL)
.setPriority(NotificationManager.IMPORTANCE_HIGH)
.addAction(new NotificationCompat.Action(
android.R.drawable.sym_call_missed,
"Cancel",
PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT)))
.addAction(new NotificationCompat.Action(
android.R.drawable.sym_call_outgoing,
"OK",
PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT)));
NotificationManager notificationManager =
(NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.O) {
NotificationChannel channel = new
NotificationChannel(
channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(0,
notificationBuilder.build());
}
}
Bài 21: SearchView và Option menu trong Fragment
Thêm hàm setHasOptionsMenu(true) ở sau
onCreatView như sau:
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
setHasOptionsMenu(true);
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel.class);
View root = inflater.inflate(R.layout.fragment_home, container, false);
Override hai hàm sau:
// hàm dùng để khai báo Search và Option menu
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.mnu_search, menu);
MenuItem item = menu.findItem(R.id.mnu_search);
// chỉnh sửa chế độ hiển thị của ô tìm kiếm IFROOM,
ALWAYS,...
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW |
MenuItem.SHOW_AS_ACTION_IF_ROOM);
SearchView searchView = (SearchView) item.getActionView();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
ArrayList<HangBayBan>ds1=new ArrayList<HangBayBan>();
for(HangBayBan matHang:hangBayBans){
if(matHang.getTen().contains(query)){
ds1.add(matHang);
}
}
hangBayBanAdapter.clear();
hangBayBanAdapter.addAll(ds1);
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
// Here is where we are going to implement the filter logic
return true;
}
});
}
// hàm dùng để chọn case của option menu
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.mnu_thoat:
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startActivity(startMain);
break;
}
return super.onOptionsItemSelected(item);
}
}
Bài 19: S ử d ụng ScrollView để hi ển th ị đo ạn text dài
Bài 20: L ấy hình ảnh t ừ Đa Ph ươ ng Ti ện hi ển th ị lên
ImageView
Tạo sự kiện khi ta click vào ImageView:
PICK_IMAGE_REQUEST là biến requestCode là mã số
để xác định hình ảnh được lưu
imgHinhAnh1.setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select
Picture"), PICK_IMAGE_REQUEST);
}
});
Override hàm sau:
@Override
public void onActivityResult(int requestCode, int
resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode,
data);
if(resultCode == RESULT_OK
&& data != null && data.getData() != null )
{
filePath = data.getData();
try {
Bitmap bitmap =
MediaStore.Images.Media.getBitmap(getActivity().getCont
entResolver(), filePath);
if(requestCode == PICK_IMAGE_REQUEST) {
// hiển thị hình ảnh lên ImageView:
imgHinhAnh1.setImageBitmap(bitmap);
bitmap1=bitmap;
}
if(requestCode == PICK_IMAGE_REQUEST2) {
imgHinhAnh2.setImageBitmap(bitmap);
bitmap2=bitmap;
}
if(requestCode == PICK_IMAGE_REQUEST3) {
imgHinhAnh3.setImageBitmap(bitmap);
bitmap3=bitmap;
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Bài 22: Drawable custom các widget và theme
notifyItemInsert(int) trong RecyclerView
Dùng để đưa các phần tử lên RecyvlerView tức thì:
Adapter.notifyItemInsert( position);