前言
①方法:思路+案例、预习思路
②补充知识点: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