移动开发技术【安卓part3】——实现绑定非绑定音乐播放服务及系统广播式启动音乐服务

移动开发技术【安卓part3】——实现绑定非绑定音乐播放服务及系统广播式启动音乐服务,第1张

上一篇请参见

(5条消息) 移动开发技术【Android】:【part 2】——RecyclerView实现列表_With_Zero的博客-CSDN博客https://blog.csdn.net/m0_61067829/article/details/123850913

         在上一篇中我们说到如何使用RecyclerView实现列表功能,自此我们熟悉了Android中的Activity组件,那么接下来我们就要开始学习如何来写一个服务。本篇中主要是来写一个音乐服务,同时最后一个广播式启动音乐服务,则是通过系统模拟接收到Message后,跳转到我们的MainActivity中并播放音乐。

目录

一、进度说明(此项说明本功能的实现使用文件及前期准备)

1、做音乐服务的页面

二、非绑定/绑定式启动音乐

1.非绑定式(UnbindMusic)

2.绑定式(BindMusic)

 3.BindMusic和UnbindMusic比较

三、系统广播式启动音乐服务

总结


一、进度说明(此项说明本功能的实现使用文件及前期准备)

(功能实现说明从第二步开始)

【首先】先看一下我们的目录结构

        在此目录中,我们是根据之前一直所积累所做的,但是在我们说明的时候,会依照怎么做去说明,但是希望可以清清楚我们主要用到了那些文件。

1、做音乐服务的页面

【fragment_friend】UI界面

 可以看到,此界面有UnbindMusic和BindMusic两个模块:

        UnbindMusic :非绑定启动音乐服务

        BindMusic:绑定式启动音乐服务

【主要代码】

        view = inflater.inflate(R.layout.fragment_fridend, container, false);

        tab05 = view.findViewById(R.id.friendtab05);
        tab06 = view.findViewById(R.id.friendtab06);



        tab05.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MainActivity main = (MainActivity) getActivity();
                main.show(5);

            }
        });

        tab06.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                MainActivity main = (MainActivity) getActivity();
                main.show(6);
            }
        });

        return view;

        这里的显示show()主要使用了MainActivity之前写的方法。详情可以参看爬取gitee源代码见方法实现。

【音乐启动页面】

        明白我们的逻辑后,下面我们进入具体实现 *** 作!


二、非绑定/绑定式启动音乐 1.非绑定式(UnbindMusic)

    private View view;
    private LinearLayout unbindtab01,unbindtab02;
    Service1.Mybinder binder;

     @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        Log.d("friend","uuuuuuuuuuuuu");

        view = inflater.inflate(R.layout.fragment_unbind_music,container,false);

        unbindtab01 = view.findViewById(R.id.unbindtab01);
        unbindtab02 = view.findViewById(R.id.unbindtab02);


        Intent intentservices = new Intent(getActivity(),Service1.class);

        unbindtab01.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getActivity().startService(intentservices);
            }
        });

        unbindtab02.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getActivity().stopService(intentservices);
            }
        });

        return view;
//        return inflater.inflate(R.layout.fragment_unbind_music, container, false);
    }

        这里我们看到,我们通过id找到两个Layout(unbindtab01、unbindtab02)后进行点击动作监听。我们通过Intent,使得跳转到Service1进行启动服务。

//目的进入Service1服务
Intent intentservices = new Intent(getActivity(),Service1.class);

        然后我们在unbindtab01(启动)中startService(intentservices)

        在unbindtab02(停止)中stopService(intentservices)

【Service1】

public class Service1 extends Service {

    MediaPlayer mediaPlayer;

    public class Mybinder extends Binder{
        public void myplay(){
            mediaPlayer=MediaPlayer.create(getApplicationContext(),R.raw.lovevisemusic);
            mediaPlayer.start();
        }
    }

    //绑定非绑定都会启动此方法
    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("service1","service1 is oncreate");
        mediaPlayer=MediaPlayer.create(getApplicationContext(),R.raw.yuxitanmusic);

    }

    //邦定式服务不启动此方法
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("service1","service1 is onStartCommand");
        mediaPlayer=MediaPlayer.create(this,R.raw.yuxitanmusic);
        mediaPlayer.start();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        Log.d("service1","service1 is onDestroy");
        mediaPlayer.stop();
        super.onDestroy();
    }



    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new Mybinder();


    }

    @Override
    public boolean onUnbind(Intent intent) {
        return super.onUnbind(intent);
    }


    @Override
    public boolean stopService(Intent name) {
        Log.d("service1","service1 is stop");
        return super.stopService(name);
    }
}

其中我们通过这一句绑定音乐文件。

mediaPlayer=MediaPlayer.create(getApplicationContext(),R.raw.yuxitanmusic);

(注意:将你的音乐文件放在res/raw中,这里raw文件夹自己新建一下。)

        

另外,service还要在AndroidManifest.xml中标记一下。

 到此,非绑定的服务书写结束


2.绑定式(BindMusic)

    private View view;
    private LinearLayout tab01,tab02;
    Service1.Mybinder binder;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        Log.d("friend","bbbbbbbbbbbbbb");
        view = inflater.inflate(R.layout.fragment_bind_music,container,false);



        Intent intentservices = new Intent(getActivity(),Service1.class);

        ServiceConnection connection= new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                binder = (Service1.Mybinder)iBinder;
                binder.myplay();
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                binder=null;
            }
        };


        tab01 = view.findViewById(R.id.bindtab01);
        tab02 = view.findViewById(R.id.bindtab02);

        tab01.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                getActivity().bindService(intentservices,connection, Context.BIND_AUTO_CREATE);//绑定服务
            }
        });

        tab02.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                getActivity().unbindService(connection);
            }
        });


        return view;
//        return inflater.inflate(R.layout.fragment_bind_music, container, false);
    }

        在这里我们做了什么呢?注意,我们这里加了一个属性ServiceConnection connection,来建立与Service1的连接,连接谁呢?这里我们注意是不是在Service1中有个Myplay方法(见下图)?这个方法是我们自定义的,用来启动音乐播放服务,其中两行分别就是:绑定音乐、开启服务。

         除此之外,和非绑定式一样,都是利用了Service1服务,但是注意,我们利用binder绑定服务,在解除绑定时我们则是直接让binder=null。至此,非绑定式服务写完了。


 3.BindMusic和UnbindMusic比较

        我们如何比较两者差异呢?那我们将通过生命周期和效果来看。

(1)生命周期

【UnbindMusic】

 Logcat日志记录:

2022-04-19 19:22:42.514 9475-9475/? D/service1: bbbbbbbbbbbbbbb
2022-04-19 19:22:42.531 9475-9475/? D/service1: uuuuuuuuuuuuuuuuuuu
2022-04-19 19:24:20.043 9475-9475/com.example.mywork D/service1: onclick to start unbind......
2022-04-19 19:24:32.162 9475-9475/com.example.mywork D/service1: unbind start music....
2022-04-19 19:24:32.169 9475-9475/com.example.mywork D/service1: service1 is oncreate
2022-04-19 19:24:32.189 9475-9475/com.example.mywork D/service1: service1 is onStartCommand
2022-04-19 19:24:53.138 9475-9475/com.example.mywork D/service1: unbind stop music....
2022-04-19 19:24:53.140 9475-9475/com.example.mywork D/service1: service1 is onDestroy

        前两项是BindMusicFragment和UnbindMusicFragment启动的提示,我们打了Log都设为service字段记录。

        UnbindMusic:Oncreate ->OnSraerCommand -> OnDestory  (生命周期)

【bindMusic】

  Logcat日志记录:

2022-04-19 19:31:20.761 9475-9475/com.example.mywork D/service1: onclic to start bind.....
2022-04-19 19:31:25.810 9475-9475/com.example.mywork D/service1: bind start music....
2022-04-19 19:31:25.813 9475-9475/com.example.mywork D/service1: service1 is oncreate
2022-04-19 19:31:25.831 9475-9475/com.example.mywork D/service1: Mybinder is working....
2022-04-19 19:31:33.274 9475-9475/com.example.mywork D/service1: bind stop music....
2022-04-19 19:31:33.276 9475-9475/com.example.mywork D/service1: service1 is onDestroy

        这里就和非绑定的服务产生差别了,生命周期有了变化。

                BindMusic:  Oncreate -> Mybinder -> OnDestory

(2)效果不同

        非绑定式的服务,在启动后,返回桌面后,并不会停止,而是在后台继续播放音乐,即在离开当前Activity后,不会影响服务。

        绑定式服务,在启动后,返回桌面后,服务就会停止,即在离开当前Activity后服务就结束了。当然,假设你进入第二个Activity,第一个Activity并没有Destory的话,服务也自然不会停止。

        这里我们说明一下,因为我们只写了一个Activity,其他Fragment都是依赖于这个Activity的,因此我们选择以返回界面来检测差异。


三、系统广播式启动音乐服务

        首先说明,这部分功能实现效果:在我们利用编译器给自己发信息后,我们会启动MainActivity,同时会启动我们绑定的服务,即播放音乐。

【MyReceiver】广播接收

package com.example.mywork;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class MyReceiver1 extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        // an Intent broadcast.
        Log.d("onReceiver","get receiver");
        Intent receiverintent1 = new Intent(context,Service1.class);
        context.startService(receiverintent1);
        Intent receiverintent2 = new Intent(context,MainActivity.class);
        receiverintent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(receiverintent2);
    }
}

        在我们监听接收到系统消息后,我们会启动MainActivity和Service1。

但是在这里我们要注意,接收功能写完后,我们需要去注册驱动并且授权。这里就要说到,授权分为两种:静态授权、动态授权。这里我们进行动态授权,静态授权可能会出现问题不能启动。

【AndroidManifest.xml】


        


        
            
                
            
        

    

        我们需要把上面几行加进去,注意receiver对应你自己的name,其他不用变,你创建Brocastreceiver应该会自动生成,注意修改一下就好。

 【动态授权】

    //动态授权
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        Log.d("aaa","??????");
        switch (requestCode){
            case 1:
                if(grantResults[0]!=PackageManager.PERMISSION_GRANTED){
                    Toast.makeText(this, "未授权,无法实现预定的功能!", Toast.LENGTH_SHORT).show();
                    finish();
                } else {
                    Toast.makeText(this, "请发一条短信验证!", Toast.LENGTH_SHORT).show();
                }
        }
    }
 //授权
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{"android.permission.RECEIVE_SMS"}, 1);
        }

        如图这里我是这样写的,把这两段分别找到为止加入你要写的地方,因为我们要跳转到MainActivity,所以我们在MainActivity中编辑。

         这样我们就把这个服务写完了,然后我们试一下效果:

———————————————————————————————————————————

首先我们假若不注册:则未授权无法进入

 我们恢复注册后:会提示是否允许接收信息,选择allow

     

 然后它会说请发一条信息(只有第一次会d出)

      

点击这里的三个小圆点,选择Phone,就可以模拟发送消息给模拟器

   

 那么现在你应该收到消息了

         最后服务就启动了,音乐响起!注意我们启动的是Service1,所以要停止可以直接使用UnbindMusic中的停止按钮,不要用BindMusic,可能会有bug。


总结

        至此,本次的所有实验都结束了,主要就是初步学习一下如何写一个服务,观察服务的生命周期等重要属性。当然本次过程中也遇到bug:

        1、MyReceiver拷贝过来无法接收消息:这里可能和编译器环境因素有关系,自己重新创建文件复制代码就可以解决了,一定要关注编译器自身是否存在缓存、无法及时更新等问题,这种问题往往最难发现。

        2、在最后一项广播启动服务中,我们先启动项目,然后后台关闭,再发消息,就会启动服务,但是这里软件并未启动。

最后附上本篇gitee:Android_Studion_Mobile: 针对移动开发的学习代码记录

With_Zero 2022.04.19

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/876682.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存