精华内容
下载资源
问答
  • ②ESP8266与手机交互多种方式

    千次阅读 2019-03-02 00:23:45
    说明:学习edp8266模块与手机发送与接收数据,这节为今后学习8266与8266模块的交互和使用手机控制8266模块的的目的。 一、原料 硬件:①esp8266-wifi模块②usb转ttl③5v转3.3v模块④杜邦线 软件:安卓下安装...

    说明:学习edp8266模块与手机发送与接收数据,这节为今后学习8266与8266模块的交互和使用手机控制8266模块的的目的。

    一、原料

    硬件:①esp8266-wifi模块②usb转ttl③5v转3.3v模块④杜邦线

    软件:安卓下安装“有人网络助手”

    二、TCP

    1、AP模式下模块的tcp服务配置步骤

    在这里插入图片描述

    2、手机作为tcp客户端连接模块

    在这里插入图片描述在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    3、模块与手机交互

    手机端发送数据

    在这里插入图片描述

    串口工具接收数据后显示

    在这里插入图片描述

    串口工具发送数据AT+CIPSEND

    在这里插入图片描述

    在这里插入图片描述
    手机接收到数据

    在这里插入图片描述

    尝试许久之后,你会发现,这样的方式送数据是不是很麻烦,每次都要AT+CIPSEND一次才能发送一次数据。下一章将会讲一下透传模式。
    

    三、UDP

    与TCP一样的配置步骤:
    模块连接好热点AT+CWJAP=”ssid”,”password”
    模块设置为多连接模式AT+CIPMUX=1
    手机在udp server项配置udp端口,和记录手机ip
    模块进行UDP连接AT+CIPSTART=0,”UDP”,”192.168.***.***”,端口号1,端口号2
    (端口号1是指手机udp server的端口号,端口号2是设置模块的端口号)

    会遇到的问题:

    1.为什么连上udp之后,模块能收到手机数据而手机收不到模块数据,或者是手机收的到模块数据而模块收不到手机数据?
    答:检查端口号1和端口号2是否写对,是否写反。

    展开全文
  • 多种方式实现JS调用后台方法进行数据交互  项目开发过程中很多地方都需要前端和后台的数据交互,几种典型常用的方法如利用控件的AutopostBack属性、Button提交表单等等。但这些都是有条件的,...

    多种方式实现JS调用后台方法进行数据交互


        项目开发过程中很多地方都需要前端和后台的数据交互,几种典型常用的方法如利用控件的AutopostBack属性、Button提交表单等等。但这些都是有条件的,AutoPostBack具有实时性但会刷新页面,Button提交表单不能实现数据交互的实时性。当然说到前台与后台的数据交互更不能漏掉ajax,ajax实现前台与后台数据的异步交互,并且保证实时的、局部刷新。但有些数据不需要异步交互,例如当交互的数据是下一步执行的条件时,就必须要等到数据前台与后台数据交互完成后才能继续执行程序。所以对于掌握js与后台数据交互的方法还是很有必要的。

        方法一

        后台方法:

        复制代码代码如下:

        // 需要标识为WebMethod

        [System.Web.Services.WebMethod]

        // 注意,要让前台调用的方法,一定要是public和static的

        public static string Say(string name)

        {

        string result = "Hello:" + name;

        return result;

        }

        前台js:

        复制代码代码如下:

       

    function btnClick(){

        PageMethods.Say("you",funReady,funError);//注意js中调用后台方法的方式

        }

        //回调函数, result 就是后台方法返回的数据

        function funReady(result){

        alert(result);

        }

        //错误处理函数,err 就是后台方法返回的错误信息

        function funError(err){

        alert("Error:" + err._message );

        }

       

       

       

        方法二

        后台方法:

        复制代码代码如下:

        protected string Say(string strCC)

        {

        strCC = "你好!" + strCC;

        return strCC;

        }

        前台js:

        复制代码代码如下:

        function Show()

        {

        var v = "中国";

        var s = '<%=Say("'+v+'") %>'; // 你好!“+V+”

        alert(s);

        }

        方法三

        后台方法:

        复制代码代码如下:

        // 需要标识为WebMethod

        [System.Web.Services.WebMethod]

        // 注意,要让前台调用的方法,一定要是public和static的

        public static string Say(string name)

        {

        string result = "Hello:" + name;

        return result;

        }

       

        前台js:

        复制代码代码如下:

       

    function btnClick(){

        // 调用页面后台方法,前面跟方法所需的参数,接着是方法回调成功时要执行的js函数,最后一个是方法回调失败时要执行的js函数

        WebSerCustomer.Say("you",function(ress){//ress就是后台方法返回的数据,Say是webservice WebSerCustomer.axms页面上的方法

        alert(ress)

        });

        }

       

       

        //WebSerCustomer.asmx后台webservice类的页名称

       

        

        总结

        对于方法一和方法三来说,标识System.web.Services.webmethod可以声明一个方法可以通过客户端js函数来调用,并且后台方法必须声明为public和static,正是由于要将方法声明为static,使得这两种方法都有局限性,即静态方法中只允许访问静态成员变量。所以要想用这两种方式调用后台方法,后台方法中是不能访问非静态成员变量的。

        对于方法二来说,虽然后台方法没有任何限制,但是前台调用的时候由于<%=%>是只读的,前台向后台传的参数实际上是不存在的,即从后台中拿不到。所以方法二适合于调用后台方法经过处理并返回给客户端使用,不适合于将数据传到后台供后台使用。

    展开全文
  • 上一篇文章:Android中程序与Service交互方式——综述 简述了Service的一些基础知识以及Service和Thread的简单区别,本文将着重讲解与Service交互的五种基本方式:广播交互、共享文件交互、Mssenger(信使)交互、...
    上一篇文章:Android中程序与Service交互的方式——综述 简述了Service的一些基础知识以及Service和Thread的简单区别,本文将着重讲解与Service交互的五种基本方式:广播交互、共享文件交互、Mssenger(信使)交互、自定义接口交互、AIDL交互。
    

           1. 广播交互

           提到Activity与Service的交互,可能狠多人首先想到的就是BroadCast——广播。在Android中,广播是系统提供的一种很好的交互方式。比如:在电池电量过低,开机完成等情况下,系统都会发出相应的系统广播,我们的应用程序只需要注册相应的广播接收器,就可以接收到这些系统的广播。同时,我们也可以定义自己的广播,这样在不同的Activity、Service以及应用程序之间,就可以通过广播来实现交互。我们通过模拟应用程序后台下载的情况来分析Service与Activity的交互方式。实现效果如图1.1:

    图1.1

            当我们点击StartService按钮之后,界面上的进度条将会每隔一秒加1。因为是模拟下载,因此下载动作我们在Service中通过一个Timer定时器来实现,在Timer中对一个整型数据i进行自加(i++),然后Client端获取Server端的i值并显示在界面上,从而达到模拟的目的。

            1.1. 实现原理

            Server端将目前的下载进度,通过广播的方式发送出来,Client端注册此广播的监听器,当获取到该广播后,将广播中当前的下载进度解析出来并更新到界面上。

            1.2. 实现步骤

            1.2.1 在Client端中通过startService()啟动Service。

    [java] view plaincopy
    1. if(v == startBtn){  
    2.     Log.i(TAG, "start button clicked...pid: "+Process.myPid());  
    3.     mIntent.setClass(BroadCastService.this, DownLoadService.class);  
    4.     startService(mIntent);  
    5. }  
              这里的mIntent = new Intent();Process.myPid()方法可以获取当前进程的ID号。
           1.2.2 DownLoadService接到启动的命令之后,执行onCreate()方法,并在其中开启timer计数模拟下载。

    [java] view plaincopy
    1. @Override  
    2. public void onCreate() {  
    3.     super.onCreate();  
    4.     Log.i(TAG, "DownLoadService.onCreate()...pid: "+Process.myPid());  
    5.     intent = new Intent("com.seven.broadcast");  
    6.     mTimer = new Timer();  
    7.     mTimer.schedule(new MyTimerTask(), 0 , TIME * 1000);  
    8. }  
              这里的intent是Server端向Client端传送数据用的,使用的action是”com.seven.broadcast”,Client端只有註册了相应action才能够接收到Server端的广播,并解析其中的内容。Process.myPid()是获取当前进程的ID。
            1.2.3 在Server端的timer计数其中发送广播,告知Client端目前下载进度。

    [java] view plaincopy
    1. class MyTimerTask extends TimerTask{  
    2.     @Override  
    3.     public void run() {  
    4.         if(i==100){  
    5.             i=0;  
    6.         }  
    7.         intent.putExtra("CurrentLoading", i);  
    8.         sendBroadcast(intent);  
    9.         i++;  
    10.         Log.e(TAG, "i= "+i);  
    11.     }  
    12. }  
              通过intent.putExtra(key,value);设置intent的值,然后通过sendBroadcast(intent)2方法,将广播发送出去。

           1.2.4 在Client端通过匿名内部类的方式实例化BroadcastReceiver并覆写其中的onReceive()方法。

    [java] view plaincopy
    1. BroadcastReceiver receiver = new BroadcastReceiver() {  
    2.     @Override  
    3.     public void onReceive(Context context, Intent intent) {  
    4.         if(MYACTION.equals(intent.getAction())){  
    5.             Log.i(TAG, "get the broadcast from DownLoadService...");  
    6.             curLoad = intent.getIntExtra("CurrentLoading", ERROR);  
    7.             mHandler.sendMessage(mHandler.obtainMessage());  
    8.         }  
    9.     }  
    10. };  
              在onReceive()方法中,判断是否为Server端发送的广播,如果是则对广播中携带的intent数据进行解包处理。这裡也可以单独写一个类继承自BroadcastReceiver,在其中覆写onReceive()方法,在Client端中实例化其对象,同样可以达到相应的效果,这样做可以为后面实现静态注册广播。
            1.2.5 更新主介面下载进度。

    [java] view plaincopy
    1. Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         Log.i(TAG, "current loading: "+curLoad);  
    6.         if(curLoad<0||curLoad>100){  
    7.             Log.e(TAG, "ERROR: "+curLoad);  
    8.             return;  
    9.         }  
    10.         mProgressBar.setProgress(curLoad);  
    11.         mTextView.setText(curLoad+"%");  
    12.     }  
    13. };  
                 这里对获取到的进度进行了一次判断,如果获取到的值没有异常,那么将会显示到界面,并更新进度条的进度,如果异常则返回。
             1.2.6 一定要对Broadcast进行注册和取消注册。只有注册之后相应的broadcast之后才能接收到广播注册方法有两种。
             动态注册/取消注册:

    [java] view plaincopy
    1. @Override  
    2. protected void onResume() {  
    3.     super.onResume();  
    4.     Log.i(TAG, "register the broadcast receiver...");  
    5.     IntentFilter filter = new IntentFilter();  
    6.     filter.addAction(MYACTION);  
    7.     registerReceiver(receiver, filter);  
    8. }  
    9. @Override  
    10. protected void onDestroy() {  
    11.     super.onDestroy();  
    12.     Log.i(TAG, "unregister the broadcast receiver...");  
    13.     unregisterReceiver(receiver);  
    14. }  
               动态註册可以随时註册随时取消。

            静态註册:

    [html] view plaincopy
    1. <receiver android:name="MyBroadcastReceiver">  
    2.     <intent-filter>  
    3.         <action android:name="com.seven.broadcast" />  
    4.     </intent-filter>  
    5. </receiver>  
               注:这里的MyBroadcastReceiver是一个继承自BroadcastReceiver的类。静态注册只要注册了一次那么只要该程序没有被卸载那么该广播将一直有效。

            最后贴出整个AndroidManifest.xml文件

    [html] view plaincopy
    1. <application android:icon="@drawable/icon" android:label="@string/app_name">  
    2.     <activity android:name=".BroadCastService"  
    3.               android:label="@string/app_name">  
    4.         <intent-filter>  
    5.             <action android:name="android.intent.action.MAIN" />  
    6.             <category android:name="android.intent.category.LAUNCHER" />  
    7.         </intent-filter>  
    8.     </activity>  
    9.     <service android:name="DownLoadService" android:process=":remote"/>  
    10. </application>  
              这里的android:process =”:remote”可以使该Service运行在单独进程中,从而可以模拟跨进程通信。

           1.3 小结

           通过广播的方式实现Activity与Service的交互操作简单且容易实现,可以胜任简单级的应用。但缺点也十分明显,发送广播受到系统制约。系统会优先发送系统级广播,在某些特定的情况下,我们自定义的广播可能会延迟。同时在广播接收器中不能处理长耗时操作,否则系统会出现ANR即应用程序无响应。

            2. 共享文件交互

            这里提到的共享文件指的是Activity和Service使用同一个文件来达到传递数据的目的。我们使用SharedPreferences来实现共享,当然也可以使用其它IO方法实现,通过这种方式实现交互时需要注意,对于文件的读写的时候,同一时间只能一方读一方写,不能两方同时写。实现效果如图2.1:

    图2.1

             2.1 实现原理

             Server端将当前下载进度写入共享文件中,Client端通过读取共享文件中的下载进度,并更新到主界面上。

             2.2 实现步骤

             2.2.1 在Client端通过startService()啟动Service。

    [java] view plaincopy
    1. if(startSerBtn==v){  
    2.     Log.i(TAG, "Start Button Clicked.");  
    3.     if(intent!=null){  
    4.     startService(intent);  
    5.     timer.schedule(new MyTimerTask(), 0, TIME * 1000);  
    6.     }  
    7. }  
              这里的intent = new Intent()2只是为了启动Server端。
            2.2.2 Server端收到启动intent之后执行onCreate()方法,并开启timer,模拟下载,以及初始化SharedPreferences对象preferences。

    [java] view plaincopy
    1. @Override  
    2. public void onCreate() {  
    3.     super.onCreate();  
    4.     Log.i(TAG, "DownLoadService.onCreate()...");  
    5.     preferences = getSharedPreferences("CurrentLoading_SharedPs"0);  
    6.     timer = new Timer();  
    7.     timer.schedule(new MyTimerTask(), 0, TIME*1000);  
    8. }  
              通过preferences=getSharedPreferences(String,MODE)2可以在/data/data/com.seven.servicetestdemo/shared_prefs文件夹下建立相应的xml文件。

           2.2.3 开始计数并将下载进度写入shared_prefs文件夹下的xml文件中,内容以键值对的方式保存。

    [java] view plaincopy
    1. class MyTimerTask extends TimerTask{  
    2.     @Override  
    3.     public void run() {  
    4.         setCurrentLoading();  
    5.         if(100==i){  
    6.             i=0;  
    7.         }  
    8.         i++;  
    9.     }         
    10. }     
    11. private void setCurrentLoading() {  
    12.     preferences.edit().putInt("CurrentLoading", i).commit();  
    13. }  
               对於SharedPreferences的使用需要注意一下几点:

            首先,使用sharedPreferences前需要获取文件引用。

            preferences = getSharedPreferences("CurrentLoading_SharedPs", 0);

            其次,使用sharedpreferences写数据方式。

            preferences.edit().putInt("CurrentLoading", i).commit();

            最后,读取数据的方式。

            int couLoad = preferences.getInt("CurrentLoading", 0);

            2.2.4 Client端通过读取/data/data/com.seven.servicetestdemo/shared_prefs文件夹下的xml文件,并取得里面的键值对,从而获取到当前的下载进度,并更新到主界面上。

    [java] view plaincopy
    1. Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         int couLoad = preferences.getInt("CurrentLoading"0);  
    6.         mProgressBar.setProgress(couLoad);  
    7.         currentTv.setText(couLoad+"%");  
    8.     }  
    9.  };  

              2.3 小结

            因為方法简单,因此就不贴出AndroidManifest.xml文件了。对於这种方式实现Activity与Service的交互,可以说很方便,就像使用管道,一个往裡写,一个往外读。但这种方式也有缺陷,写入数据较为复杂以及数据量较大时,就有可能导致写入与读数据出不一致的错误。同时因为经过了一个中转站,这种操作将更耗时。

            3. Messenger交互(信使交互)

            Messenger翻译过来指的是信使,它引用了一个Handler对象,别人能够向它发送消息(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message通信,在服务端使用Handler创建一个 Messenger,客户端只要获得这个服务端的Messenger对象就可以与服务端通信了。也就是说我们可以把Messenger当做Client端与Server端的传话筒,这样就可以沟通交流了。实现效果如图3.1:

    图3.1

            3.1 实现原理

            在Server端与Client端之间通过一个Messenger对象来传递消息,该对象类似于信息中转站,所有信息通过该对象携带。

            3.2 Messenger的一般用法

            (1). 在Server端创建信使对象。

                   mMessenger = new Messenger(mHandler)

            (2). Client端使用bindService()绑定Server端。

            (3). Server端的onBind()方法返回一个binder对象。

                   return mMessenger.getBinder();

            (4). Client端使用返回的binder对象得到Server端信使。

    [java] view plaincopy
    1. public void onServiceConnected(ComponentName name, IBinder service) {    
    2.               rMessenger = new Messenger(service);        
    3.              ......  
    4.  }  
              这里虽然是new了一个Messenger,但我们查看它的实现

    [java] view plaincopy
    1. public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target);  }   
               发现它的mTarget是通过AIDL得到的,实际上就是远程创建的那个。

            (5). Client端可以使用这个Server端的信使对象向Server端发送消息。
                   rMessenger.send(msg);

            这样Server端的Handler对象就能收到消息了,然后可以在其handlerMessage(Message msg)方法中进行处理。经过这5个步骤之后只有Client端向Server端发送消息,这样的消息传递是单向的,那么如何实现消息的双向传递呢?

            首先需要在第5步做修改,在send(msg)前通过msm.replyTo = mMessenger将Client端自己的信使设置到消息中,这样Server端接收到消息时同时也得到了Client端的信使对象,然后Server端也可以通过使用得到的Client端的信使对象来项Client端发送消息 cMessenger = msg.replyTo2  cMessenger.send(message);

           这样即完成了从Server端向Client端发送消息的功能,这样Client端可以在自己的Handler对象的handlerMessage()方法中接收服务端发送来的message进行处理。

            3.3 实现步骤

            3.3.1 创建并初始化Server端的信使对象。

    [java] view plaincopy
    1. private Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         switch (msg.what) {  
    6.         case TEST:  
    7.             Log.e(TAG, "Get Message from MainActivity.");  
    8.             cMessenger = msg.replyTo;  
    9.             mTimer.schedule(new MyTimerTask(), 1000,TIME * 1000);  
    10.             break;  
    11.             default:  
    12.                 break;  
    13.             }  
    14.         }         
    15. };  
    16. //It's the messenger of server  
    17. private Messenger mMessenger = new Messenger(mHandler);  

              3.3.2 在Client端使用bindService()方法绑定Server端。

    [java] view plaincopy
    1. private void doBindService(){  
    2.         Log.i(TAG, "doBindService()...");  
    3.     mIsBind = bindService(intent, serConn, BIND_AUTO_CREATE);//if bind success return true  
    4.         Log.e(TAG, "Is bind: "+mIsBind);  
    5. }  

              3.3.3 在Server端的onBind()方法中返回一个binder对象。

    [java] view plaincopy
    1. @Override  
    2. public IBinder onBind(Intent intent) {  
    3.     Log.i(TAG, "MessengerService.onBind()...");  
    4.     return mMessenger.getBinder();  
    5. }  
              这裡的mMessenger就是Server端的信使对象。

            3.3.4 Client端使用ServiceConnected()方法来获取Server端的信使对象。

    [java] view plaincopy
    1. private ServiceConnection serConn = new ServiceConnection() {     
    2.     @Override  
    3.     public void onServiceDisconnected(ComponentName name) {  
    4.         Log.i(TAG, "onServiceDisconnected()...");  
    5.         rMessenger = null;  
    6.     }         
    7.     @Override  
    8.     public void onServiceConnected(ComponentName name, IBinder service) {  
    9.         Log.i(TAG, "onServiceConnected()...");  
    10.     rMessenger = new Messenger(service);//get the object of remote service  
    11.     mMessenger = new Messenger(mHandler);//initial the object of local service  
    12.     sendMessage();  
    13.     }  
    14. };  
               获取Server端的信使对象的同时,也初始化Client端的自己的信使对象,并且通过sendMessage()方法发送消息给Server端,表示可以开始下载了。

            3.3.5 Client端使用获取到的rMessenger来发送消息给Server端,同时将Client端的信使封装到消息中,一并发送给Server端。

    [java] view plaincopy
    1. private void sendMessage() {  
    2.     Message msg = Message.obtain(null, MessengerService.TEST);//MessengerService.TEST=0  
    3.     msg.replyTo = mMessenger;  
    4.     try {  
    5.         rMessenger.send(msg);  
    6.     } catch (RemoteException e) {  
    7.         e.printStackTrace();  
    8.     }  
    9. }  
               这里的MessengerService.TEST為Server端里的一个静态常量。Msg.replyTo=mMessenger;表示发送给Server端的信息里携带Client端的信使。

            3.3.6 Server端获取Client端发送的消息并得到Client端的信使对象。

    [java] view plaincopy
    1. private Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         switch (msg.what) {  
    6.         case TEST:  
    7.             Log.e(TAG, "Get Message from MainActivity.");  
    8.             cMessenger = msg.replyTo;//get the messenger of client  
    9.             mTimer.schedule(new MyTimerTask(), 1000,TIME * 1000);  
    10.             break;  
    11.         default:  
    12.             break;  
    13.         }  
    14.     }  
    15. };  
               在接收到Client端的信息之后,Server端开啟timer模拟下载,并接收Client端的信使对象。

            3.3.7 Server端向Client端发送数据。

    [java] view plaincopy
    1. class MyTimerTask extends TimerTask {  
    2.     @Override  
    3.     public void run() {  
    4.         if (i == 100) {  
    5.             i = 0;  
    6.         }  
    7.         try {  
    8.             //send the message to the client  
    9.         Message message = Message.obtain(null, MessengerService.TEST,i, 0);  
    10.             cMessenger.send(message);  
    11.         } catch (RemoteException e) {  
    12.                 e.printStackTrace();  
    13.         }  
    14.             i++;  
    15.     }  
    16. }  
              直接使用接收到的Client端的信使对象来发送当前下载进度给Client端。

            3.3.8 Client端接收来自Server端的数据。


    [java] view plaincopy
    1. private Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         switch (msg.what) {  
    6.         case MessengerService.TEST:  
    7.             Log.e(TAG, "Get Message From MessengerService. i= "+msg.arg1);  
    8.             int curLoad = msg.arg1;  
    9.             mTextView.setText(curLoad+"%");  
    10.             mProgressBar.setProgress(curLoad);  
    11.             break;  
    12.         default:  
    13.             break;  
    14.         }  
    15.     }  
    16. };  
               Client端的接收和Server端的接收狠类似。接收到Server端传过来的数据之后进行介面更新,以及下载进度更新。

            以下是AndroidManifest.xml文件:

    [html] view plaincopy
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    3.       package="com.seven.messengerservicedemo"  
    4.       android:versionCode="1"  
    5.       android:versionName="1.0">  
    6.     <uses-sdk android:minSdkVersion="10" />  
    7.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
    8.         <activity android:name=".MainActivity"  
    9.                   android:label="@string/app_name">  
    10.             <intent-filter>  
    11.                 <action android:name="android.intent.action.MAIN" />  
    12.                 <category android:name="android.intent.category.LAUNCHER" />  
    13.             </intent-filter>  
    14.         </activity>  
    15.     <service android:name="MessengerService">  
    16.         <intent-filter>  
    17.     <action ndroid:name="com.seven.messagerservice.MessengerService" />  
    18.         </intent-filter>  
    19.     </service>  
    20. </application>  
    21. </manifest>  
               这里在Service的註册中加入了过滤动作,只有相匹配的action才能启动相应的Service。

            3.4 小结

            通过Messenger来实现Activity和Service的交互,稍微深入一点我们就可以知道,其实Messenger也是通过AIDL来实现的。对於前两种实现方式,Messenger方式总体上来讲也是比较容易理解的,这就和平时使用Handler和Thread通信一个道理。

            4. 自定义接口交互

            何谓自定义接口呢,其实就是我们自己通过接口的实现来达到Activity与Service交互的目的,我们通过在Activity和Service之间架设一座桥樑,从而达到数据交互的目的,而这种实现方式和AIDL非常类似(后文会说到)。实现效果如图4.1:

    图4.1

            4.1 实现原理

            自定义一个接口,该接口中有一个获取当前下载进度的空方法。Server端用一个类继承自Binder并实现该接口,覆写了其中获取当前下载进度的方法。Client端通过ServiceConnection获取到该类的对象,从而能够使用该获取当前下载进度的方法,最终实现实时交互。

            4.2 实现步骤

            4.2.1 新建一个Interface,并在其中创建一个用于获取当前下载进度的的空方法getCurrentLoad()。

    [java] view plaincopy
    1. package com.seven.servicetestdemo;  
    2.   
    3. public interface ICountService {  
    4.     public int getCurrentLoad();  
    5. }  

            4.2.2 新建Server端DownService实现ICountService并在其中通过一个内部类ServiceBinder继承自Binder并实现ICoutService接口。

    [java] view plaincopy
    1. public class DownLoadService extends Service implements ICountService{  
    2. private ServiceBinder serviceBinder = new ServiceBinder();    
    3. public class ServiceBinder extends Binder implements ICountService{  
    4.     @Override  
    5.     public int getCurrentLoad() {  
    6.         Log.i(TAG, "ServiceBinder getCurrentLoad()... i=:"+i);  
    7.         return i;  
    8.     }     
    9. }  
    10. @Override  
    11. public int getCurrentLoad() {  
    12.     return 0;  
    13. }  
    14. }  
              在Server端中,实现获取下载进度的空方法getCurrentLoad();这是Eclipse自动生成的,重点不在这裡。我们需要在ServiceBinder类中覆写getCurrentLoad()方法,这裡我们返回当前的下载进度i。

           4.2.3 Client端使用bindService()绑定Server端。

    [java] view plaincopy
    1. if (startSerBtn == v) {  
    2.     Log.i(TAG, "Start Button Clicked.");  
    3.     bindService(intent, serConn, BIND_AUTO_CREATE);  
    4.     timer.schedule(new MyTimerTask(), 1000, TIME * 1000);//这里一定要延迟一下再开始获取数据,不然会报空指针异常  
    5. }  
               在Client端绑定Server端的同时,延迟1s开始获取下载进度。其中的intent = new Intent(“com.seven.test”)2com.seven.test该字符串要与在AndroidManifest.xml中申明的一致。

           4.2.4 Server端返回binder对象。

    [java] view plaincopy
    1. @Override  
    2. public IBinder onBind(Intent intent) {  
    3.     Log.i(TAG, "DownLoadService.onBind()...");  
    4.     return serviceBinder;  
    5. }  
               这里的serviceBinder因为继承了Binder因此也是Binder对象。

            4.2.5 Client端通过ServiceConnection来获取Server端的binder对象。

    [java] view plaincopy
    1. private ServiceConnection serConn = new ServiceConnection() {  
    2. @Override  
    3.     public void onServiceDisconnected(ComponentName name) {  
    4.         iCountService = null;  
    5.     }         
    6.     @Override  
    7.     public void onServiceConnected(ComponentName name, IBinder service) {  
    8.         Log.i(TAG, "onServiceConnected()...");  
    9.         iCountService = (ICountService)service;  
    10.     }  
    11. };  
              获取的过程是在bindService()过程中完成的,这里的iCountService是接口ICountService的对象,在这里得到实例化。

            4.2.6 在绑定完成之后,Server端会开启下载,在实际情况中Server端会开启独立线程用于下载,这里用i++来代替。

    [java] view plaincopy
    1. @Override  
    2. public void onCreate() {  
    3.     super.onCreate();  
    4.     Log.i(TAG, "DownLoadService.onCreate()...");  
    5.     timer = new Timer();  
    6.     timer.schedule(new MyTimerTask(), 0, TIME*1000);  
    7. }  
    8. class MyTimerTask extends TimerTask{  
    9.     @Override  
    10.     public void run() {  
    11.         if(100==i){  
    12.             i=0;  
    13.         }  
    14.         i++;  
    15.     }  
    16. }  
              bindService()方法执行之后会调用DownLoadService中的onCreate()方法,在其onCreate()方法中开启timer使得i++。

            4.2.7 Server端已经开启了下载,那么Client端需要及时获取下载进度并在主界面上更新。

    [java] view plaincopy
    1. Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         Log.i(TAG, "handleMessage...");  
    6.         int curLoad = iCountService.getCurrentLoad();  
    7.         mProgressBar.setProgress(curLoad);  
    8.         currentTv.setText(curLoad+"%");  
    9.     }  
    10.  };  
    11. class MyTimerTask extends TimerTask{  
    12.     @Override  
    13.     public void run() {  
    14.         mHandler.sendMessage(mHandler.obtainMessage());  
    15.     }  
    16. }  
               Client端的Timer在bindService()完成之后1秒再开始获取下载进度,获取方法是直接通过int curLoad = iCountService.getCurrentLoad();这里的getCurrentLoad()方法是DownLoadService内部类ServiceBinder中的方法。Client端将获取到的下载进度更新到介面上并更新进度条。

            4.3 小结

            通过上面的例子可以知道,这种方法简单实用,扩展性强,但其也有一些缺点,比如需要延迟一些再开始获取Server端的数据,从而无法完全实现从零开始同步更新。综其所述,通过自定义接口实现Activity与Service交互的方法还是比较实用的。适用於同进程中通信,不能进行跨进程通信。

            5. AIDL交互

            什么是AIDL?

            AIDL是Android Interface Definition Language的首字母缩写, 也就是Android接口定义语言。提及AIDL就不得不说下Android的服务,Android 支持两种服务类型的服务即本地服务和远程服务。

            本地服务无法供在设备上运行的其他应用程序访问,也就是说只能该应用程序内部调用,比如某些应用程序中的下载类服务,这些服务只能由内部调用。而对于远程服务,除了可以由本应用程序调用,还可以允许其他应用程序访问。远程服务一般通过AIDL来实现,可以进行进程间通信,这种服务也就是远程服务。

            本地服务与远程服务还是有一些重要的区别。具体来讲,如果服务完全只供同一进程中的组件使用(运行后台任务),客户端一边通过调用 Context.startService()来启动该服务。这种类型的服务为本地服务,它的一般用途是后台执行长耗时操作。而远程服务一般通过bindService()方法启动,主要为不同进程间通信。我们也将远程服务称为AIDL支持服务,因为客户端使用 AIDL 与服务通信。Android中对于远程服务有多种叫法:远程服务、AIDL服务、外部服务和RPC服务。

            5.1 AIDL实现流程图

    图5.1

            这属于代理/存根结构,通过这张AIDL的流程图,很容易发现Android实现IPC其实是在原来的C/S框架上加入了代理/存根结构。

            比如,你到自动取款机上去取款。那么你就是客户(Client),取款机就是你的代理(Proxy);你不会在乎钱具体放在那里,你只想将你的钱从取款机中取出来。你同银行之间的操作完全是取款机代理实现。你的取款请求通过取款机传到另一边,即银行的服务器(Server)。它也没有必要知道你在哪儿取钱,它所关心的是你的身份和你取款多少。当它确认你的权限,就进行相应的操作,返回操作结果给取款机,取款机根据服务器返回结果,从保险柜里取出相应数量的钱给你。你取出卡后,操作完成。取款机不是直接同服务器连接的,他们之间还有一个“存根(Stub)”,取款机与存根通信,服务器与存根通信,从某种意义上说存根就是服务器的代理。实现效果如图5.2:

    图5.2

            5.3 实现原理

            AIDL属于Android的IPC机制,常用于跨进程通信,主要实现原理基于底层Binder机制。

            5.4 实现步骤

            5.4.1 建立工程。按照图5.3和图5.4建立AIDLServer端以及AIDLClient端。在AIDLServer端中只有一个服务程序,没有主界面,其主要功能就是负责下载。AIDLClient端从AIDLServer端获取当前下载进度(注:AIDLServer端和AIDLClient端是不同的两个APK,在模拟本例的时候,需要先在模拟器上安装AIDLServer编译出来的APK,安装方法可以直接在模拟器上运行一次,可以通过adb install your.apk 来安装)。

    图5.3

            AIDLServer端中新建了一个ICountService.aidl的文件,该文件内容如下:

    [plain] view plaincopy
    1. package com.seven.aidlserver;  
    2.   
    3. interface ICountService{  
    4.     int getCount();  
    5. }  

              aidl文件的书写规范如下:

            (1). Android支持String和CharSequence(以及Java的基本数据类型);

            (2). 如果需要在aidl中使用其它aidl接口类型,需要import,即使是在相同包结构下;

            (3). Android允许传递实现Parcelable接口的类,需要import;

            (4). Android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者前面三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import;

            (5). 非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。

    图5.4

             AIDLClient端需要将AIDLServer端的ICountService.aidl文件复製过去,这裡为了方便,新建了一个和Server端同名的包,并将ICountService.aidl放与其中。

             5.4.2 我们在Server端建立好ICoutService.aidl文件之后,Eclipse会在/gen/com.seven.aidlserver/目录下自动生成ICountService.java文件。该文件由Eclipse自动生成,请勿随便修改,后文我们需引用到的内容如下:

    [java] view plaincopy
    1. public static com.seven.aidlserver.ICountService asInterface(android.os.IBinder obj) {  
    2.     if ((obj == null)) {  
    3.         return null;  
    4.     }  
    5. android.os.IInterface iin = (android.os.IInterface) obj.queryLocalInterface(DESCRIPTOR);  
    6.     if (((iin != null) && (iin instanceof com.seven.aidlserver.ICountService))) {  
    7.         return ((com.seven.aidlserver.ICountService) iin);  
    8.     }  
    9.     return new com.seven.aidlserver.ICountService.Stub.Proxy(obj);  
    10. }  

              5.4.3 在Server端新建一个内部类继承自ICountService.Stub并覆写其中的getCount()方法,以及实例化该类的一个对象serviceBinder。

    [java] view plaincopy
    1. private AIDLServerBinder serviceBinder = new AIDLServerBinder();  
    2. class AIDLServerBinder extends ICountService.Stub{  
    3.     @Override  
    4.     public int getCount() throws RemoteException {  
    5.         return i;  
    6.     }  
    7. }  
             这里与前面提到的“通过接口实现交互”非常类似。

            5.4.4 在Server端的onBind()方法中,返回前面的serviceBinder对象。

    [java] view plaincopy
    1. @Override  
    2. public IBinder onBind(Intent intent) {  
    3.     Log.i(TAG, "AIDLServer.onBind()...");  
    4.     return serviceBinder;  
    5. }  

             5.4.5 在Server端的onCreate()方法中,开启timer,模拟下载。在Client端通过bindService()绑定Server端的时候,会首先执行Server端的onCreate()方法。


    [java] view plaincopy
    1. @Override  
    2. public void onCreate() {  
    3.     super.onCreate();  
    4.     Log.i(TAG, "AIDLServer.onCreate()...");  
    5.     mTimer = new Timer();  
    6.     mTimer.schedule(new MyTimerTask(), 0,TIME * 1000);  
    7. }  
    8. class MyTimerTask extends TimerTask{  
    9.     @Override  
    10.     public void run() {  
    11.         if(i==100){  
    12.             i=0;  
    13.         }  
    14.         i++;  
    15.     }  
    16. }  

              5.4.6 Client端通过bindService()绑定Server端。


    [java] view plaincopy
    1. if(startBtn==v){  
    2.     Log.i(TAG, "start button click.");  
    3.     mIsBind = bindService(intent, serConn, BIND_AUTO_CREATE);  
    4.     mTimer.schedule(new MyTimerTask(), 1000 ,TIME * 1000);  
    5. }  
              这里的intent = new Intent(“com.seven.aidlserver”);这里跟Server端注册Service时过滤的要一致,也就是说只有发出相同的action才会启动该Service。同时开启了一个timer用于获取下载进度。
            5.4.7 Client端通过ServiceConnection来获取Server端的binder对象。

    [java] view plaincopy
    1. private ServiceConnection serConn = new ServiceConnection() {         
    2.     @Override  
    3.     public void onServiceDisconnected(ComponentName name) {  
    4.         iCountService = null;  
    5.     }         
    6.     @Override  
    7.     public void onServiceConnected(ComponentName name, IBinder service) {  
    8.         Log.i(TAG, "AIDLClient.onServiceConnected()...");  
    9.         iCountService = ICountService.Stub.asInterface(service);  
    10.     }  
    11. };  
              这里的iCountService对象实际上就是ICountService的对象在此实例化。

            5.4.8 获取当前下载进度并更新到界面上。

    [java] view plaincopy
    1. Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         try {  
    6.             int count =  iCountService.getCount();  
    7.             mTextView.setText(count+"%");  
    8.             mProgressBar.setProgress(count);  
    9.         } catch (RemoteException e) {  
    10.             e.printStackTrace();  
    11.         }  
    12.     }  
    13. };  
              通过更新介面上的进度条,可以狠容易的后去当前下载进度。因為AIDLServer端只是一个继承自Service的服务,因此就不贴出其AndroidManifest.xml文件了。

            5.5 小结

            AIDL在Android中是进程间通信常用的方式,可能使用较為复杂,但效率高,扩展性好。同时很多系统服务就是以这种方式完成与应用程序通信的。

            本文通过五个例子,分别介绍了五种与Service交互的方法,这些方法有的简单,有的可能要复杂一些。在这里只是做为对Servie的一些总结。后文附上源码下载链接,不需要积分的哦。:D

            源码下载

            所有源码均在Ubuntu 10.04 Eclipse-Indigo下实验通过 模拟器采用的是2.3的镜像

    展开全文
  • 上一篇文章 简述了Service的一些基础知识以及Service和Thread的简单区别,本文将着重讲解与Service交互的五种基本方式:广播交互、共享文件交互、Mssenger(信使)交互、自定义接口交互、AIDL交互。  1. 广播交互...
    上一篇文章 简述了Service的一些基础知识以及Service和Thread的简单区别,本文将着重讲解与Service交互的五种基本方式:广播交互、共享文件交互、Mssenger(信使)交互、自定义接口交互、AIDL交互。
    

           1. 广播交互

           提到Activity与Service的交互,可能狠多人首先想到的就是BroadCast——广播。在Android中,广播是系统提供的一种很好的交互方式。比如:在电池电量过低,开机完成等情况下,系统都会发出相应的系统广播,我们的应用程序只需要注册相应的广播接收器,就可以接收到这些系统的广播。同时,我们也可以定义自己的广播,这样在不同的Activity、Service以及应用程序之间,就可以通过广播来实现交互。我们通过模拟应用程序后台下载的情况来分析Service与Activity的交互方式。实现效果如图1.1:

    图1.1

            当我们点击StartService按钮之后,界面上的进度条将会每隔一秒加1。因为是模拟下载,因此下载动作我们在Service中通过一个Timer定时器来实现,在Timer中对一个整型数据i进行自加(i++),然后Client端获取Server端的i值并显示在界面上,从而达到模拟的目的。

            1.1. 实现原理

            Server端将目前的下载进度,通过广播的方式发送出来,Client端注册此广播的监听器,当获取到该广播后,将广播中当前的下载进度解析出来并更新到界面上。

            1.2. 实现步骤

            1.2.1 在Client端中通过startService()啟动Service。

    [java] view plaincopy
    1. if(v == startBtn){  
    2.     Log.i(TAG, "start button clicked...pid: "+Process.myPid());  
    3.     mIntent.setClass(BroadCastService.this, DownLoadService.class);  
    4.     startService(mIntent);  
    5. }  
              这里的mIntent = new Intent();Process.myPid()方法可以获取当前进程的ID号。
           1.2.2 DownLoadService接到启动的命令之后,执行onCreate()方法,并在其中开启timer计数模拟下载。

    [java] view plaincopy
    1. @Override  
    2. public void onCreate() {  
    3.     super.onCreate();  
    4.     Log.i(TAG, "DownLoadService.onCreate()...pid: "+Process.myPid());  
    5.     intent = new Intent("com.seven.broadcast");  
    6.     mTimer = new Timer();  
    7.     mTimer.schedule(new MyTimerTask(), 0 , TIME * 1000);  
    8. }  
              这里的intent是Server端向Client端传送数据用的,使用的action是”com.seven.broadcast”,Client端只有註册了相应action才能够接收到Server端的广播,并解析其中的内容。Process.myPid()是获取当前进程的ID。
            1.2.3 在Server端的timer计数其中发送广播,告知Client端目前下载进度。

    [java] view plaincopy
    1. class MyTimerTask extends TimerTask{  
    2.     @Override  
    3.     public void run() {  
    4.         if(i==100){  
    5.             i=0;  
    6.         }  
    7.         intent.putExtra("CurrentLoading", i);  
    8.         sendBroadcast(intent);  
    9.         i++;  
    10.         Log.e(TAG, "i= "+i);  
    11.     }  
    12. }  
              通过intent.putExtra(key,value);设置intent的值,然后通过sendBroadcast(intent)2方法,将广播发送出去。

           1.2.4 在Client端通过匿名内部类的方式实例化BroadcastReceiver并覆写其中的onReceive()方法。

    [java] view plaincopy
    1. BroadcastReceiver receiver = new BroadcastReceiver() {  
    2.     @Override  
    3.     public void onReceive(Context context, Intent intent) {  
    4.         if(MYACTION.equals(intent.getAction())){  
    5.             Log.i(TAG, "get the broadcast from DownLoadService...");  
    6.             curLoad = intent.getIntExtra("CurrentLoading", ERROR);  
    7.             mHandler.sendMessage(mHandler.obtainMessage());  
    8.         }  
    9.     }  
    10. };  
              在onReceive()方法中,判断是否为Server端发送的广播,如果是则对广播中携带的intent数据进行解包处理。这裡也可以单独写一个类继承自BroadcastReceiver,在其中覆写onReceive()方法,在Client端中实例化其对象,同样可以达到相应的效果,这样做可以为后面实现静态注册广播。
            1.2.5 更新主介面下载进度。

    [java] view plaincopy
    1. Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         Log.i(TAG, "current loading: "+curLoad);  
    6.         if(curLoad<0||curLoad>100){  
    7.             Log.e(TAG, "ERROR: "+curLoad);  
    8.             return;  
    9.         }  
    10.         mProgressBar.setProgress(curLoad);  
    11.         mTextView.setText(curLoad+"%");  
    12.     }  
    13. };  
                 这里对获取到的进度进行了一次判断,如果获取到的值没有异常,那么将会显示到界面,并更新进度条的进度,如果异常则返回。
             1.2.6 一定要对Broadcast进行注册和取消注册。只有注册之后相应的broadcast之后才能接收到广播注册方法有两种。
             动态注册/取消注册:

    [java] view plaincopy
    1. @Override  
    2. protected void onResume() {  
    3.     super.onResume();  
    4.     Log.i(TAG, "register the broadcast receiver...");  
    5.     IntentFilter filter = new IntentFilter();  
    6.     filter.addAction(MYACTION);  
    7.     registerReceiver(receiver, filter);  
    8. }  
    9. @Override  
    10. protected void onDestroy() {  
    11.     super.onDestroy();  
    12.     Log.i(TAG, "unregister the broadcast receiver...");  
    13.     unregisterReceiver(receiver);  
    14. }  
               动态註册可以随时註册随时取消。

            静态註册:

    [html] view plaincopy
    1. <receiver android:name="MyBroadcastReceiver">  
    2.     <intent-filter>  
    3.         <action android:name="com.seven.broadcast" />  
    4.     </intent-filter>  
    5. </receiver>  
               注:这里的MyBroadcastReceiver是一个继承自BroadcastReceiver的类。静态注册只要注册了一次那么只要该程序没有被卸载那么该广播将一直有效。

            最后贴出整个AndroidManifest.xml文件

    [html] view plaincopy
    1. <application android:icon="@drawable/icon" android:label="@string/app_name">  
    2.     <activity android:name=".BroadCastService"  
    3.               android:label="@string/app_name">  
    4.         <intent-filter>  
    5.             <action android:name="android.intent.action.MAIN" />  
    6.             <category android:name="android.intent.category.LAUNCHER" />  
    7.         </intent-filter>  
    8.     </activity>  
    9.     <service android:name="DownLoadService" android:process=":remote"/>  
    10. </application>  
              这里的android:process =”:remote”可以使该Service运行在单独进程中,从而可以模拟跨进程通信。

           1.3 小结

           通过广播的方式实现Activity与Service的交互操作简单且容易实现,可以胜任简单级的应用。但缺点也十分明显,发送广播受到系统制约。系统会优先发送系统级广播,在某些特定的情况下,我们自定义的广播可能会延迟。同时在广播接收器中不能处理长耗时操作,否则系统会出现ANR即应用程序无响应。

            2. 共享文件交互

            这里提到的共享文件指的是Activity和Service使用同一个文件来达到传递数据的目的。我们使用SharedPreferences来实现共享,当然也可以使用其它IO方法实现,通过这种方式实现交互时需要注意,对于文件的读写的时候,同一时间只能一方读一方写,不能两方同时写。实现效果如图2.1:

    图2.1

             2.1 实现原理

             Server端将当前下载进度写入共享文件中,Client端通过读取共享文件中的下载进度,并更新到主界面上。

             2.2 实现步骤

             2.2.1 在Client端通过startService()啟动Service。

    [java] view plaincopy
    1. if(startSerBtn==v){  
    2.     Log.i(TAG, "Start Button Clicked.");  
    3.     if(intent!=null){  
    4.     startService(intent);  
    5.     timer.schedule(new MyTimerTask(), 0, TIME * 1000);  
    6.     }  
    7. }  
              这里的intent = new Intent()2只是为了启动Server端。
            2.2.2 Server端收到启动intent之后执行onCreate()方法,并开启timer,模拟下载,以及初始化SharedPreferences对象preferences。

    [java] view plaincopy
    1. @Override  
    2. public void onCreate() {  
    3.     super.onCreate();  
    4.     Log.i(TAG, "DownLoadService.onCreate()...");  
    5.     preferences = getSharedPreferences("CurrentLoading_SharedPs"0);  
    6.     timer = new Timer();  
    7.     timer.schedule(new MyTimerTask(), 0, TIME*1000);  
    8. }  
              通过preferences=getSharedPreferences(String,MODE)2可以在/data/data/com.seven.servicetestdemo/shared_prefs文件夹下建立相应的xml文件。

           2.2.3 开始计数并将下载进度写入shared_prefs文件夹下的xml文件中,内容以键值对的方式保存。

    [java] view plaincopy
    1. class MyTimerTask extends TimerTask{  
    2.     @Override  
    3.     public void run() {  
    4.         setCurrentLoading();  
    5.         if(100==i){  
    6.             i=0;  
    7.         }  
    8.         i++;  
    9.     }         
    10. }     
    11. private void setCurrentLoading() {  
    12.     preferences.edit().putInt("CurrentLoading", i).commit();  
    13. }  
               对於SharedPreferences的使用需要注意一下几点:

            首先,使用sharedPreferences前需要获取文件引用。

            preferences = getSharedPreferences("CurrentLoading_SharedPs", 0);

            其次,使用sharedpreferences写数据方式。

            preferences.edit().putInt("CurrentLoading", i).commit();

            最后,读取数据的方式。

            int couLoad = preferences.getInt("CurrentLoading", 0);

            2.2.4 Client端通过读取/data/data/com.seven.servicetestdemo/shared_prefs文件夹下的xml文件,并取得里面的键值对,从而获取到当前的下载进度,并更新到主界面上。

    [java] view plaincopy
    1. Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         int couLoad = preferences.getInt("CurrentLoading"0);  
    6.         mProgressBar.setProgress(couLoad);  
    7.         currentTv.setText(couLoad+"%");  
    8.     }  
    9.  };  

              2.3 小结

            因為方法简单,因此就不贴出AndroidManifest.xml文件了。对於这种方式实现Activity与Service的交互,可以说很方便,就像使用管道,一个往裡写,一个往外读。但这种方式也有缺陷,写入数据较为复杂以及数据量较大时,就有可能导致写入与读数据出不一致的错误。同时因为经过了一个中转站,这种操作将更耗时。

            3. Messenger交互(信使交互)

            Messenger翻译过来指的是信使,它引用了一个Handler对象,别人能够向它发送消息(使用mMessenger.send(Message msg)方法)。该类允许跨进程间基于Message通信,在服务端使用Handler创建一个 Messenger,客户端只要获得这个服务端的Messenger对象就可以与服务端通信了。也就是说我们可以把Messenger当做Client端与Server端的传话筒,这样就可以沟通交流了。实现效果如图3.1:

    图3.1

            3.1 实现原理

            在Server端与Client端之间通过一个Messenger对象来传递消息,该对象类似于信息中转站,所有信息通过该对象携带。

            3.2 Messenger的一般用法

            (1). 在Server端创建信使对象。

                   mMessenger = new Messenger(mHandler)

            (2). Client端使用bindService()绑定Server端。

            (3). Server端的onBind()方法返回一个binder对象。

                   return mMessenger.getBinder();

            (4). Client端使用返回的binder对象得到Server端信使。

    [java] view plaincopy
    1. public void onServiceConnected(ComponentName name, IBinder service) {    
    2.               rMessenger = new Messenger(service);        
    3.              ......  
    4.  }  
              这里虽然是new了一个Messenger,但我们查看它的实现

    [java] view plaincopy
    1. public Messenger(IBinder target) { mTarget = IMessenger.Stub.asInterface(target);  }   
               发现它的mTarget是通过AIDL得到的,实际上就是远程创建的那个。

            (5). Client端可以使用这个Server端的信使对象向Server端发送消息。
                   rMessenger.send(msg);

            这样Server端的Handler对象就能收到消息了,然后可以在其handlerMessage(Message msg)方法中进行处理。经过这5个步骤之后只有Client端向Server端发送消息,这样的消息传递是单向的,那么如何实现消息的双向传递呢?

            首先需要在第5步做修改,在send(msg)前通过msm.replyTo = mMessenger将Client端自己的信使设置到消息中,这样Server端接收到消息时同时也得到了Client端的信使对象,然后Server端也可以通过使用得到的Client端的信使对象来项Client端发送消息 cMessenger = msg.replyTo2  cMessenger.send(message);

           这样即完成了从Server端向Client端发送消息的功能,这样Client端可以在自己的Handler对象的handlerMessage()方法中接收服务端发送来的message进行处理。

            3.3 实现步骤

            3.3.1 创建并初始化Server端的信使对象。

    [java] view plaincopy
    1. private Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         switch (msg.what) {  
    6.         case TEST:  
    7.             Log.e(TAG, "Get Message from MainActivity.");  
    8.             cMessenger = msg.replyTo;  
    9.             mTimer.schedule(new MyTimerTask(), 1000,TIME * 1000);  
    10.             break;  
    11.             default:  
    12.                 break;  
    13.             }  
    14.         }         
    15. };  
    16. //It's the messenger of server  
    17. private Messenger mMessenger = new Messenger(mHandler);  

              3.3.2 在Client端使用bindService()方法绑定Server端。

    [java] view plaincopy
    1. private void doBindService(){  
    2.         Log.i(TAG, "doBindService()...");  
    3.     mIsBind = bindService(intent, serConn, BIND_AUTO_CREATE);//if bind success return true  
    4.         Log.e(TAG, "Is bind: "+mIsBind);  
    5. }  

              3.3.3 在Server端的onBind()方法中返回一个binder对象。

    [java] view plaincopy
    1. @Override  
    2. public IBinder onBind(Intent intent) {  
    3.     Log.i(TAG, "MessengerService.onBind()...");  
    4.     return mMessenger.getBinder();  
    5. }  
              这裡的mMessenger就是Server端的信使对象。

            3.3.4 Client端使用ServiceConnected()方法来获取Server端的信使对象。

    [java] view plaincopy
    1. private ServiceConnection serConn = new ServiceConnection() {     
    2.     @Override  
    3.     public void onServiceDisconnected(ComponentName name) {  
    4.         Log.i(TAG, "onServiceDisconnected()...");  
    5.         rMessenger = null;  
    6.     }         
    7.     @Override  
    8.     public void onServiceConnected(ComponentName name, IBinder service) {  
    9.         Log.i(TAG, "onServiceConnected()...");  
    10.     rMessenger = new Messenger(service);//get the object of remote service  
    11.     mMessenger = new Messenger(mHandler);//initial the object of local service  
    12.     sendMessage();  
    13.     }  
    14. };  
               获取Server端的信使对象的同时,也初始化Client端的自己的信使对象,并且通过sendMessage()方法发送消息给Server端,表示可以开始下载了。

            3.3.5 Client端使用获取到的rMessenger来发送消息给Server端,同时将Client端的信使封装到消息中,一并发送给Server端。

    [java] view plaincopy
    1. private void sendMessage() {  
    2.     Message msg = Message.obtain(null, MessengerService.TEST);//MessengerService.TEST=0  
    3.     msg.replyTo = mMessenger;  
    4.     try {  
    5.         rMessenger.send(msg);  
    6.     } catch (RemoteException e) {  
    7.         e.printStackTrace();  
    8.     }  
    9. }  
               这里的MessengerService.TEST為Server端里的一个静态常量。Msg.replyTo=mMessenger;表示发送给Server端的信息里携带Client端的信使。

            3.3.6 Server端获取Client端发送的消息并得到Client端的信使对象。

    [java] view plaincopy
    1. private Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         switch (msg.what) {  
    6.         case TEST:  
    7.             Log.e(TAG, "Get Message from MainActivity.");  
    8.             cMessenger = msg.replyTo;//get the messenger of client  
    9.             mTimer.schedule(new MyTimerTask(), 1000,TIME * 1000);  
    10.             break;  
    11.         default:  
    12.             break;  
    13.         }  
    14.     }  
    15. };  
               在接收到Client端的信息之后,Server端开啟timer模拟下载,并接收Client端的信使对象。

            3.3.7 Server端向Client端发送数据。

    [java] view plaincopy
    1. class MyTimerTask extends TimerTask {  
    2.     @Override  
    3.     public void run() {  
    4.         if (i == 100) {  
    5.             i = 0;  
    6.         }  
    7.         try {  
    8.             //send the message to the client  
    9.         Message message = Message.obtain(null, MessengerService.TEST,i, 0);  
    10.             cMessenger.send(message);  
    11.         } catch (RemoteException e) {  
    12.                 e.printStackTrace();  
    13.         }  
    14.             i++;  
    15.     }  
    16. }  
              直接使用接收到的Client端的信使对象来发送当前下载进度给Client端。

            3.3.8 Client端接收来自Server端的数据。


    [java] view plaincopy
    1. private Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         switch (msg.what) {  
    6.         case MessengerService.TEST:  
    7.             Log.e(TAG, "Get Message From MessengerService. i= "+msg.arg1);  
    8.             int curLoad = msg.arg1;  
    9.             mTextView.setText(curLoad+"%");  
    10.             mProgressBar.setProgress(curLoad);  
    11.             break;  
    12.         default:  
    13.             break;  
    14.         }  
    15.     }  
    16. };  
               Client端的接收和Server端的接收狠类似。接收到Server端传过来的数据之后进行介面更新,以及下载进度更新。

            以下是AndroidManifest.xml文件:

    [html] view plaincopy
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    3.       package="com.seven.messengerservicedemo"  
    4.       android:versionCode="1"  
    5.       android:versionName="1.0">  
    6.     <uses-sdk android:minSdkVersion="10" />  
    7.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
    8.         <activity android:name=".MainActivity"  
    9.                   android:label="@string/app_name">  
    10.             <intent-filter>  
    11.                 <action android:name="android.intent.action.MAIN" />  
    12.                 <category android:name="android.intent.category.LAUNCHER" />  
    13.             </intent-filter>  
    14.         </activity>  
    15.     <service android:name="MessengerService">  
    16.         <intent-filter>  
    17.     <action ndroid:name="com.seven.messagerservice.MessengerService" />  
    18.         </intent-filter>  
    19.     </service>  
    20. </application>  
    21. </manifest>  
               这里在Service的註册中加入了过滤动作,只有相匹配的action才能启动相应的Service。

            3.4 小结

            通过Messenger来实现Activity和Service的交互,稍微深入一点我们就可以知道,其实Messenger也是通过AIDL来实现的。对於前两种实现方式,Messenger方式总体上来讲也是比较容易理解的,这就和平时使用Handler和Thread通信一个道理。

            4. 自定义接口交互

            何谓自定义接口呢,其实就是我们自己通过接口的实现来达到Activity与Service交互的目的,我们通过在Activity和Service之间架设一座桥樑,从而达到数据交互的目的,而这种实现方式和AIDL非常类似(后文会说到)。实现效果如图4.1:

    图4.1

            4.1 实现原理

            自定义一个接口,该接口中有一个获取当前下载进度的空方法。Server端用一个类继承自Binder并实现该接口,覆写了其中获取当前下载进度的方法。Client端通过ServiceConnection获取到该类的对象,从而能够使用该获取当前下载进度的方法,最终实现实时交互。

            4.2 实现步骤

            4.2.1 新建一个Interface,并在其中创建一个用于获取当前下载进度的的空方法getCurrentLoad()。

    [java] view plaincopy
    1. package com.seven.servicetestdemo;  
    2.   
    3. public interface ICountService {  
    4.     public int getCurrentLoad();  
    5. }  

            4.2.2 新建Server端DownService实现ICountService并在其中通过一个内部类ServiceBinder继承自Binder并实现ICoutService接口。

    [java] view plaincopy
    1. public class DownLoadService extends Service implements ICountService{  
    2. private ServiceBinder serviceBinder = new ServiceBinder();    
    3. public class ServiceBinder extends Binder implements ICountService{  
    4.     @Override  
    5.     public int getCurrentLoad() {  
    6.         Log.i(TAG, "ServiceBinder getCurrentLoad()... i=:"+i);  
    7.         return i;  
    8.     }     
    9. }  
    10. @Override  
    11. public int getCurrentLoad() {  
    12.     return 0;  
    13. }  
    14. }  
              在Server端中,实现获取下载进度的空方法getCurrentLoad();这是Eclipse自动生成的,重点不在这裡。我们需要在ServiceBinder类中覆写getCurrentLoad()方法,这裡我们返回当前的下载进度i。

           4.2.3 Client端使用bindService()绑定Server端。

    [java] view plaincopy
    1. if (startSerBtn == v) {  
    2.     Log.i(TAG, "Start Button Clicked.");  
    3.     bindService(intent, serConn, BIND_AUTO_CREATE);  
    4.     timer.schedule(new MyTimerTask(), 1000, TIME * 1000);//这里一定要延迟一下再开始获取数据,不然会报空指针异常  
    5. }  
               在Client端绑定Server端的同时,延迟1s开始获取下载进度。其中的intent = new Intent(“com.seven.test”)2com.seven.test该字符串要与在AndroidManifest.xml中申明的一致。

           4.2.4 Server端返回binder对象。

    [java] view plaincopy
    1. @Override  
    2. public IBinder onBind(Intent intent) {  
    3.     Log.i(TAG, "DownLoadService.onBind()...");  
    4.     return serviceBinder;  
    5. }  
               这里的serviceBinder因为继承了Binder因此也是Binder对象。

            4.2.5 Client端通过ServiceConnection来获取Server端的binder对象。

    [java] view plaincopy
    1. private ServiceConnection serConn = new ServiceConnection() {  
    2. @Override  
    3.     public void onServiceDisconnected(ComponentName name) {  
    4.         iCountService = null;  
    5.     }         
    6.     @Override  
    7.     public void onServiceConnected(ComponentName name, IBinder service) {  
    8.         Log.i(TAG, "onServiceConnected()...");  
    9.         iCountService = (ICountService)service;  
    10.     }  
    11. };  
              获取的过程是在bindService()过程中完成的,这里的iCountService是接口ICountService的对象,在这里得到实例化。

            4.2.6 在绑定完成之后,Server端会开启下载,在实际情况中Server端会开启独立线程用于下载,这里用i++来代替。

    [java] view plaincopy
    1. @Override  
    2. public void onCreate() {  
    3.     super.onCreate();  
    4.     Log.i(TAG, "DownLoadService.onCreate()...");  
    5.     timer = new Timer();  
    6.     timer.schedule(new MyTimerTask(), 0, TIME*1000);  
    7. }  
    8. class MyTimerTask extends TimerTask{  
    9.     @Override  
    10.     public void run() {  
    11.         if(100==i){  
    12.             i=0;  
    13.         }  
    14.         i++;  
    15.     }  
    16. }  
              bindService()方法执行之后会调用DownLoadService中的onCreate()方法,在其onCreate()方法中开启timer使得i++。

            4.2.7 Server端已经开启了下载,那么Client端需要及时获取下载进度并在主界面上更新。

    [java] view plaincopy
    1. Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         Log.i(TAG, "handleMessage...");  
    6.         int curLoad = iCountService.getCurrentLoad();  
    7.         mProgressBar.setProgress(curLoad);  
    8.         currentTv.setText(curLoad+"%");  
    9.     }  
    10.  };  
    11. class MyTimerTask extends TimerTask{  
    12.     @Override  
    13.     public void run() {  
    14.         mHandler.sendMessage(mHandler.obtainMessage());  
    15.     }  
    16. }  
               Client端的Timer在bindService()完成之后1秒再开始获取下载进度,获取方法是直接通过int curLoad = iCountService.getCurrentLoad();这里的getCurrentLoad()方法是DownLoadService内部类ServiceBinder中的方法。Client端将获取到的下载进度更新到介面上并更新进度条。

            4.3 小结

            通过上面的例子可以知道,这种方法简单实用,扩展性强,但其也有一些缺点,比如需要延迟一些再开始获取Server端的数据,从而无法完全实现从零开始同步更新。综其所述,通过自定义接口实现Activity与Service交互的方法还是比较实用的。适用於同进程中通信,不能进行跨进程通信。

            5. AIDL交互

            什么是AIDL?

            AIDL是Android Interface Definition Language的首字母缩写, 也就是Android接口定义语言。提及AIDL就不得不说下Android的服务,Android 支持两种服务类型的服务即本地服务和远程服务。

            本地服务无法供在设备上运行的其他应用程序访问,也就是说只能该应用程序内部调用,比如某些应用程序中的下载类服务,这些服务只能由内部调用。而对于远程服务,除了可以由本应用程序调用,还可以允许其他应用程序访问。远程服务一般通过AIDL来实现,可以进行进程间通信,这种服务也就是远程服务。

            本地服务与远程服务还是有一些重要的区别。具体来讲,如果服务完全只供同一进程中的组件使用(运行后台任务),客户端一边通过调用 Context.startService()来启动该服务。这种类型的服务为本地服务,它的一般用途是后台执行长耗时操作。而远程服务一般通过bindService()方法启动,主要为不同进程间通信。我们也将远程服务称为AIDL支持服务,因为客户端使用 AIDL 与服务通信。Android中对于远程服务有多种叫法:远程服务、AIDL服务、外部服务和RPC服务。

            5.1 AIDL实现流程图

    图5.1

            这属于代理/存根结构,通过这张AIDL的流程图,很容易发现Android实现IPC其实是在原来的C/S框架上加入了代理/存根结构。

            比如,你到自动取款机上去取款。那么你就是客户(Client),取款机就是你的代理(Proxy);你不会在乎钱具体放在那里,你只想将你的钱从取款机中取出来。你同银行之间的操作完全是取款机代理实现。你的取款请求通过取款机传到另一边,即银行的服务器(Server)。它也没有必要知道你在哪儿取钱,它所关心的是你的身份和你取款多少。当它确认你的权限,就进行相应的操作,返回操作结果给取款机,取款机根据服务器返回结果,从保险柜里取出相应数量的钱给你。你取出卡后,操作完成。取款机不是直接同服务器连接的,他们之间还有一个“存根(Stub)”,取款机与存根通信,服务器与存根通信,从某种意义上说存根就是服务器的代理。实现效果如图5.2:

    图5.2

            5.3 实现原理

            AIDL属于Android的IPC机制,常用于跨进程通信,主要实现原理基于底层Binder机制。

            5.4 实现步骤

            5.4.1 建立工程。按照图5.3和图5.4建立AIDLServer端以及AIDLClient端。在AIDLServer端中只有一个服务程序,没有主界面,其主要功能就是负责下载。AIDLClient端从AIDLServer端获取当前下载进度(注:AIDLServer端和AIDLClient端是不同的两个APK,在模拟本例的时候,需要先在模拟器上安装AIDLServer编译出来的APK,安装方法可以直接在模拟器上运行一次,可以通过adb install your.apk 来安装)。

    图5.3

            AIDLServer端中新建了一个ICountService.aidl的文件,该文件内容如下:

    [plain] view plaincopy
    1. package com.seven.aidlserver;  
    2.   
    3. interface ICountService{  
    4.     int getCount();  
    5. }  

              aidl文件的书写规范如下:

            (1). Android支持String和CharSequence(以及Java的基本数据类型);

            (2). 如果需要在aidl中使用其它aidl接口类型,需要import,即使是在相同包结构下;

            (3). Android允许传递实现Parcelable接口的类,需要import;

            (4). Android支持集合接口类型List和Map,但是有一些限制,元素必须是基本型或者前面三种情况,不需要import集合接口类,但是需要对元素涉及到的类型import;

            (5). 非基本数据类型,也不是String和CharSequence类型的,需要有方向指示,包括in、out和inout,in表示由客户端设置,out表示由服务端设置,inout是两者均可设置。

    图5.4

             AIDLClient端需要将AIDLServer端的ICountService.aidl文件复製过去,这裡为了方便,新建了一个和Server端同名的包,并将ICountService.aidl放与其中。

             5.4.2 我们在Server端建立好ICoutService.aidl文件之后,Eclipse会在/gen/com.seven.aidlserver/目录下自动生成ICountService.java文件。该文件由Eclipse自动生成,请勿随便修改,后文我们需引用到的内容如下:

    [java] view plaincopy
    1. public static com.seven.aidlserver.ICountService asInterface(android.os.IBinder obj) {  
    2.     if ((obj == null)) {  
    3.         return null;  
    4.     }  
    5. android.os.IInterface iin = (android.os.IInterface) obj.queryLocalInterface(DESCRIPTOR);  
    6.     if (((iin != null) && (iin instanceof com.seven.aidlserver.ICountService))) {  
    7.         return ((com.seven.aidlserver.ICountService) iin);  
    8.     }  
    9.     return new com.seven.aidlserver.ICountService.Stub.Proxy(obj);  
    10. }  

              5.4.3 在Server端新建一个内部类继承自ICountService.Stub并覆写其中的getCount()方法,以及实例化该类的一个对象serviceBinder。

    [java] view plaincopy
    1. private AIDLServerBinder serviceBinder = new AIDLServerBinder();  
    2. class AIDLServerBinder extends ICountService.Stub{  
    3.     @Override  
    4.     public int getCount() throws RemoteException {  
    5.         return i;  
    6.     }  
    7. }  
             这里与前面提到的“通过接口实现交互”非常类似。

            5.4.4 在Server端的onBind()方法中,返回前面的serviceBinder对象。

    [java] view plaincopy
    1. @Override  
    2. public IBinder onBind(Intent intent) {  
    3.     Log.i(TAG, "AIDLServer.onBind()...");  
    4.     return serviceBinder;  
    5. }  

             5.4.5 在Server端的onCreate()方法中,开启timer,模拟下载。在Client端通过bindService()绑定Server端的时候,会首先执行Server端的onCreate()方法。


    [java] view plaincopy
    1. @Override  
    2. public void onCreate() {  
    3.     super.onCreate();  
    4.     Log.i(TAG, "AIDLServer.onCreate()...");  
    5.     mTimer = new Timer();  
    6.     mTimer.schedule(new MyTimerTask(), 0,TIME * 1000);  
    7. }  
    8. class MyTimerTask extends TimerTask{  
    9.     @Override  
    10.     public void run() {  
    11.         if(i==100){  
    12.             i=0;  
    13.         }  
    14.         i++;  
    15.     }  
    16. }  

              5.4.6 Client端通过bindService()绑定Server端。


    [java] view plaincopy
    1. if(startBtn==v){  
    2.     Log.i(TAG, "start button click.");  
    3.     mIsBind = bindService(intent, serConn, BIND_AUTO_CREATE);  
    4.     mTimer.schedule(new MyTimerTask(), 1000 ,TIME * 1000);  
    5. }  
              这里的intent = new Intent(“com.seven.aidlserver”);这里跟Server端注册Service时过滤的要一致,也就是说只有发出相同的action才会启动该Service。同时开启了一个timer用于获取下载进度。
            5.4.7 Client端通过ServiceConnection来获取Server端的binder对象。

    [java] view plaincopy
    1. private ServiceConnection serConn = new ServiceConnection() {         
    2.     @Override  
    3.     public void onServiceDisconnected(ComponentName name) {  
    4.         iCountService = null;  
    5.     }         
    6.     @Override  
    7.     public void onServiceConnected(ComponentName name, IBinder service) {  
    8.         Log.i(TAG, "AIDLClient.onServiceConnected()...");  
    9.         iCountService = ICountService.Stub.asInterface(service);  
    10.     }  
    11. };  
              这里的iCountService对象实际上就是ICountService的对象在此实例化。

            5.4.8 获取当前下载进度并更新到界面上。

    [java] view plaincopy
    1. Handler mHandler = new Handler(){  
    2.     @Override  
    3.     public void handleMessage(Message msg) {  
    4.         super.handleMessage(msg);  
    5.         try {  
    6.             int count =  iCountService.getCount();  
    7.             mTextView.setText(count+"%");  
    8.             mProgressBar.setProgress(count);  
    9.         } catch (RemoteException e) {  
    10.             e.printStackTrace();  
    11.         }  
    12.     }  
    13. };  
              通过更新介面上的进度条,可以狠容易的后去当前下载进度。因為AIDLServer端只是一个继承自Service的服务,因此就不贴出其AndroidManifest.xml文件了。

            5.5 小结

            AIDL在Android中是进程间通信常用的方式,可能使用较為复杂,但效率高,扩展性好。同时很多系统服务就是以这种方式完成与应用程序通信的。

            本文通过五个例子,分别介绍了五种与Service交互的方法,这些方法有的简单,有的可能要复杂一些。在这里只是做为对Servie的一些总结。后文附上源码下载链接,不需要积分的哦。

            源码下载

            所有源码均在Ubuntu 10.04 Eclipse-Indigo下实验通过 模拟器采用的是2.3的镜像。

    展开全文
  • VTK之交互方式(interactor style)

    千次阅读 2015-04-27 17:27:33
    VTK提供了多种交互方式,最常用的包括joystick和trackball,并且可以分别对actor和camera进行操作。  在VTK中,可以通过集成已有的交互方式类,然后添加自己的功能,则可以完成在触发响应时,完成响应的操作。  ...
  • 几种项目间数据交互方式

    千次阅读 2018-06-27 11:49:57
    一、 ftp服务器共享方式。...交互时,一个系统按约定的时间将数据写入ftp目录中,另一个系统定期取走并进行相应的业务操作。这种方式在电信、移动中项目用得比较多,特别是sp二、 socket通讯服务器方...
  • ZYNQ PS-PL数据交互方式总结

    千次阅读 2020-06-29 18:09:57
    二,IO方式:MIO EMIO GPIO 三,BRAM或FIFO或EMIF (1)通过BRAM实现PL/PS之间交互 PS 的配置如下图所示。使能 M_AXI_GP0 口,将 FCLK_CLK0 设为 100MHz,使能 PL 至 PS 的中断。 AXI BRAM Controller ...
  • 10个最新交互式Web设计实例欣赏

    千次阅读 2018-03-06 10:05:09
    如今,越来越多的UX/UI设计师将交互/动画元素(例如鼠标悬停状态,音频或视频媒体,滚动交互等等)添加到其网站设计之中。这样一方面可以使网站本身更加绚丽有趣,吸引更多访问者,同时也能够激励访问者更多的关注和...
  • 某一天,我突然在想:App的交互方式有哪些?不同的交互方式有什么区别?每一种交互方式主要的运用场景是什么?如何运用不同的交互方式创造出好玩又爽的体验? 然而,我并没有找到有关于上述问题的系统化的回答,...
  • JAVA与SAP数据交互方式总结

    千次阅读 2012-02-18 18:16:01
    JAVA与SAP数据交互方式总结  RFC方式:Java程序直接通过RFC访问SAP的对象(或称函数,可能叫法不对)  SAP提供了BAPI(Business Application Programming Interface),BAPI是SAP系统对外提供的一系列接口,...
  • 比如在一个项目中,需要同时使用mysql、oracle中存储的数据,将两个数据库中同一张表的数据取出来,获取特的的字段再插入到另一张表中,这种多数据库的交互操作有什么实现方法吗?
  • Spring mvc中前后端数据交互方式

    千次阅读 2017-10-30 15:12:08
    现在IT行业ssm框架用的还是挺多的,今天给大家分享一下spring mvc中前后的数据交互方式: 后端 ➡ 前端 在Spring MVC中这主要通过Model将数据从后端传送到前端,一般的写法为: @RequestMapping(value = ...
  • 信息系统的普及应用导致原有系统间的信息孤岛需要通过系统间接口进行数据交互,信息交互的接口常见有以下几种: (1)数据库交互:服务方提供表或存储过程,由调用方控制commit或rollback。 (2)文件交互:双方对请求...
  • 核心态和用户 态数据的交互方式

    千次阅读 2009-07-30 12:24:00
    核心态和用户 态数据的交互,有多种方式:1:可以通用socket创建特殊套接字,利用套接字实现数据交互;2:通过proc文件系统创建文件来进行数据交互;3:还可以使用设备 文件的方式,访问设备文件会调用设备驱动相应...
  • pyqt5中的多窗口数据交互多种方式方式1:直接访问控件数据—一般不推荐使用(代码的耦合度高) 方式2:通过信号来传输数据,推荐使用,代码的耦合度低,可操作性强 主窗口的代码: #coding=utf8 import sys ...
  • JAVA与SAP数据交互方式总结

    千次阅读 2009-08-31 14:17:00
    JAVA与SAP数据交互方式总结 RFC方式:Java程序直接通过RFC访问SAP的对象(或称函数,可能叫法不对)SAP提供了BAPI(Business Application ProgrammingInterface),BAPI是SAP系统对外提供的一系列接口,主要是使第三...
  • Kinect作为一个划时代的产品,通过获取彩色图像、深度图像以及人体骨骼图像提供一项全新的人机交互方式,使人机互动的理念更加彻底的展现出来。它能够捕捉、跟踪以及解密人体的动作、手势以及声音。另一方面,随着...
  • HRI-人与机器人的智能交互)课程介绍与资料这是机器人系统设计与控制技术的后续课程,全部的课程内容包括四门课程(本科),如下:人机智能交互技术是人机融合的基础,课程介绍多种人机交互技术,包括传统和新兴的,...
  • 文件交互,数据传输的几种方式

    千次阅读 2016-12-06 15:19:03
    原来在一个系统之间可以完成的业务流程,通过多系统的之间多次交互来实现。这里不打算介绍如何进行SOA架构的设计,而是介绍一下应用系统之间如何进行数据的传输。 应用系统之间数据传输有三个要素:传输方式,传输...
  • 许多的设备如雨后春笋般层出不穷,但总体来看,他们都有一些共同的特性,那就是具备高清晰的显示能力,屏幕比较大、有良好的视觉效果,支持友好的触摸交互方式,带有很多新式的传感器模块,如GPS,温度感应器、...
  • 计算机语言概述 2.1 计算机语言的基本概念 2.2 计算机语言的发展 2.3解释型语言和编译型语言的区别 3 计算机的交互方式 3.1 交互方式的种类 3.2文本交互模式打开的方式(windows系统) 4 文本文件和字符集 4.1文本...
  • 交互设计

    千次阅读 2014-12-13 20:19:54
    交互设计编辑 本词条缺少信息栏,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! ...交互设计,又称互动设计,(英文Interaction Design, 缩写 IxD ...交互设计在于定义人造物的行为方式(the "interac
  • 智能时代-不一样的人机交互体验

    千次阅读 2017-08-11 12:20:37
    人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。人工智能从诞生...
  • AR交互设计

    千次阅读 2018-06-13 11:13:24
        研究生期间做基于MR的远程协同设计和指导技术研究,阅读和学习相关资料,学习总结了AR交互设计相关内容。     AR类产品的出现,可能是第一次实现虚拟...    AR效果的呈现有多种方式,市场在短期...
  • Ajax 异步交互

    千次阅读 2020-09-07 08:21:13
    异步交互的区别在于同步交互需要等待结果,而异步交互不需要等待。 所谓异步交互,就是指发送一个请求,不需要等待返回,随时可以再发送下一个请求。 同步交互与异步交互区别在于:同步需要等待结果,而异步不需要...
  • 导语:从现在开始的相当长一段时间里,手部交互依然是最成熟的控制类人机交互方式,并且体验也远远没到完美,值得投入完善。 我们与现实世界进行交互的主要方式是手,我们与VR世界的交互同样如此...
  • 产品读书《交互设计沉思录》

    千次阅读 2019-04-23 14:12:22
    同时,可用性并不是衡量交互设计的唯一重要指标,其内核更应是通过各种方式使观者理解动作,或是参与对话,使其感受交互设计师要传达的观点和文化,才会促使可用性的圆满。(即文中作者提倡的创造更具有诗意和文化...
  • 什么是多模态交互

    千次阅读 2021-02-21 09:16:57
    多模态是指将多种感官进行融合,而多模态交互是指人通过声音、肢体语言、信息载体(文字、图片、音频、视频)、环境等多个通道与计算机进行交流,充分模拟人与人之间的交互方式。 多模态交互包括了视觉、听觉、嗅觉...
  • 摘要:基于华为开源openLooKeng引擎的交互式分析功能,将重磅发布便于用户构建轻量级流、批、交互式全场景数据湖。 在这个“信息爆炸”的时代,大数据已经成为这个时代的关键词之一!随着云计算、物联网、移动计算...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 287,398
精华内容 114,959
关键字:

多种新的交互方式