• Android Service 与 Activity使用Pending Intent通信


    Android Service 与 Activity使用Pending Intent通信

    service使用pending intent返回结果给客户端


    我们使用一个activity作为一个客户端,来通过startService()的方法启动一个服务,这个服务的功能很简单,就是去访问客户端指定的Url,然后返回这个url对应的页面的源代码的字符数量。这个例子中,我们是不允许这个服务被绑定的。即我们在onBind()方法中返回null。那么好了,现在我们这个服务不可以被绑定,只可以通过startService()的方法启动,那么此时服务和客户端的通信方式就只有一种了,即通过Pending Intent了。

    1.首先自定义我们的服务类:MyService

    public class MyService extends Service {
        private ServiceHandler mHandler;
        //内部类
        private final  class ServiceHandler extends Handler{
    
            public ServiceHandler(Looper looper){
                super(looper);
            }
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if(msg.what == 0x1234){
                    Log.v("MyService","handleMessage()被调用");
    
                    int charNum = ((String)(msg.obj)).length();
                    Bundle bundle = msg.getData();
                    PendingIntent client = bundle.getParcelable("receiver");
    
                    Log.v("MyService","字符数为" + charNum);
                    Intent intent = new Intent();
                    intent.putExtra("CHARNUM",charNum);
                    try {
                        client.send(getApplicationContext(),0,intent);
                        Log.v("MyService","广播发送完成");
                    } catch (PendingIntent.CanceledException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        @Override
        public void onCreate() {
            super.onCreate();
            mHandler = new ServiceHandler(this.getMainLooper());
            Log.v("MyService","onCreate()被调用");
        }
    
        @Override
        public int onStartCommand(final Intent intent, int flags, final int startId) {
            Log.v("MyService","onStartCommand()被调用");
            final String urlString = intent.getStringExtra("URL");
            new Thread(){
                @Override
                public void run() {
                    try {
                        String result = null;
                        BufferedReader in = null ;
    
                        URL url = new URL(urlString);
                        URLConnection conn = url.openConnection();
    
                        conn.connect();//建立连接
    
                        in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                        String line = null;
                        while ((line = in.readLine()) != null ){
                            result += "
    " + line;
                        }
    
                        Log.v("URL请求结果",result);
                        //发送消息
                        Message msg = new Message();
                        msg.what = 0x1234;
                        msg.arg1 = startId;
                        msg.obj = result;
                        msg.setData(intent.getExtras());
                        mHandler.sendMessage(msg);
    
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
                }
            }.start();
    
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            Log.v("MyService","onBind()被调用");
            return null;
        }
    
    }
    



    对于每一个startService()请求,我们都开启了一个新的线程去访问指定的额URL,并对字符串计数。服务里面最重要的便是自定义的Handler里面的handleMessage()方法了,这个方法里面我们取出client传给服务的intent,然后在这个intent里面取出序列化的pendingintent,然后再将其反序列化成为pending intent对象。最后理由这个客户端定义好的pending intent,给广播接受者发送广播,当然广播内容便是我们需要返回给客户端的的结果了。

    2.MainActivity类

    	public class MainActivity extends AppCompatActivity implements View.OnClickListener,MyBroadcastReceiver.onServiceResultReturnListener{
    
    	    Button btnStartService,btnBindService,btnStartServiceForResult;
    
    	    MyBroadcastReceiver receiver;
    	    @Override
    	    protected void onCreate(Bundle savedInstanceState) {
    	        super.onCreate(savedInstanceState);
    	        setContentView(R.layout.activity_main);
    
    	        btnStartServiceForResult = (Button)findViewById(R.id.id_btn_startServiceForResult);
    	        btnStartServiceForResult.setOnClickListener(this);
    
    	        //初始化广播接受者
    	        initBroadcastReceiver();
    	    }
    
    	    @Override
    	    public void onClick(View view) {
    	        switch (view.getId()){
    
    	            case R.id.id_btn_startServiceForResult:
    	                Intent sfIntent = new Intent(this,MyService.class);
    
    	                Intent broadIntent = new Intent();
    	                broadIntent.setAction("cn.edu.dlut.receiver");
    
    	                PendingIntent pIntent = PendingIntent.getBroadcast(this,0,broadIntent,0);
    	                Bundle bundle = new Bundle();
    	                bundle.putParcelable("receiver",pIntent);
    
    	                sfIntent.putExtras(bundle);
    	                sfIntent.putExtra("URL","http://www.baidu.com");
    	                startService(sfIntent);
    	                Log.v("MainActivity","startService()方法被调用");
    	                break;
    	        }
    	    }
    	    //初始化广播接收者
    	    private void initBroadcastReceiver(){
    	        receiver = new MyBroadcastReceiver(this);
    	        this.registerReceiver(receiver,new IntentFilter("cn.edu.dlut.receiver"));
    	        Log.v("MainActivity","广播接受者动态注册初始化完成");
    
    	    }
    
    	    @Override
    	    protected void onDestroy() {
    	        super.onDestroy();
    	        this.unregisterReceiver(receiver);
    	    }
    
    	    @Override
    	    public void onServiceResultReturn(Intent intent) {
    	        int charNum = intent.getIntExtra("CHARNUM",0);
    	        Toast.makeText(this,"字符数为" + charNum,Toast.LENGTH_SHORT).show();
    	    }
    	}
    
    	//自定义广播接受者
    	class MyBroadcastReceiver extends BroadcastReceiver{
    	    //回调接口
    	    public interface onServiceResultReturnListener{
    	         void onServiceResultReturn(Intent intent);
    	    }
    
    	    private onServiceResultReturnListener client;
    
    	    public MyBroadcastReceiver(onServiceResultReturnListener client){
    	        this.client = client;
    	    }
    	    @Override
    	    public void onReceive(Context context, Intent intent) {
    	        Log.v("MyBroadcaseReceiver","onReceive()方法被调用");
    	        this.client.onServiceResultReturn(intent);
    	    }
    	}
    


        demo程序源代码,已上传至git上面https://github.com/Spground/ServiceDemo

    3.总结
        利用pending intent作为started service(即用startService()启动的服务)与client通信的步骤大致如下:
        1.实现自己的Service类,并取得client传递过来的intent,因为这个intent里面包含我们序列化的pending intent。
        
        2.自定义广播接受者,并在client端动态注册广播接收者(静态注册也可以,只要广播接受者收到消息后会通知到client)
        
        3.定义好client与广播接受者通信的回调接口
        
        4.在client端调用startService()方法启动服务的时候,讲pending intent准备好,并将其序列化作为Extras放进入启动服务的intent中.

    总的来说,使用这种方式来进行服务 和 client通信是十分繁琐的,后面有绑定服务运行方式,会在绑定成功以后给client一个实现了IBinder的实例,
    通过让服务实现IBinder接口,便可以将服务的实例的引用作为返回值传递给client,client便可以用这个接口与服务通信了,当然也还是可用使用广播的形式让服务与client通信。
  • 相关阅读:
    继承—泛型
    单例模式
    继承 4—Monkey
    继承 3—A B E
    继承 2—people
    继承 1—Mucic
    面向对象—汽车
    面向对象—封装—汽车
    Linux下查看CPU型号,内存大小,硬盘空间的命令
    redis源码——数据结构与对象
  • 原文地址:https://www.cnblogs.com/Spground/p/8536164.html
Copyright © 2020-2023  润新知