zoukankan      html  css  js  c++  java
  • 入门篇:7.组件2:Android Service-service的数据传递与通信

    (由于对java的回调机制和线程理解的不够透彻,所以这块内容我理解了好久,尤其是绑定服务传递数据,一句一句写一句一句看,对我来说挺难理解的。以后还要多看几遍--!)

          既然单纯的启动或跳转activity没有意义,那么同样的,单纯的启动或绑定service也是无意义的,实际应用中常常要携带数据启动service或绑定service。

    1.启动service并传递数据

    (1)新建一个Service:MyService

    (2)在布局中添加两个按钮,启动服务和停止服务,和一个EditText,用户传递数据

    (3)给两个按钮添加监听器,分别执行startService方法和stopService方法

    (4)在MyService类中onCreate方法添加一个控制台输出语句,便于我们看到服务的状态和数据的传递效果。

    (5)在开始按钮的onClick方法中添加intent.putExtra("data",etData.getText().toString()),用于在activity中初始化和传递数据。

    (6)在MyService类中重写onStartCommand方法,其中的intent参数用于接收activity传来的数据。intent.getStringExtra("data");

    此时运行程序,点击启动服务,会在控制台输出界面输入框中的数据,更改数据再次点击启动服务,控制台输出的数据也随之改变。点击停止服务,控制台停止输出。

    代码如下:

    MyService.java:

    public class MyService extends Service {
        private boolean running = false;
        private String data = "这是默认信息";
    
        public MyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            // TODO: Return the communication channel to the service.
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            data = intent.getStringExtra("data");
    
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            running = true;
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    while(running){
    
                        System.out.println(data);
                        try {
                            sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            running = false;
        }
    }

    MainActivity.java:

    import android.os.Bundle;
    import android.support.v7.widget.SwitchCompat;
    import android.view.View;
    import android.widget.EditText;
    
    import layout.MyService;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    
        private EditText etData;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            findViewById(R.id.btnStartSevice).setOnClickListener(this);
            findViewById(R.id.btnStopSevice).setOnClickListener(this);
            etData = (EditText) findViewById(R.id.etData);
    
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btnStartSevice:
                    Intent i = new Intent(this, MyService.class);
                    i.putExtra("data",etData.getText().toString());
                    startService(i);
                    break;
                case R.id.btnStopSevice:
                    stopService(new Intent(this,MyService.class));
                    break;
    
            }
        }
    }

    activity_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:orientation="vertical"
        tools:context="com.example.lzc.connectservice.MainActivity">
        <EditText
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="默认信息"
            android:id="@+id/etData"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!" />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="启动服务"
            android:id="@+id/btnStartSevice" />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="停止服务"
            android:id="@+id/btnStopSevice" />
    </LinearLayout>

    2.绑定服务并传递数据(执行服务的内部代码)<由于侦听服务状态也包括执行服务内部代码,所以第二部分和第三部分的代码在第三部分下面一起贴出来>

     (1)在布局中添加三个按钮,绑定服务、解除绑定服务、同步数据,同步数据按钮是用来同步activity传到service的数据。

     (2)给绑定服务和解除绑定服务按钮添加监听器,执行以下代码

            绑定服务:bindService(new Intent(this,MyService.class),this, Context.BIND_AUTO_CREATE);

            解除绑定服务:unbindService(this);

     (3)同时实现两个方法onServiceConnected()和onServiceDisconnectid(); 

     (4)在MyService类中添加一个Binder 类,该类内添加一个成员方方法setData()用来实时更改数据。

    public class Binder extends android.os.Binder{
             public void setData(String data){
                 MyService.this.data = data;
             }
        }

     (5)在MyService类中的onBind方法中添加return new Binder();返回上一步新建的类的一个对象作为一个activity与service绑定的纽带。

     (6)回到MainActivity.java,创建一个binder:MyService.Binder binder = null;

     (7)在onServiceConnected()方法中添加 binder = (MyService.Binder) iBinder; 

     (8)在同步数据按钮的onClick()方法中执行以下代码:

    if(binder!=null){
         binder.setData(etData.getText().toString());
     }

    至此完成绑定服务并传递数据。这样的用法好处是不用每次同步数据时都发送一个intent,而是直接通过调用方法来同步数据,保证了代码的高效性,也很快捷。

    3.绑定服务并传递数据(侦听服务内部状态)

    利用java的回调机制,从activity传递数据到service,service接到数据或数据改变时回调回来呈现在activity中

    (1)在MyService类中添加一个CallBack接口,添加抽象方法onDataChange()。

    (2)在MyService类中创建CallBack的对象,并添加get和set方法。

    (3)在binder类中添加一个getService()方法,返回MyService.this.

    (4)回到外部的MainActivity,布局添加一个TextView用于显示服务的状态。

    (5)在onServiceConnected方法中添加binder.getService().setCallback(),给service添加回调函数,并且实现onDataChange方法,把数据通过Message传给Handler。

    (6)在MainActivity中添加一个Handler(由于安全机制,安卓的UI线程不允许随意被调用。所以只能用Handler来改变UI),在Handler中改变TextView的值。

    所有的代码如下:

    MyService.java:

    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    
    public class MyService extends Service {
        private boolean running = false;
        private String data = "这是默认信息";
    
        public MyService() {
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return new Binder();
        }
    
        public class Binder extends android.os.Binder{
             public void setData(String data){
                 MyService.this.data = data;
             }
            public MyService getService(){
                return MyService.this;
            }
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            data = intent.getStringExtra("data");
    
            return super.onStartCommand(intent, flags, startId);
        }
    
        @Override
        public void onCreate() {
            super.onCreate();
            running = true;
            new Thread() {
                @Override
                public void run() {
                    super.run();
                    int i = 0;
                    while(running){
                        i++;
                        String str = i+":"+data;
                        System.out.println(i+":"+data);
                        if(callback!=null){
                            callback.onDataChange(str);
                        }
    
                        try {
                            sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }.start();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            running = false;
        }
    
        private CallBack callback = null;
    
        public void setCallback(CallBack callback) {
            this.callback = callback;
        }
    
        public CallBack getCallback() {
            return callback;
        }
    
        public static  interface CallBack{
            void onDataChange(String data);
        }
    }

    activity_main.xml和MainActivity:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:orientation="vertical"
        tools:context="com.example.lzc.connectservice.MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="New Text"
            android:id="@+id/tvOut" />
    
        <EditText
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="默认信息"
            android:id="@+id/etData"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!" />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="启动服务"
            android:id="@+id/btnStartSevice" />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="停止服务"
            android:id="@+id/btnStopSevice" />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="绑定服务"
            android:id="@+id/btnBindService" />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="解除绑定服务"
            android:id="@+id/btnUnbindService" />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="同步数据"
            android:id="@+id/btnSyncData" />
    </LinearLayout>
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.support.v7.widget.SwitchCompat;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.TextView;
    
    import layout.MyService;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection {
    
        private EditText etData;
        private TextView tvOut;
        private MyService.Binder binder = null;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            etData = (EditText) findViewById(R.id.etData);
            findViewById(R.id.btnStartSevice).setOnClickListener(this);
            findViewById(R.id.btnStopSevice).setOnClickListener(this);
            findViewById(R.id.btnBindService).setOnClickListener(this);
            findViewById(R.id.btnUnbindService).setOnClickListener(this);
            findViewById(R.id.btnSyncData).setOnClickListener(this);
            tvOut = (TextView) findViewById(R.id.tvOut);
    
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btnStartSevice:
                    Intent i = new Intent(this, MyService.class);
                    i.putExtra("data",etData.getText().toString());
                    startService(i);
                    break;
                case R.id.btnStopSevice:
                    stopService(new Intent(this,MyService.class));
                    break;
                case R.id.btnBindService:
                    bindService(new Intent(this,MyService.class),this, Context.BIND_AUTO_CREATE);
                    break;
                case R.id.btnUnbindService:
                    unbindService(this);
                    break;
                case R.id.btnSyncData:
                    if(binder!=null){
                        binder.setData(etData.getText().toString());
                    }
                    break;
    
            }
        }
    
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
          binder = (MyService.Binder) iBinder;
            binder.getService().setCallback(new MyService.CallBack() {
                @Override
                public void onDataChange(String data) {
                     Message msg = new Message();
                     Bundle b = new Bundle();
                     b.putString("data",data);
                     msg.setData(b);
                     handler.sendMessage(msg);
                }
            });
        }
    
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
    
        }
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                tvOut.setText(msg.getData().getString("data"));
    
    
            }
        };
    }
  • 相关阅读:
    Luogu P4727-- 【HNOI2009】图的同构记数
    UOJ #390. 【UNR #3】百鸽笼
    Loj #2541「PKUWC2018」猎人杀
    BZOJ 1444:[JSOI2009]有趣的游戏
    CF895C: Square Subsets && 【BZOJ2844】albus就是要第一个出场
    [NOI2011]阿狸的打字机
    不要再搜啦,满足你的需要,封装保留小数点后两位
    react 中刷新,路由传参数丢失不存在了?
    字符串根据某个符号查找并截取
    react-swiper 如何实现滑动小卡片的移动?
  • 原文地址:https://www.cnblogs.com/androidNot/p/5601082.html
Copyright © 2011-2022 走看看