前言
①方法:思路+案例、預習思路
②補充知識點:debug、代碼規范、約束布局
③學生講課:三四節課學生講課(學委--組長--組員):前一天通知,沒有就題庫
④小組PK:
提問搶答加分
檢查作業給對應組加分
成為主持人的給對應組加分
題庫
1.側滑、音樂、tvf、rv單布局、elv+點擊(√)
2.側滑、rv+刷新+點擊、pop、通知+延時意圖、選項菜單
3.側滑、tvf、多布局、打電話、webview
4.側滑、tvf、項目、刷新、webview
5.vp導航、tvf、banner+rv多布局、多布局(需要修改)
6.導航、tvf、九宮格+banner、二級列表、webview
7.側滑、tvf、rv多布局、選項菜單、pop、相冊跳轉替換圖片、service實現音樂播放
8.tvf、rv+banner多布局、選項菜單、數據庫、上下文菜單、pop、通知
9.側滑、tvf、banner+rv多布局、選項菜單、pop、點擊頭像替換圖片
10、tvf、二級列表、側滑菜單、toobar、cardview、項目
50個面試題
每天講解十五個面試題(一節課),剩余的時間學生記憶
4月2日:項目搭建,主要側滑和toobar
4月3日:題庫4、10,主要項目
4月7日:題庫1、3、6,主要音樂和九宮格、打電話
4月8日:題庫2、8,主要pop和通知(數據庫不講)
4月9日:題庫7、9,主要相冊替換和服務播放音樂
4月10日:題庫5、8,主要數據庫
4月13日:帶領大家做終極題1-15(給定時間學生練習)
4月14日:帶領大家做終極題16-25
一、列表
二級列表(ExpandableListView)
①創建布局,找控件
②獲取數據:死數據、網絡數據
③創建適配器:10個方法要掌握
④設置適配器
⑤父項、子項點擊事件
⑥基本屬性Listview手動、自動加載更多
(1)Listview
①創建布局,找控件
②獲取網絡數據
③創建適配器:兩個優化(必會):convertView復用,避免重復找控件
④設置適配器
(2)Listview手動加載更多
①創建布局,找控件
②獲取網絡數據
③創建適配器:兩個優化(必會)
④設置適配器
⑤給Listview添加一個footer
⑥點擊footer中button加載更多:page++,獲取數據
(3)Listview自動加載更多
①創建布局,找控件
②獲取網絡數據
③創建適配器:兩個優化(必會)
④設置適配器
⑤定義一個變量isBottom表示是否滑到底部
⑥Listview設置滑動監聽
lv.setOnScrollListener(new AbsListView.OnScrollListener() {
/**
* 滑動狀態發生改變:如果滑到底部,加載更多,修改isBottom值
* @param view
* @param scrollState
* //scrollState 有三種類型
* 1.SCROLL_STATE_IDLE 手指未觸摸屏幕,且屏幕靜止
* 2.SCROLL_STATE_TOUCH_SCROLL 手指未離開屏幕滑動
* 3.SCROLL_STATE_FLING 手指使勁滑動屏幕,然后手指離開屏幕,屏幕仍在滾動
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case SCROLL_STATE_IDLE:
if (isBottom) {
page++;
initData();
isBottom = false;
}
break;
}
}
/**
* 滑動監聽,判斷是否滑動底部,返回isBottom具體值
* @param view
* @param firstVisibleItem:可見頁面第一個條目小標
* @param visibleItemCount:可見頁面數據個數
* @param totalItemCount:條目總數
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
isBottom = true;
} else {
isBottom = false;
}
}
});
二、菜單
側滑菜單
①添加依賴
②創建布局:DrawerLayout、NavigationView(三個屬性、menu)
③設置actionbar:toolbar設置標題、logo、關聯toobar和側滑菜單
④監聽事件:頭部監聽、側滑菜單監聽、DrawerLayout、代買開關側滑菜單
⑤沉浸式狀態欄選項菜單
①創建選項菜單(onCreateOptionsMenu):兩種方式-代碼和menu(showAsAction)
②選項菜單的點擊事件(onOptionsItemSelected):switch上下文菜單
①注冊上下文菜單:registerForContextMenu()
②創建上下文菜單:onCreateContextMenu()
③上下文菜單點擊事件:onContextItemSelected()
注意區別:
OptionsMenu是整個界面共用,ContextMenu是注冊給某個組件,此組件擁有此菜單,沒有注冊的組件沒此菜單。補充:fragment怎么顯示選項菜單??
三、RecyclerView
RecyclerView基本使用
①添加依賴(版本問題注意)
②創建布局(寬高必須是充滿的)
③找控件
④設置布局管理器(三種顯示方式:線性布局、網格布局、瀑布流布局)
⑤獲取數據(切換子線程的方法)
⑥創建適配器-- 重寫三個,通過接口回調實現點擊事件
⑦設置適配器RecyclerView多布局一:list+banner
① RecyclerView基本使用
②定義類型常量
③重寫方法getItemViewType()
根據位置返回不同類型
④重寫oncreateViewHolder()
根據不同類型加載不同的布局
⑤重寫onBindViewHolder()
根據不用類型加載不同數據
- 注意
①獲取條目總數:list.size()+1
②onBindViewHolder
:獲取別表條目數據的時候,position-1
- RecyclerView多布局二:奇數位置左圖右文字+偶數位置左文字右圖片
① RecyclerView基本使用(看6)
②定義類型常量
③重寫方法getItemViewType()
根據位置返回不同類型
④重寫oncreateViewHolder()
根據不同類型加載不同的布局
⑤重寫onBindViewHolder()
根據不用類型加載不同數據
- 注意:沒有7中注意
RecyclerView通過接口回調實現點擊事件
①在adapter定義一個內部接口,內部接口定義一個方法,方法參數是我們需要返回值的;
②在adapter定義接口變量,并設置set方法
③在onBindVIewholder()
中,給條目做一個點擊事件
④在fragment或者activity中,使用adapter對象調用點擊事件即可RecyclerView添加刷新
①添加依賴
②在布局中添加刷新的控件并找控件
③給刷新控件添加加載更多、下拉刷細膩添加監聽,監聽中寫具體代碼
④刷新完畢列表,關閉SmartRefreshLayout頭和腳。
四、fragment
- 靜態添加fragment
①創建一個fragment
②創建布局,把①中的fragment放到布局中
- 注意:
①必須要有id,否則:Caused by: java.lang.IllegalArgumentException: Binary XML file line #9: Must specify unique android:id, android:tag, or have a parent with an id for com.anfly.fragmentr.AFragment
②布局中必須添加屬性name,值該fragment全類名
- 動態添加fragment
//獲取碎片管理器
FragmentManager fm = getSupportFragmentManager();
//開啟事務
FragmentTransaction fragmentTransaction = fm.beginTransaction();
//獲取fragment對象
AFragment aFragment = new AFragment();
//替換容器中內容
fragmentTransaction.replace(R.id.fl_container, aFragment);
//提交事務
fragmentTransaction.commit();
Transaction常用方法
①add
②remove
③replace
④hide
⑤show
⑥attach
⑦detach
⑧commitfragment生命周期
①onAttach()
②onCreate()
③onCreateView()
④onActivityCreated()
⑤onStart()
⑥onResume()
⑦onPause()
⑧onStop()
⑨onDestroyView()
⑩onDestroy()
?onDetach()fragment傳遞數據到activity
①獲取activity對象,直接調用方法
MainActivity activity = (MainActivity) getActivity();
activity.getMsgFromFramgent("我是來自fragment的數據");
②接口回調傳遞數據
Java接口與接口回調在Android中的使用
③通過fragment的有參構造傳數據(不推薦)
- activity傳遞數據到fragment
①通過bundle方式傳值
activity中:
AFragment aFragment = new AFragment();
Bundle bundle = new Bundle();
bundle.putString("a", "我是來自activity的數據");
aFragment.setArguments(bundle);
fragment中:
Bundle bundle = getArguments();
String a = bundle.getString("a");
fragment與fragment之間傳遞數據
①通過構造方式傳值(不推薦)
②通過FragmentManager找到對應Id或者Tag的Framgment,然后獲取里面的數據或方法
③通過它們所在的Activity作為橋梁,可以使用getActivity()或者接口回調,達到獲取另一個Fragment數據的目的.RadioGroup底部導航結合Fragmentr切換
五、ViewPager+tablayout
- ViewPager結合view實現導航
①創建布局找控件
②獲取數據集合
③創建適配器:
getCount()
isViewFromObject()
instantiateItem()
destroyItem()
④設置適配器
Viewpager結合Fragment實現導航
①創建布局找控件
②獲取fragment的集合fragments
③創建適配器:FragmentStatePagerAdapter和FragmentPagerAdapter區別以及內部方法
④設置適配器Banner開源框架
官方
banner
.setBannerStyle(BannerConfig.NUM_INDICATOR_TITLE)//設置風格
.setImages(images)//設置圖片集合
.setBannerAnimation(Transformer.DepthPage)//設置動畫
.setBannerTitles(titles)//直接添加無效,必須設置BannerStyle
.setImageLoader(new GlideImageLoader())//圖片加載器
.start();
Tablayout
①屬性TVF
①創建布局找控件:TV
②創建兩個集合:fragments和titles
③創建適配器:四個方法(包含一個構造)
④設置適配器
⑤TV結合:tab.setupWithViewPager(vp);
⑥設置圖片選擇器tab.getTabAt(0).setIcon()
TVF涉及到的懶加載 -- 為了避免預加載
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
initData();
} else {
if (list != null && list.size > 0) {
list.clear();
}
}
}
六、PopupWindow
①創建PopupWindow布局
②創建PopupWindow對象,用三個參數的構造
③PopupWindow四種顯示方式
④聚焦:EditText能輸入內容
⑤點擊范圍外關閉PopupWindow
⑥全屏陰影,PopupWindow點擊消失監聽
⑦進出場動畫
七、Notification
①獲取通知管理器getSystemService
②兼容O版以上系統
③獲取通知對象(構建者模式):必要屬性有三項
④用通知管理器發送通知
⑤延時意圖:intent、pendingIntent、setContentIntent
⑥通知提示:聲音、震動、呼吸燈、全部
八、權限
- 分類
①普通權限:不需要動態獲取
②危險權限:需要動態獲取 - 危險權限分類
3CSLMP - 如何動態獲取權限
①在清單列表寫上需要的全下你
②檢查是否授權
如果授權 -> 操作
如果沒有授權 -> 請求權限
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {
callPhone();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CALL_PHONE}, 100);
}
③請求權限結果
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case 100:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
callPhone();
} else {
Toast.makeText(MainActivity.this, "授權失敗", Toast.LENGTH_SHORT).show();
}
break;
}
}
- 通過框架獲取危險權限
①添加依賴implementation 'com.github.dfqin:grantor:2.5'
②使用
PermissionsUtil.requestPermission(this, new PermissionListener() {
@Override
public void permissionGranted(@NonNull String[] permission) {
callPhone();
}
@Override
public void permissionDenied(@NonNull String[] permission) {
Toast.makeText(MainActivity.this, "授權失敗", Toast.LENGTH_SHORT).show();
}
}, Manifest.permission.CALL_PHONE);
九、內容提供者
- ContentProvider
①創建一個數據庫及一張表
②自定義ContentProvider繼承自ContentProvider,重寫方法 - ContentResolver
①獲取ContentResolver
②獲取uri:Uri.parse("content://"+authorities+/+path)
Uri uri = Uri.parse("content://com.anfly.contentproviderr.ClContentProvider/cl");
3.ContentResolver讀取短信、通訊錄、圖片、音頻、視頻
①動態獲取危險全新
②獲取ContentResolver對象contentResolver
③contentResolver調用query()方法查詢相關內容
短信:Telephony.Sms.CONTENT_URI
通訊錄:ContactsContract.CommonDataKinds.Phone.CONTENT_URI
圖片:MediaStore.Images.Media.EXTERNAL_CONTENT_URI
音頻:MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
視頻:MediaStore.Video.Media.EXTERNAL_CONTENT_URI
十、Service
- service概述、應用場景
- startService生命周期
- bindService生命周期
- startService和bindService區別
- Activity和Service之間的數據傳遞
①數據從Activity和到Service
intent方式:startService和bindService都可以
②數據從Activity到Service
IBinder方式:bindService
③數據從Service到Activity
接口回調和廣播
十一、音樂播放器
- MediaPlayer創建方式
①MediaPlayer mp = new MediaPlayer();
②MediaPlayer mp = MediaPlayer.create(this, R.raw.test);
- 四種資源
①用戶在應用中事先自帶的resource資源
例如:MediaPlayer.create(this, R.raw.test);
②存儲在SD卡或其他文件路徑下的媒體文件
例如:mp.setDataSource("/sdcard/test.mp3");
③網絡上的媒體文件
例如:mp.setDataSource("http://music.163.com/song/media/outer/url?id=139894.mp3");
④assets目錄下文件
AssetManager assets = getAssets();
try {
AssetFileDescriptor assetFileDescriptor = assets.openFd("qinghuaci.mp3");
player.setDataSource(assetFileDescriptor.getFileDescriptor(), assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength());
player.prepare();
player.start();
} catch (IOException e) {
e.printStackTrace();
}
- assets 和 raw 資源文件夾區別
- 結合SeekBar實現拖動播放音樂功能
①創建seekbar布局
②seekbar設置監聽,在停止拖動中player.seekTo(seekBar.getProgress());
③更新seekbar:
private void updataProgress() {
new Thread(new Runnable() {
@Override
public void run() {
while (player.isPlaying()) {
try {
Thread.sleep(1000);
seekbar_mp.setMax(player.getDuration());
seekbar_mp.setProgress(player.getCurrentPosition());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
- 結合RecyclerView實現音樂播放上一首,下一首功能
① 使用ContentResolver+recyclerview展示音樂列表
②條目點擊事件播放對應的音樂
③點擊上一首、下一首
private void next() {
if (positon < list.size() - 1) {
positon++;
} else {
positon = 0;
}
player(list.get(positon).getPath());
}
private void pre() {
if (positon > 0) {
positon--;
} else {
positon = list.size() - 1;
}
player(list.get(positon).getPath());
}
- 結合Service實現后臺音樂播放功能
①創建一個服務AudioService
②服務中創建內部類AudioBinder,類中有一個方法返回服務類
③在onCreate()初始化MediaPlayer對象
④創建一系列關于mp的方法:播放、暫停、繼續、停止、拖動
⑤在AudioActivity中綁定服務,返回服務類的對象
⑥按鈕點擊事件:通過服務類對象調用其方法實現音頻播放
⑦seekbar進度改變監聽,把進度傳給mp