Android中级思路

一 二级列表(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使用详情

/**
 * 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());
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容

  • 前言 ①方法:思路+案例、预习思路②补充知识点:debug、代码规范、约束布局③学生讲课:三四节课学生讲课(学委-...
    Anwfly阅读 1,029评论 0 6
  • 1, 二级列表(ExpandableListView) ①创建布局,找控件②获取数据:死数据、网络数据③创建适配器...
    一只易拉宝阅读 198评论 0 0
  • 1.二级列表ExpandableListView (1).创建布局,找控件 (2).获取数据:死数据,网络数据 (...
    孙_慧_雯阅读 347评论 0 0
  • 随着卡尼暗示5月加息并非板上钉钉,英镑多头的热情退却。市场担心卡尼次日凌晨的讲话将再度打压英镑。不过,包括法农银行...
    雷老冇阅读 215评论 0 0
  • 流程图 Excel输入image.png Switch / caseimage.png Excel输出image....
    千客阅读 874评论 0 0