一 二级列表(ExpandableListView)
1.1 死数据步骤:
①创建布局找控件
②数据源(两个集合:groupLists, childLists:泛型是<ArrayList<String>>)
③创建适配器:自定义一个类继承自:BaseExpandableListAdapter
并重写十个方法 注意:如果想要子条目实现点击事件监听适配器中isChildSelectable方法设置为true
④设置适配器
1.2 Elv监听:
//父条目点击事件监听
elv.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
Toast.makeText(MainActivity.this, grouplist.get(groupPosition), Toast.LENGTH_SHORT).show();
return false;
}
});
//子条目点击事件监听 注意:适配器中isChildSelectable方法设置为true
elv.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
Toast.makeText(MainActivity.this, childList.get(groupPosition).get(childPosition), Toast.LENGTH_SHORT).show();
return false;
}
});
//打开一个新的条目关闭其他条目
elv.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
int count = elv.getExpandableListAdapter().getGroupCount();
for (int i = 0; i < count; i++) {
if (i < groupPosition) {
elv.collapseGroup(i);
} else if (i > groupPosition) {
elv.collapseGroup(i);
}
}
}
});
二 侧滑
2.1 侧滑菜单
①添加依赖
(implementation'com.android.support:design:29.0.2')
②创建布局:
DrawerLayout、Toolbar、NavigationView(menu、header)
③设置actionbar:toolbar设置标题、logo、关联toolbar和侧滑
④监听事件:头部监听、侧滑菜单监听、DrawerLayout、Home旋转开关
⑤沉浸式状态栏
//当侧滑的时候主界面跟随 X 轴移动
dl.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
cl.setX(drawerView.getRight());
}
//此处省略三个方法......
}
2.2 选项菜单
①创建选项菜单(onCreateOptionsMenu)
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, 0, 0, "线性布局").setIcon(R.mipmap.ic_launcher_round).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
return super.onCreateOptionsMenu(menu);
}
②选项菜单的点击事件(onOptionsItemSelected)
③Fragment中加setHasOptionsMenu(true);
④使选项菜单内容以标题的样式显示在标题上:
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS)
2.3 上下文菜单
①注册上下文菜单(registerForContextMenu())
②创建上下文菜单(onCreateContextMenu)
③上下文菜单的点击事件(onContextItemSelected)
Toolbar使用详情
//侧滑菜单item图片显示
nv.setItemIconTintList(null);
//设置 Logo
toolbar.setLogo(R.mipmap.logo);
// 设置主标题
toolbar.setTitle("Title");
// 设置副标题
toolbar.setSubtitle("Sub Title");
//设置toolbar,将Toolbar设置到界面上
setSupportActionBar(toolbar);
//左边的小箭头(注意某些版本api需要在setSupportActionBar(toolbar)之后才有效果)
toolbar.setNavigationIcon(R.mipmap.back);
//菜单点击事件(注意需要在setSupportActionBar(toolbar)之后才有效果)
toolbar.setOnMenuItemClickListener(onMenuItemClick);
//点击头部
View headerView = nv.getHeaderView(0);
View iv = headerView.findViewById(R.id.iv);
iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "点击了头部", Toast.LENGTH_SHORT).show();
}
});
//Home旋转开关
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, dl, toolbar, R.string.app_name, R.string.app_name);
dl.addDrawerListener(toggle);
toggle.syncState();
android:fitsSystemWindows="true"
//在res文件夹下创建values-v21,复制styles.xml并添加属性 注意:修改为.NoActionBar
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimary</item>
<item name="colorAccent">@color/colorAccent</item>
<!--透明状态栏-->
<item name="android:statusBarColor">#00ffffff</item>
</style>
//选项菜单不遮蔽标题栏
//1.在styles文件里编写此代码
<style name="OverflowMenuStyle" parent="Widget.AppCompat.Light.PopupMenu.Overflow">
<item name="overlapAnchor">false</item>
</style>
//2.在toolbar中调用此方法:
android:theme="@style/OverflowMenuStyle"
三 RecyclerView
3.1 RecyclerView的使用步骤
①添加依赖(implementation 'com.android.support:recyclerview-v7:29.0.2')
②创建布局(宽、高必须充满)
③找控件
④设置布局管理器(线性布局,网格布局和瀑布流)
⑤获取数据(切换子线程的方法)
⑥创建适配器——重写三个方法,通过接口回调实现点击事件
⑦设置适配器
布局管理器:
//线性布局
rv.setLayoutManager(new LinearLayoutManager(this));
//网格布局
rv.setLayoutManager(new GridLayoutManager(this, 3));
//瀑布流
rv.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
3.2 接口回调:
类A调用类B的方法b(),类B在回调类A的方法a(),期中方法a()是定义在接口中的,由类A来实现,这是一个双向调用的过程。
//定义接口
public interface OnItemClickListener{
void onItemClick(int position);
}
//设置传递接口类实现对象的方法
private OnItemClickListeneronItemClickListener;
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
this.onItemClickListener = onItemClickListener;
}
//条目的监听事件
holder.itemView.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View){
onItemClickListener.onItemClick(position);
}
});
3.3 RecyclerView多布局1:banner+recycleview
①RecyclerView基本使用
②定义类型常量
③重写获取条目根据位置分类的方法(getItemViewType)
④重写onCreateViewHolder,根据类型创建不同的布局
⑤重写onBindViewHolder,根据不同类型加载不同数据
-
注意:
①获取条目总数(list.size()+1)
②onBindViewHolder:获取列表条目数据的时候(position-1)
3.RecyclerView与ListView的对比
RecyclerView与ListView不同点
ListView:
①继承BaseAdapter,需要重写四个方法
②自定义ViewHolder与convertView的优化(判断是否为null);
③可以直接使用item的点击事件
④不用单独设置分隔线
⑤不可以定向刷新某一条数据
RecyclerView:
①继承RecyclerView.Adapter与RecyclerView.ViewHolder
②必须使用viewholder,封装了view的复用
③设置LayoutManager,以及layout的布局效果
④点击事件可以使用给控件设置点击事件,也可以自定义点击事件
⑤可以自定义绘制分隔线
⑥可以定向刷新某一条数据notifyItemChanged等方法
⑦可以自定义item删除增加的动画效果
3.4 RecyclerView多布局2:奇数位置左图右文字+偶数位置左文字右图片
①RecyclerView基本使用
②定义类型常量
③重写获取条目根据位置分类的方法(getItemViewType)
④重写onCreateViewHolder
,根据类型创建不同的布局
⑤重写onBindViewHolder
,根据不同类型加载不同数据
- 注意:不需要注意索引
3.5 RecyclerView通过接口回调实现点击事件
①在adapter中定义一个内部接口,内部接口定义一个方法,方法参数是我们需要的返回的值;
②在adapter定义借口变量,并设置set方法;
③在onBindViewholder()
中,给条目做一个点击事件
④在fragment或者activity对象调用点击时间即可
3.6 RecyclerView下拉刷新上拉加载更多
①添加依赖
(implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.0')
②在布局中添加刷新控件并找控件
<com.scwang.smartrefresh.layout.SmartRefreshLayout
android:id="@+id/srl"
android:layout_width="match_parent"
android:layout_height="wrap_content">
//下拉刷新
< com.scwang.smartrefresh.layout.header.ClassicHeader
android:layout_width="match_parent"
android:layout_height="match_parent">
//上拉加载更多
<com.scwang.smartrefresh.layout.footer.ClassicsFooter
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.scwang.smartrefresh.layout.SmartRefreshLayout>
③给刷新控件添加加载更多、下拉刷新添加监听,监听中写具体代码
//监听
srl.setOnRefreshLoadMoreListener(this);
//上拉加载更多
@Override
public void onLoadMore(@NonNull RefreshLayout refreshLayout){
page++;
//数据源
initData();
}
//下拉刷新
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
page = 1;
if (list != null && list.size() > 0) {
list.clear();
initData();
}
④刷新完毕列表,关闭SmartRefreshLayout头和脚
srl.finishRefresh();
srl.finishLoadMore();
4 Fragment
4.1 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全名
4.2 动态添加fragment(五步)
//获取碎片管理器
FragmentManager fm = getSupportFragmentManager();
//开启事务
FragmentTransaction fragmentTransaction = fm.beginTransaction();
//获取fragment对象
AFragment aFragment = new AFragment();
//替换容器中内容
fragmentTransaction.replace(R.id.fl_container, aFragment);
//提交事务
fragmentTransaction.commit();
4.3 Transaction常用方法
①add 添加
②remove 移除
③replace 替换
④hide 隐藏
⑤show 显示
⑥attach 重建view视图,附加到UI上并显示
⑦detach 会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护
⑧commit 提交事务
4.4 fragment生命周期
①onAttach() 当Fragment与Activity发生关联时调用
②onCreate()
③onCreateView() 创建该Fragment的视图
④onActivityCreated() 当Activity的onCreate方法返回时调用
⑤onStart()
⑥onResume()
⑦onPause()
⑧onStop()
⑨onDestroyView() 与onCreateView想对应,当该Fragment的视图被移除时调用
⑩onDestroy()
⑪onDetach() 与onAttach相对应,当Fragment与Activity关联被取消时调用
4.5 fragment传递数据到activity
①获取activity对象,调方法
//获取getActivity(),强转成MainActivity
MainActivity activity = (MainActivity) getActivity();
activity.getMsgFromFramgent("我是来自fragment的数据");
② 接口回调传递数据
Java接口与接口回调在Android中的使用
③通过fragment的有参构造传递数据(不推荐)
4.6 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");
4.7 fragment与fragment之间传递数据
①通过构造方式传值(不推荐)
②通过FragmentManager找到对应id或者Tag的Fragment,然后获取里面的数据或者方法
③通过它们所在的Activity作为桥梁,可以使用getActivity()或者接口回调,达到获取另一个Fragment数据的目的
4.8 RedioGroup底部导航结合Fragment切换
//创建布局找控件
fl_container = (FrameLayout) findViewById(R. id.fl_ container);
rb_a = (RadioButton) findViewById(R.id.rb_a);
rb_b = (RadioButton) findViewById(R.id.rb_b);
rg = (RadioGroup) findViewById(R. id.rg);
//获取碎片管理器
fm = getSupportFragmentManager();
//开启一个事物
FragmentTransaction fragmentTransaction = fm. beginTransaction();
aFragment = new AFragment();
bFragment = new BFragment();
//添加fragment并提交事务
fragmentTransaction. replace(R.id.fl_container, aFragment). replace(R.id.fl_container, bFragment)
.hide(bFragment).show(aFragment).commit();
//给RedioGroup设置监听并通过switch case显示和隐藏fragment
rg. set0nCheckedChangeListener(new RadioGroup . OnCheckedChangeListener() (
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.rb_a:
fm.beginTransaction().show( aFragment).hide(bFragment).commit();
break;
case R.id.rb_b:
fm.beginTransaction().show( bFragment).hide(aFragment).commit();
break;
}
}
]);
五 ViewPager
5.1 ViewPager+tablayout
①创建布局并找控件
②获取数据集合(存放图片的集合)
③创建适配器(四个方法):
//数量
getCount()
//判断添加的识图是否是当前的view
isViewFronObject()
//
instantiateItem()
//
destroyItem()
④设置适配器
5.2 Viewpager结合Fragment实现导航
①创建布局找控件
②获取fragment的集合fragments
③创建适配器:
FragmentStatePagerAdapter和FragmentPagerAdapter的区别(布局多的用加state,
不知道的可以用加state,两个内部方法一样)
④设置适配器
5.3 Banner使用详情
/**
* banner使用
* 1.添加依赖(implementation 'com.youth.banner:banner:1.4.10')
* 2.创建布局并找控件
* 3.获取网数据
* 4.banner设置图片集合并调用start()方法
*/
runOnUiThread(new Runnable() {
@Override
public void run() {
ArrayList<String> images = new ArrayList<>();
ArrayList<String> titles = new ArrayList<>();
for (int i = 0; i < bannerBean.getData().size(); i++) {
images.add(bannerBean.getData().get(i).getImagePath());
titles.add(bannerBean.getData().get(i).getTitle());
}
//设置图片集合
banner.setImages(images)
//设置图片加载器
.setImageLoader(new ImageLoader() {
@Override
public void displayImage(Context context, Object path, ImageView imageView) {
Glide.with(context).load(path).into(imageView);
}
})
//设置标题 直接设置无效必须设置BannerStyle
.setBannerTitles(titles)
//设置banner样式
.setBannerStyle(BannerConfig.NUM_INDICATOR_TITLE)
//设置banner动画
.setBannerAnimation(Transformer.DepthPage)
//设置间隔时间
.setDelayTime(500)
//启动轮播
.start();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
5.4 TVF
①创建布局找控件
vp = (ViewPager) findViewById(R.id.vp);
tab = (TabLayout) findViewById(R.id.tab);
②创建两个集合:fragments和titles
③创建适配器:
public class MyViewpagerAdapter extends FragmentPagerAdapter {
ArrayList<PageFragment> pageFragmentList;
public MyViewpagerAdapter(FragmentManager fm, List<PageFragment> pageFragmentList) {
super(fm);
this.pageFragmentList = pageFragmentList;
}
@Override
public Fragment getItem(int i) {
return pageFragmentList.get(i);
}
@Override
public int getCount() {
return pageFragmentList.size();
}
}
④ 设置适配器
⑤TV结合:tab.settupWithViewPager(vp);
⑥设置图片选择器:tab.getTabAt(0).setIcon();
5.5 TVF涉及到的懒加载(为了避免页面预加载)
//重写过时方法setUserVisibleHint
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//判断页面是否可见
if (isVisibleToUser) {
//如果页面可见加载数据
initData();
} else {
if (list != null && list.size > 0) {
list. clear();
}
}
}
六 弹窗
6.1 Popupwindow
//加载pop的布局
View view = LayoutInflater .from(this). inflate(R.layout.pop1, root: null);
//创建PopupWindow 对象
PopupWindow pop = new PopupWindow(view, ViewGroup. LayoutParams . WRAP_ CONTENT, ViewGroup . LayoutParam . WRAP_ CONTENT);
//聚焦 如果想在pop上编辑框需要设置该属性
pop.setFocusable(true);
//pop进出场动画
pop.setAnimationStyle(R.style.pop_animation);
//想要实现点击外消失需要设置一个背景
pop.setBackgroundDrawable(new colorDrawable);
//点击范围外消失
pop.setOutsideTouchable(true);
//设置全屏阴影
backgroundAlpha(0.5f);
//把pop设置到控件上
//pop.showAsDropDown(tv_ address, 0, 0);
//把pop设置到布局上
pop.showAtLocation(cl, Gravity.CONTENT, 0, 0);
//设置全屏阴影
private void backgroundAlpha(float alpha) {
Window window = getWindow();
WindowManager. LayoutParams attributes = window . getAttributes( );
attributes.alpha = alpha;
window. setAttributes(attributes );
}
//pop监听
pop.setOnDi smissListener new PopupWindow . OnDismissListener() {
@Override
public void onDismiss() {
//恢复透明度
backgroundAlpha(1f);
}
});
//style文件
<style name= "pop_ animation">
//进场动画
<item name="android windowEnterAnimation">@anim/anim_ enter</item>
//出场动画
<item name="android :windowExitAnimation">@anim/anim_ eixt</item>
</style>
//进场动画
<?xml version="1.0" encoding="utf-8"?>
<set xmlns :android= "http://schemas.android.com/apk/res/android"
android : duration="1500">
<alpha
android : fromAlpha="0"
android:toAlpha="1.0" />
<translate
android : fromXDelta="100%p"
android : fromYDelta="100%p"
android: toXDelta="0"
android :toYDelta="0" />
</set>
//出场动画
<?xml version="1.0" encoding="utf-8"?>
<set xmlns :android= "http://schemas.android.com/apk/res/android"
android : duration="1500">
<alpha
android : fromAlpha="1.0"
android:toAlpha="0" />
<translate
android : fromXDelta="0"
android : fromYDelta="0"
android: toXDelta="100%p"
android :toYDelta="100%p" />
</set>
七 通知
7.1Notification 通知
//创建通知管理器
NotificationManager nm = (NotificationManager) getSystemService (Context.NOTIFICATION_SERVICE);
//兼容O系统:Build.VERSION.SDK_INT得到当前手机的版本
String channelId = "1";
String channelName = "lu";
if (Build.VERSION.SDK INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(true);
channel.setLightColor(Color.RED);
nm.createNotificationChannel(channe);
}
//延时意图
Intent intent = new Intent(this, Main2Activity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 100, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//创建通知对象
Notification notification = new NotificationCompat.Builder(this, channelId)
//通知三要素图标,标题,内容
.setSmallIcon(R.mipmap.ic_Launcher round)
.setContentTitle("标题")
.setContentText("内容")
//设置延时意图
.setContentIntent(pendingIntent)
.build();
//发送通知
nm.notify(hd: 1, notification);
八 权限
8.1 分类:
①普通权限:不需要动态获取
②危险权限:需要动态获取
8.2 九大危险权限
3C 3S L M P
①CALENDAR 日历
②CAMERA 相机
③CONTACTA 联系人
④SEMSORS 传感器
⑤SMS 短信
⑥STORAGE 存储
⑦LOCATION 位置
⑧MICROPHONE 麦克风
⑨PHONE 电话
8.3 如何动态的获取权限
①在清单文件里添加打电话权限
<uses-permission android:name="android.permission.CALL_PHONE"/>
②检查权限
//检查是否授权
private void checkPhonePermission(){
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;
}
//打电话
private void callPhone() {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
startActivity(intent);
}
8.4 通过第三方框架获取权限
①添加依赖
implementation 'com.github.dfqin:grantor:2.5'
②使用
private void authorityGranter() {
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);
}
九 内容提供者
9.1 内容提供者步骤
①创建内容提供者
new→Other→Content Provider
(1)URI格式 Main里面的全类名+.内容提供者类名
(2)手动创建内容提供者:自定义一个类继承自ContentProvider,并重写方法
②在清单文件里注册
<provider
android:name=".ClContentProvider"
android:authorities="com.lulu.contentproviderr.ClContentProvider"
android:enabled="true"
android:exported="true/>
③创建SQL数据库 继承自 SQLitemOpenHelper 并且建库建表
④在内容提供者里面的重写onCreate中获取数据库对象并返回对象,并补齐里面的增删改查方法
⑤创建第二个类contentresolver
//获取内容解析器
ContentResolver contentResolver=getContentResolver();
//获取URI(通用资源标识符)
Uri uri = Uri.parse("content://+清单文件中的authoriries+/+库名");
// insert 插入方法
ContentValues contentValues = new ContentValues();
contentValues.put("数据库字段", "内容");
contentResolver.insert(uri, contentValues);
-
常用Uri:
短信:Telephony.Sms.CONTENT_URI
通讯录: ContactsContract.CommonDataKinds.Phone.CONTENT_URI
图片:MediaStore.Images.Media.EXTERNAL_CONTENT_URI
音频:MediaStore.Audio.Media.ENTERNAL_CONTENT_URI
视频:MediaStpre.Video.Media.ENTERNAL_CONTENT_URI
十 Service
10.1 Service生命周期
①startService生命周期:
onCreate()(开启服务)-→onStartCommand()(服务运行)-→onDestory()(停止服务)
②bindService生命周期:
onCreate()(开启服务)-→onBind()(绑定服务)-→onUnbind(解绑服务)-→onDestory(停止服务)
10.2 startService和bindService区别
1.启动服务中使用StartService()方法来进行方法的调用,调用者和服务之间没有联系,即使调用者退出了,服务依然在进行,onCreate()- >onStartCommand()->onDestroy(),注意其中没有onStart(),主要是被onStartCommand()方法给取代了,onStart方法不推荐使用了。
2.绑定服务中使用bindService()方法来绑定服务,调用者和绑定者绑在一起,调用者一旦退出服务也就终止了onCreate()->onBind()->onUnbind()->onDestroy()。
10.3 Activity和Service之间的数据传递
1.数据从Activity和到Service
intent方式:startService和bindService都可以
2.数据从Activity到Service
IBinder方式:bindService
3.数据从Service到Activity
接口回调和广播
十二.音乐播放器
12.1 MediaPlayer创建方式
① 使用 new MediaPlayer 对象的方式
MediaPlayer mp = new MediaPlayer();
② 使用create的方式
MediaPlayer mp = MediaPlayer.create(this,R.raw.test);
12.2 四种资源
① 用户在应用中事先自带的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](https://links.jianshu.com/go?to=http%3A%2F%2Fmusic.163.com%2Fsong%2Fmedia%2Fouter%2Furl%3Fid%3D139894.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();
}
12.3 assets和raw资源文件夹的区别:
res/raw不可以有目录,而assets则可以有目录结构,也就是assets目录下可以再建立文件夹
12.4 结合SeekBar实现拖动播放音乐功能
//创建seekbar布局
//seekbar设置监听,在停止拖动中player.seekTo(seekBar.getProgress());
//更新seekbar:
private void updataProgress(){
new Thread(newRunnable(){
@Override
public void run(){
while(player.isPlaying()){
try{
Thread.sleep(1000);
seekbar_mp.setMax(player.getDuration());
seekbar_mp.setProgress(player.getCurrentPosition());
}catch(Exceptione){
e.printStackTrace();
}
}
}
}).start();
}
12.5 结合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());
}