精华内容
下载资源
问答
  • 初学必知的AIDL应用层上的Binder机制首先得理解几个概念:IPC:Inter-Process Communication,进程间的通信或跨进程通信。简单点理解,一个应用可以存在多个进程,但需要数据交换就必须用IPC;或者是二个应用...

    初学者必知的AIDL在应用层上的Binder机制


    首先得理解几个概念:

    IPC:Inter-Process Communication,进程间的通信或跨进程通信。简单点理解,一个应用可以存在多个进程,但需要数据交换就必须用IPC;或者是二个应用之间的数据交换。

    Binder:Binder是Android的一个类,它实现了IBinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信方式。通过这个Binder对象,客户端就可以获取服务端提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。

    AIDL:Android Interface Definition language,它是一种Android内部进程通信接口的描述语言。


    一、AIDL的使用




    服务端:

    创建一个服务端工程,在工程中点击右键New->AIDL->AIDL File,默认直接点确定,这时会在工程中出现一个aidl文件:


    我们打开这个aidl文件,我们创建一个我们需要测试的方法:


    由于Android Studio是要手动编译才能生成对应AIDL的java文件,既然aidl文件是个接口,那就必须存在着实现这个接口的类,点击编译,系统自动生成一个java类,该java类的代码就是整个Binder机制的原理所在(会在下面第二步骤介绍原理):



    既然是个服务端,那么我们就要开始写服务了,创建一个类,继承Service:

    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.support.annotation.Nullable;
    import android.util.Log;
    
    import com.handsome.boke.IMyAidlInterface;
    
    public class MyService extends Service {
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return myS;
        }
    
        private IBinder myS = new IMyAidlInterface.Stub() {
    
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
    
            }
    
            @Override
            public int add(int num1, int num2) throws RemoteException {
                Log.i("Hensen", "从客户端发来的AIDL请求:num1->" + num1 + "::num2->" + num2);
                return num1 + num2;
            }
        };
    }

    既然是个服务,就必须在manifests文件中配置:

    <!--exported:允许外界访问该服务,AIDL必备条件-->
            <service
                android:name=".Aidl.MyService"
                android:exported="true"/>
    到现在服务端写好了,开启模拟器启动这个程序,记得在代码中开启服务:

    public class LoginActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
    
            startService(new Intent(this, MyService.class));
        }
    }


    客户端:


    在工程中点击右键New->Module,按默认确定,finish:


    关键的一步来了,
    复制服务端的aidl整个文件夹(包括里面的包、aidl文件、完整无缺)粘贴到客户端对应放aidl的地方


    不要忘了,客户端还要
    手动编译


    好了我们来写客户端的代码(我们在MainActivity中放一个”AIDL“的按钮,先绑定服务,然后点击按钮调用):

    public class MainActivity extends AppCompatActivity {
    
        IMyAidlInterface iMyAidlInterface;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //绑定服务
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.handsome.boke", "com.handsome.boke.Aidl.MyService"));
            bindService(intent, conn, BIND_AUTO_CREATE);
        }
    
        /**
         * 点击“AIDL”按钮事件
         *
         * @param view
         */
        public void add(View view) {
            try {
                int res = iMyAidlInterface.add(1, 2);
                Log.i("Hensen", "从服务端调用成功的结果:" + res);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 服务回调方法
         */
        private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                iMyAidlInterface = null;
            }
        };
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //解绑服务,回收资源
            unbindService(conn);
        }
    }


    测试结果(先开启服务端,开启服务后,接着开启客户端,绑定远程服务):

    08-19 10:59:34.548 6311-6328/com.handsome.boke I/Hensen: 从客户端发来的AIDL请求:num1->1::num2->2
    08-19 10:59:34.550 7052-7052/com.handsome.app2 I/Hensen: 从服务端调用成功的结果:3

    二、AIDL的Binder机制原理分析



    分析原理:

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: D:\\workspace5\\Boke\\app\\src\\main\\aidl\\com\\handsome\\boke\\IMyAidlInterface.aidl
     */
    package com.handsome.boke;
    // Declare any non-default types here with import statements
    
    public interface IMyAidlInterface extends android.os.IInterface {
        /**
         * Local-side IPC implementation stub class.
         */
        public static abstract class Stub extends android.os.Binder implements com.handsome.boke.IMyAidlInterface {
            private static final java.lang.String DESCRIPTOR = "com.handsome.boke.IMyAidlInterface";
    
            /**
             * Construct the stub at attach it to the interface.
             */
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            /**
             * Cast an IBinder object into an com.handsome.boke.IMyAidlInterface interface,
             * generating a proxy if needed.
             */
            public static com.handsome.boke.IMyAidlInterface asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.handsome.boke.IMyAidlInterface))) {
                    return ((com.handsome.boke.IMyAidlInterface) iin);
                }
                return new com.handsome.boke.IMyAidlInterface.Stub.Proxy(obj);
            }
    
            @Override
            public android.os.IBinder asBinder() {
                return this;
            }
    
            @Override
            public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
                switch (code) {
                    case INTERFACE_TRANSACTION: {
                        reply.writeString(DESCRIPTOR);
                        return true;
                    }
                    case TRANSACTION_basicTypes: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        long _arg1;
                        _arg1 = data.readLong();
                        boolean _arg2;
                        _arg2 = (0 != data.readInt());
                        float _arg3;
                        _arg3 = data.readFloat();
                        double _arg4;
                        _arg4 = data.readDouble();
                        java.lang.String _arg5;
                        _arg5 = data.readString();
                        this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                        reply.writeNoException();
                        return true;
                    }
                    case TRANSACTION_add: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = this.add(_arg0, _arg1);
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    
            private static class Proxy implements com.handsome.boke.IMyAidlInterface {
                private android.os.IBinder mRemote;
    
                Proxy(android.os.IBinder remote) {
                    mRemote = remote;
                }
    
                @Override
                public android.os.IBinder asBinder() {
                    return mRemote;
                }
    
                public java.lang.String getInterfaceDescriptor() {
                    return DESCRIPTOR;
                }
    
                /**
                 * Demonstrates some basic types that you can use as parameters
                 * and return values in AIDL.
                 */
                @Override
                public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(anInt);
                        _data.writeLong(aLong);
                        _data.writeInt(((aBoolean) ? (1) : (0)));
                        _data.writeFloat(aFloat);
                        _data.writeDouble(aDouble);
                        _data.writeString(aString);
                        mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    
                @Override
                public int add(int num1, int num2) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(num1);
                        _data.writeInt(num2);
                        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
            }
    
            static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
    
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
    
        public int add(int num1, int num2) throws android.os.RemoteException;
    }
    


    我们来分析一下这个类

    首先本身继承Iinterface,所以他也是个接口,接口中必须有方法,代码定位到结尾有2个方法。

    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
        public int add(int num1, int num2) throws android.os.RemoteException;
    这两个方法就是basicTypes和add,就是我们服务端的2个方法。

    接着发现该接口中有1个内部类Stub,继承自本身(IMyAidlInterface)接口,代码定位到Stub类。

    这个Stub有个构造方法、asInterface、asBinder、onTransact(先不介绍)。

    接着发现该内部类Stub还有一个内部类,代码定位到Proxy(我们把它称为代理)类,也是继承自本身(IMyAidlInterface)接口,所以实现该接口的两个方法。

    /**
                 * Demonstrates some basic types that you can use as parameters
                 * and return values in AIDL.
                 */
                @Override
                public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(anInt);
                        _data.writeLong(aLong);
                        _data.writeInt(((aBoolean) ? (1) : (0)));
                        _data.writeFloat(aFloat);
                        _data.writeDouble(aDouble);
                        _data.writeString(aString);
                        mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    
                @Override
                public int add(int num1, int num2) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(num1);
                        _data.writeInt(num2);
                        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
            }
    在这个类里面我们会发现有2个标识:用来区分两个方法,到底你远程请求哪个方法的唯一标识,代码定位到代理类的结尾

     static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    回过头来,还记得我们客户端做了什么吗?答案:绑定一个服务,在回调方法获取一个接口(iMyAidlInterface),它是直接静态使用IMyAidlInterface里面的静态类Stub的asInterface的方法:(好了我们去跟踪到Stub类asInterface这个方法)

     /**
         * 服务回调方法
         */
        private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                iMyAidlInterface = null;
            }
        };
    代码定位到Stub类asInterface方法

    public static com.handsome.boke.IMyAidlInterface asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.handsome.boke.IMyAidlInterface))) {
                    return ((com.handsome.boke.IMyAidlInterface) iin);
                }
                return new com.handsome.boke.IMyAidlInterface.Stub.Proxy(obj);
            }
    前面只是做一些判断、看一下最后一句话:我们将传过来的obj还是传给了它的代理类来处理,返回的是代理类的对象

    return new com.handsome.boke.IMyAidlInterface.Stub.Proxy(obj);
    所以在客户端的iMyAidlInterface = ……,则是拿到它的代理类,好了,这个时候就看客户端调用代理类干嘛了

    int res = iMyAidlInterface.add(1, 2);
    他调用了代理类的add方法,代码定位到代理类的add方法
    @Override
                public int add(int num1, int num2) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(num1);
                        _data.writeInt(num2);
                        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    你会发现,它把数据写进了_data里面,最后调用transact方法,传入_data数据,唯一标识Stub.TRANSACTION_add。

    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
    然后这个transact方法就是通过底层了,通过底层结束后,这些参数送到哪了?答案:底层会走到stub类中的onTransact方法,通过判断唯一标识,确定方法:
    case TRANSACTION_add: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = this.add(_arg0, _arg1);
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
    在这个地方将传过来的参数解包,readInt方法。然后调用this.add方法,this指的就是服务端,调用服务端的add的方法:

    int _result = this.add(_arg0, _arg1);
    将得到的结果,写入reply

    reply.writeNoException();
                        reply.writeInt(_result);
    最后一句话,最后返回系统的ontransact方法,传入结果reply:

    return super.onTransact(code, data, reply, flags);
    所以我们在上面获得的结果就是reply(答案:3):

    int res = iMyAidlInterface.add(1, 2);

    最后总结下整个过程



    三、AIDL编写时候的一些错误

    错误一:

    Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'int com.handsome.boke.IMyAidlInterface.add(int, int)' on a null object reference
    这个错误很有可能是你写的服务端,忘记返回myS了,返回的是个null

    @Override
        public IBinder onBind(Intent intent) {
            return null;
        }

    错误二:


     Caused by: java.lang.SecurityException: Not allowed to bind to service Intent { cmp=com.handsome.boke/.Aidl.MyService }
    这个错误很有可能是的服务端在manifests文件中少了exported="true"的属性

    <!--exported:允许外界访问该服务,AIDL必备条件-->
            <service
                android:name=".Aidl.MyService"/>














    展开全文
  • 自己还一个某一个位置原地踏步,想变得有钱,有能力,却知道努力方向,也知道怎么做。或者说愿意吃苦,愿意受累,又想享受。然后情 绪就会变成对社会的仇恨跟抱怨。当所有的原因归因到自己身上,是能力,...

      当一个人,本身智力不足,能力不足。他出现在社会的某一个点,比上不足,比下有余。没能力改变世界,也没能力改变自己。当发现周围的人能富的都富了,能贵 的也都贵了。自己还在一个某一个位置原地踏步,想变得有钱,有能力,却不知道努力方向,也不知道怎么做。或者说不愿意吃苦,不愿意受累,又想享受。然后情 绪就会变成对社会的仇恨跟抱怨。当所有的原因归因到自己身上,是能力,智力,性格的问题。自己又不愿意承认,然后就归因到别人身上,自己富不了,得不到社 会高价值,是是因为别人导致的。

      有时候他的生活并不像他自己想象的那么差,可能也衣食无缺,有车有房,爆发负能量的原因只是因为他看到了别人开的比他好的车子,住比他大的房子。

      他们会成为每天生活中给外面透漏着各种负面情绪,怨天尤人,混日子,以一种消极的状态生活的人。专门以恶心别人投递负能量为乐。不以客观事实去评论,全凭一时想法,甚至故意去歪曲事实,他们无法改变自己提升自己,就开始破罐子破摔,选择带给这个世界恶意,而不是善意。

       每个人天生就有一定的区别,有的人生下来就有钱,相对有的就穷,有的人生下来聪明,相对也有笨人。人天生就有天分,智力的区别。一个班里,同样学习时 间,总有人先掌握某个知识点。不管你是好的学校,还是差的学校,你总会发现有一些人,下课玩游戏,上课不怎么听课,但是考试成绩,对知识的掌握程度,总是 比你高。我们需要牺牲很多业余时间才能赶得上他们。有些天才是天生的,有些天才是靠牺牲业余时间赶出来的。

      全球60亿人,平均智商 120,那么就会有30亿智商在120以上的人,30亿智商低于平均智商的人。智商高于平均智商的30亿人,生活自然过的很好。但是如果你是处于低于平均 智商的那30亿分之一呢,假设你不是,但是低于平均智商的那30亿人总是存在的,他们无力改变现实,就会想办法破坏规则,打乱现实,用来改变自己的生活, 很多创新都是他们想出来的,但是更多的负能量也是他们散发出来的。而30亿里只要有2亿散发负能量的人,会让你感觉到整个世界都是负能量的。就可以让每天的新闻都显示社会丑恶面,每天的新闻不带一个重样的。

      中国13亿人,表明了有6.5亿人会在平均智商之下。 6.5亿人在平均生活水平之下。6.5亿人会在平均工资之下。人的基数越大,等级,分层就会越多,相对应的贫富差距也就会越大,而这是无解的一个问题。

       给予不努力,或者创造价值低的人过高的福利待遇,会伤及真正创造价值的那群人,当年的大锅饭就是合理的例子。当所有人待遇都一样的时候,当努力,奋进没有了作用,没人会选择让自己更辛苦。人都是趋利的,大部分人都会选择付出最小得到最多的那个选择,而一切平均的时候,大部分人会选择尽量的少工作,或者不 工作。而以不工作获取分配的这种价值观成立的时候,也就是社会结构崩溃的时候,也是战乱开始的时候。

      为了保持均衡,给予创造社会价值或者努力奋斗群体福利待遇过差,当得到跟付出不成正比的时候,人们就会失去努力跟奋斗的欲望,社会发展就会停滞不前,或者倒退。

      也许每当你看到国家发的平均工资统计的时候,并不是你扯了祖国的蛋了,而是你真的工资低了。当你的待遇超过了那个平均工资,或者刚好达标,你是没心情在下面感叹或者发评论的,因为你觉得它只是描述了一句常识而已。

      有时候我们应该去反省自己,观察自己是不是成为散发负能量不惹人喜欢的人了。

      当一个人发现因为自己能力,智商,先天环境的问题,一生好像只能在社会上达到目前高度了,然后他以后的生活应该怎么去生活?

      PS1:已经达到最高高度了,那么便看淡现在所拥有的。将视线放在身边其他事情上,把自己身心投入进去,去体验,去拼搏,尝试能得几分。抱着无所谓得,无所谓失的心态,随心而走。

     

      

    转载于:https://www.cnblogs.com/ariklee/p/4990641.html

    展开全文
  • 简单点理解,一个应用可以存在多个进程,但需要数据交换就必须用IPC;或者是二个应用之间的数据交换。Binder:Binder是Android的一个类,它实现了IBinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信...


    首先得理解几个概念:

    IPC:Inter-Process Communication,进程间的通信或跨进程通信。简单点理解,一个应用可以存在多个进程,但需要数据交换就必须用IPC;或者是二个应用之间的数据交换。

    Binder:Binder是Android的一个类,它实现了IBinder接口。从IPC角度来说,Binder是Android中的一种跨进程通信方式。通过这个Binder对象,客户端就可以获取服务端提供的服务或数据,这里的服务包括普通服务和基于AIDL的服务。

    AIDL:Android Interface Definition language,它是一种Android内部进程通信接口的描述语言。


    一、AIDL的使用




    服务端:

    创建一个服务端工程,在工程中点击右键New->AIDL->AIDL File,默认直接点确定,这时会在工程中出现一个aidl文件:


    我们打开这个aidl文件,我们创建一个我们需要测试的方法:


    由于Android Studio是要手动编译才能生成对应AIDL的java文件,既然aidl文件是个接口,那就必须存在着实现这个接口的类,点击编译,系统自动生成一个java类,该java类的代码就是整个Binder机制的原理所在(会在下面第二步骤介绍原理):



    既然是个服务端,那么我们就要开始写服务了,创建一个类,继承Service:

    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.support.annotation.Nullable;
    import android.util.Log;
     
    import com.handsome.boke.IMyAidlInterface;
     
    public class MyService extends Service {
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return myS;
        }
     
        private IBinder myS = new IMyAidlInterface.Stub() {
     
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
     
            }
     
            @Override
            public int add(int num1, int num2) throws RemoteException {
                Log.i("Hensen", "从客户端发来的AIDL请求:num1->" + num1 + "::num2->" + num2);
                return num1 + num2;
            }
        };
    }
    

    既然是个服务,就必须在manifests文件中配置:

    <!--exported:允许外界访问该服务,AIDL必备条件-->
            <service
                android:name=".Aidl.MyService"
                android:exported="true"/>
    

    到现在服务端写好了,开启模拟器启动这个程序,记得在代码中开启服务:

    public class LoginActivity extends AppCompatActivity {
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
     
            startService(new Intent(this, MyService.class));
        }
    }
    


    客户端:


    在工程中点击右键New->Module,按默认确定,finish:


    关键的一步来了,
    复制服务端的aidl整个文件夹(包括里面的包、aidl文件、完整无缺)粘贴到客户端对应放aidl的地方


    不要忘了,客户端还要
    手动编译


    好了我们来写客户端的代码(我们在MainActivity中放一个”AIDL“的按钮,先绑定服务,然后点击按钮调用):

    public class MainActivity extends AppCompatActivity {
     
        IMyAidlInterface iMyAidlInterface;
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
     
            //绑定服务
            Intent intent = new Intent();
            intent.setComponent(new ComponentName("com.handsome.boke", "com.handsome.boke.Aidl.MyService"));
            bindService(intent, conn, BIND_AUTO_CREATE);
        }
     
        /**
         * 点击“AIDL”按钮事件
         *
         * @param view
         */
        public void add(View view) {
            try {
                int res = iMyAidlInterface.add(1, 2);
                Log.i("Hensen", "从服务端调用成功的结果:" + res);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
     
        /**
         * 服务回调方法
         */
        private ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            }
     
            @Override
            public void onServiceDisconnected(ComponentName name) {
                iMyAidlInterface = null;
            }
        };
     
        @Override
        protected void onDestroy() {
            super.onDestroy();
            //解绑服务,回收资源
            unbindService(conn);
        }
    }
    

    通过Intent中的setComponent来启动其他应用中的Service
    在这里插入图片描述


    测试结果(先开启服务端,开启服务后,接着开启客户端,绑定远程服务):

    08-19 10:59:34.548 6311-6328/com.handsome.boke I/Hensen: 从客户端发来的AIDL请求:num1->1::num2->2
    
    08-19 10:59:34.550 7052-7052/com.handsome.app2 I/Hensen: 从服务端调用成功的结果:3
    


    二、AIDL的Binder机制原理分析



    分析原理:

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: D:\\workspace5\\Boke\\app\\src\\main\\aidl\\com\\handsome\\boke\\IMyAidlInterface.aidl
     */
    package com.handsome.boke;
    // Declare any non-default types here with import statements
     
    public interface IMyAidlInterface extends android.os.IInterface {
        /**
         * Local-side IPC implementation stub class.
         */
        public static abstract class Stub extends android.os.Binder implements com.handsome.boke.IMyAidlInterface {
            private static final java.lang.String DESCRIPTOR = "com.handsome.boke.IMyAidlInterface";
     
            /**
             * Construct the stub at attach it to the interface.
             */
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
     
            /**
             * Cast an IBinder object into an com.handsome.boke.IMyAidlInterface interface,
             * generating a proxy if needed.
             */
            public static com.handsome.boke.IMyAidlInterface asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.handsome.boke.IMyAidlInterface))) {
                    return ((com.handsome.boke.IMyAidlInterface) iin);
                }
                return new com.handsome.boke.IMyAidlInterface.Stub.Proxy(obj);
            }
     
            @Override
            public android.os.IBinder asBinder() {
                return this;
            }
     
            @Override
            public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
                switch (code) {
                    case INTERFACE_TRANSACTION: {
                        reply.writeString(DESCRIPTOR);
                        return true;
                    }
                    case TRANSACTION_basicTypes: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        long _arg1;
                        _arg1 = data.readLong();
                        boolean _arg2;
                        _arg2 = (0 != data.readInt());
                        float _arg3;
                        _arg3 = data.readFloat();
                        double _arg4;
                        _arg4 = data.readDouble();
                        java.lang.String _arg5;
                        _arg5 = data.readString();
                        this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                        reply.writeNoException();
                        return true;
                    }
                    case TRANSACTION_add: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        int _arg1;
                        _arg1 = data.readInt();
                        int _result = this.add(_arg0, _arg1);
                        reply.writeNoException();
                        reply.writeInt(_result);
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
     
            private static class Proxy implements com.handsome.boke.IMyAidlInterface {
                private android.os.IBinder mRemote;
     
                Proxy(android.os.IBinder remote) {
                    mRemote = remote;
                }
     
                @Override
                public android.os.IBinder asBinder() {
                    return mRemote;
                }
     
                public java.lang.String getInterfaceDescriptor() {
                    return DESCRIPTOR;
                }
     
                /**
                 * Demonstrates some basic types that you can use as parameters
                 * and return values in AIDL.
                 */
                @Override
                public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(anInt);
                        _data.writeLong(aLong);
                        _data.writeInt(((aBoolean) ? (1) : (0)));
                        _data.writeFloat(aFloat);
                        _data.writeDouble(aDouble);
                        _data.writeString(aString);
                        mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
     
                @Override
                public int add(int num1, int num2) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(num1);
                        _data.writeInt(num2);
                        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
            }
     
            static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
     
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
     
        public int add(int num1, int num2) throws android.os.RemoteException;
    }
    


    我们来分析一下这个类

    首先本身继承Iinterface,所以他也是个接口,接口中必须有方法,代码定位到结尾有2个方法。

    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
        public int add(int num1, int num2) throws android.os.RemoteException;
    
    这两个方法就是basicTypes和add,就是我们服务端的2个方法。

    接着发现该接口中有1个内部类Stub,继承自本身(IMyAidlInterface)接口,代码定位到Stub类。

    这个Stub有个构造方法、asInterface、asBinder、onTransact(先不介绍)。

    接着发现该内部类Stub还有一个内部类,代码定位到Proxy(我们把它称为代理)类,也是继承自本身(IMyAidlInterface)接口,所以实现该接口的两个方法。

    /**
                 * Demonstrates some basic types that you can use as parameters
                 * and return values in AIDL.
                 */
                @Override
                public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(anInt);
                        _data.writeLong(aLong);
                        _data.writeInt(((aBoolean) ? (1) : (0)));
                        _data.writeFloat(aFloat);
                        _data.writeDouble(aDouble);
                        _data.writeString(aString);
                        mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
     
                @Override
                public int add(int num1, int num2) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    int _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(num1);
                        _data.writeInt(num2);
                        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.readInt();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
            }
    
    在这个类里面我们会发现有2个标识:用来区分两个方法,到底你远程请求哪个方法的唯一标识,代码定位到代理类的结尾

     static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    

    回过头来,还记得我们客户端做了什么吗?答案:绑定一个服务,在回调方法获取一个接口(iMyAidlInterface),它是直接静态使用IMyAidlInterface里面的静态类Stub的asInterface的方法:(好了我们去跟踪到Stub类asInterface这个方法)

    1. /**
    2. * 服务回调方法
    3. */
    4. private ServiceConnection conn = new ServiceConnection() {
    5. @Override
    6. public void onServiceConnected(ComponentName name, IBinder service) {
    7. iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
    8. }
    9. @Override
    10. public void onServiceDisconnected(ComponentName name) {
    11. iMyAidlInterface = null;
    12. }
    13. };
    代码定位到Stub类asInterface方法

    1. public static com.handsome.boke.IMyAidlInterface asInterface(android.os.IBinder obj) {
    2. if ((obj == null)) {
    3. return null;
    4. }
    5. android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    6. if (((iin != null) && (iin instanceof com.handsome.boke.IMyAidlInterface))) {
    7. return ((com.handsome.boke.IMyAidlInterface) iin);
    8. }
    9. return new com.handsome.boke.IMyAidlInterface.Stub.Proxy(obj);
    10. }
    前面只是做一些判断、看一下最后一句话:我们将传过来的obj还是传给了它的代理类来处理,返回的是代理类的对象

    return new com.handsome.boke.IMyAidlInterface.Stub.Proxy(obj);
    所以在客户端的iMyAidlInterface = ……,则是拿到它的代理类,好了,这个时候就看客户端调用代理类干嘛了

    int res = iMyAidlInterface.add(1, 2);
    他调用了代理类的add方法,代码定位到代理类的add方法
    1. @Override
    2. public int add(int num1, int num2) throws android.os.RemoteException {
    3. android.os.Parcel _data = android.os.Parcel.obtain();
    4. android.os.Parcel _reply = android.os.Parcel.obtain();
    5. int _result;
    6. try {
    7. _data.writeInterfaceToken(DESCRIPTOR);
    8. _data.writeInt(num1);
    9. _data.writeInt(num2);
    10. mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
    11. _reply.readException();
    12. _result = _reply.readInt();
    13. } finally {
    14. _reply.recycle();
    15. _data.recycle();
    16. }
    17. return _result;
    18. }
    你会发现,它把数据写进了_data里面,最后调用transact方法,传入_data数据,唯一标识Stub.TRANSACTION_add。

    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
    然后这个transact方法就是通过底层了,通过底层结束后,这些参数送到哪了?答案:底层会走到stub类中的onTransact方法,通过判断唯一标识,确定方法:
    1. case TRANSACTION_add: {
    2. data.enforceInterface(DESCRIPTOR);
    3. int _arg0;
    4. _arg0 = data.readInt();
    5. int _arg1;
    6. _arg1 = data.readInt();
    7. int _result = this.add(_arg0, _arg1);
    8. reply.writeNoException();
    9. reply.writeInt(_result);
    10. return true;
    11. }
    在这个地方将传过来的参数解包,readInt方法。然后调用this.add方法,this指的就是服务端,调用服务端的add的方法:

    int _result = this.add(_arg0, _arg1);
    将得到的结果,写入reply

    1. reply.writeNoException();
    2. reply.writeInt(_result);
    最后一句话,最后返回系统的ontransact方法,传入结果reply:

    return super.onTransact(code, data, reply, flags);
    所以我们在上面获得的结果就是reply(答案:3):

    int res = iMyAidlInterface.add(1, 2);

    最后总结下整个过程



    三、AIDL编写时候的一些错误

    错误一:

    Caused by: java.lang.NullPointerException: Attempt to invoke interface methodint com.handsome.boke.IMyAidlInterface.add(int, int)’ on a null object reference
    这个错误很有可能是你写的服务端,忘记返回myS了,返回的是个null

    1. @Override
    2. public IBinder onBind(Intent intent) {
    3. return null;
    4. }

    错误二:


     Caused by: java.lang.SecurityException: Not allowed to bind to service Intent { cmp=com.handsome.boke/.Aidl.MyService }
    这个错误很有可能是的服务端在manifests文件中少了exported=“true"的属性

    1. <!–exported:允许外界访问该服务,AIDL必备条件–>
    2. <service
    3. android:name=”.Aidl.MyService"/>














    展开全文
  • 大家知道Python里面的字典虽然好用,但是有两个显著的缺点,其中之一就是无序,如何构造字典的时候,让字典里面填入的内容有序呢,一般的方法都是等字典的内容填充好了之后,用sorted排序,但是...

    工具:Sublime Text

    语言:Python3.6

    高手必知的库:

    collections

    concurrent

    logging

    argparse

    我最喜欢的collections库

    大家知道Python里面的字典虽然好用,但是有两个显著的缺点,其中之一就是无序,如何在构造字典的时候,让字典里面填入的内容有序呢,一般的方法都是等字典的内容填充好了之后,用sorted排序,但是sorted,也并不能保证是按照添加的顺序进行迭代

    痛点1:字典无序的问题

    有没有办法让字典出生的时候就是带序的,有的就是collections库里面的OrderedDict,传统的字典输出的时候,有时会乱序

     

    输出{'A': 0, 'B': 1, 'C': 2, 'E': 4, 'D': 3}

    如果我们想按照字典加入的顺序输出,必须用OrderedDict

     

    OrderedDict会自动按照加入的顺序打印,但是这样做的坏处是开销很大,因为它内部维护了一张双向链表,大小是普通字典的2倍.

    痛点2:字典无缺省值的问题

    字典一般都是没有缺省值的,比如我们在爬虫的时候,我们希望我们爬取的关键字如果爬到有值则填入内容,如果没有则用缺省值代替.

    比如我前段时间做的年度电影榜单(2017年度电影榜单出炉),keys=['movie_name','movie_link','rating_num','rating_people_num']

    初始化这样的字典有三种方法:

     

    但是上面3种解决方案有缺点:

    比如我们访问一个不存在的key的时候,如何让它返回一个缺省值 ?
        比如复杂一点数据结构,字典里面有列表,而不是一个简单的字符串?
        这些问题如何优雅的解决,用神器defaultdict
    比如我们构造一个学生的成绩单,缺省值我们认为是60分:

     

    如果我们要获取一个不在名单里面的学生成绩

    print (students['sam'])

    输出60 #输出是60

    我们打印一些看看学生的成绩,是不是非常方便

    print (students)

    输出{'lili': 100, 'jack': 80, 'tom': 70, 'sam': 60})

    如果我们是一个字典嵌套集合的数据结构,我们只要把这个字典缺省设为set,然后只要管如何添加数据就行,不用操心如何初始化字典:

     

    痛点3:像类一样玩转元组数据

    比如我们有一个数据结构students = (name, score, weight)

    我们要访问这个元组,需要通过下标去访问,非常不方便,如果这个元组很长,用下标会弄错,而且乱序之后不易扩展

    如果用一个类去构建,有点杀鸡用牛刀的赶脚!这个时候用namedtuple就有一种妙不可言的感觉,太方便了,可以体会一下Python之美.

     

    然后我们访问这个属性,可以用类似类的访问属性方式去访问

    print (s1.name)

    print (s1.score)

    print (s1.weight)

    输出

    Leo

    100

    65

    简单而强大的并发库concurrent

    痛点4:如何简便的用并发

    我们在爬虫的时候,如果有100个url需要并发去爬取,一种通用的做法是开多线程,然后把100个url放入队列里面,开多线程从共享队列里面取url并发爬取,有没有更简便的方便,有的用concurrent库.

    比如:我们有一个需求是要爬取百度,头条,知乎,豆瓣,新浪和搜狐的首页.

    我们看用concurrent里面的线程池如何轻松解决

     

    全能的日志库logging

    痛点5:日志怎么打才好

    在做大一点的项目的时候,有3个地方需要考虑:

    第一:代码架构的扩展性和维护性,主要会用一些设计模式来重构

    第二:代码的稳定性,会加很多异常保护

    第三:就是头疼的debug的日志,需求既要灵活,功能又要全面

    单一的print非常lower,为了解决这个痛点,我们必须用logging模块

     

    这个时候我们去看一下mylog.log文件就会发现,里面把这5条信息都记录下来了

    CRITICAL:root:This is a critical message

    ERROR:root:This is an error message

    WARNING:root:This is a warning message

    INFO:root:This is a info message

    DEBUG:root:This is a debug message

    logging里面有5个级别critical>error>warning>info>debug

    debug是最低的,我们上面在basciConfig里面设置的是低优先级的DEBUG,如果我们改成WARNING,那么就只显示warning以上的级别(含warning)

    如果我们想输出的日志里面加时间戳,怎么办,简单的在basicConfig里面设置一下format格式就ok了

    %(levelname)s: 打印日志级别名称

    %(asctime)s: 打印日志的时间

    %(message)s: 打印日志信息

     

    多面的命令行解析库

    痛点6:解决命令行解析多选项问题

    如果有做命令行的同学,或者是自动化脚本的对argparse一定不陌生,这个一个非常重要的库,可以对命令行提供强大的各种选项功能

    比如新建一个demo.py ,我们希望这个小脚本可以对两个数运算

     

    我们在命令行下敲一下:

    xindeMacBook-Pro:HiPython xin$ python3 demo.py -h

    usage: demo.py [-h] [-t T] [-n1 N1] [-n2 N2]

    calculate two numbers

    optional arguments:

    -h, --help show this help message and exit

    -t T add/mul

    -n1 N1 First num

    -n2 N2 Second num

    -h立马就把各个选项的用法一目了然
        -t 表示你运算类型
        -n1表示第一个数
        -n2表示第二个数
    输入add作加法运算:

    xindeMacBook-Pro:HiPython xin$ python3 demo.py -t add -n1 10 -n2 20

    10.0+20.0=30.0

    输入mul作乘法运算:

    xindeMacBook-Pro:HiPython leoxin$ python3 demo.py -t mul -n1 10 -n2 20

    10.0*20.0=200.0                                        

    展开全文
  • 传统的软件质量管理包括设计时间和部署时间活动。从根本上来说,就是一定的要求,一定的时间限制下,一定的预算支出下... 这种假设经常是错误的——大多数情况下,当要求还成熟时,会随着时间的推移改变。最
  • 从我们的测试中,从Ubuntu 10.10更改Xubuntu 10.10,要求我们下载完整Xubuntu文件的到一半(42%)。 Kubuntu live desktop (with installer) x86 Kubuntu实时桌面(带有安装程序)x86 Note: Kubuntu is only ...
  • 》一起看,但保证是说清楚了一些,还是更混乱了 :S。 对我讨论的这些话题,我的观点,明确成一句话来说:既然目前那么多现存编程范式中的种种原则、手法,都是针对*组织*这一问题的,那么我认为这恰好证明,些编程...
  • 为什么OO方法是有本质缺陷的?

    千次阅读 2009-01-22 09:08:00
    今天我这里说OO表达能力不足, 估计没人会信, 但是这真有可能是问题的核心所在, 如果是这样, 那么用歪了也罢学习困难也罢, 错不在使用和学习在于OO自身(这种质疑也不是一天两天了,不过大多数言论都...
  • 第一是因为这事客观存在的:因为现实中有一些偏离理想的复杂情况,首先,原子自己不是静止的,不是严格的周期性晶格的格点位置就动了,而是平衡位置上会发生振动;其次,杂质是必然存在的,再次,实际晶格结构...
  • 产品读书《设计心理学1-4》-设计

    千次阅读 2016-12-27 10:58:51
    诺曼这套书里面谈到,设计本质不是创意,而是设计与使用的沟通,是要让用户一眼就看得懂产品,知道怎么使用。所以一个好的设计,一定是兼顾了可视性和易懂性。 简单来说,好的设计就是让用户一看就知道这个...
  • 第一次接收到此流时,将缓冲区转换图像之前,我能够一次读取16位流,以便对每个像素执行一些计算,即每个像素存在16位数据块.现在下半部分是Django网络应用程序,这次我也通过ffmpeg,nginx,hls流向您展示了此视频输出...
  • 4.数据存储模型-二进制

    千次阅读 2018-08-01 11:41:24
    数据存储模型 当今社会,计算机无处不在,我们知道计算机CPU...计算机中的这些数据到底是以什么方式存在?本节课将会大家解答这些疑问,让大家从底层理解什么是计算机中的数据。 计算机电路模型 当我们...
  • 作者丽萨·克龙(Lisa Cron),现任加州大学洛杉矶分校写作项目的老师,她毕业于加州大学伯克利分校,出版业、电视业工作多年,也是纽约华纳兄弟电影公司、洛杉矶威秀电影公司等的故事顾问。擅于写故事,尤其擅于...
  • OC属性总结笔记

    千次阅读 2015-07-31 09:08:57
    如果方法只.m中实现,没有.h中声明,这个方法是私有方法,只能当前类中使用属性Objective-c的一个特性,通过@property指令来声明属性,会自动生成访问器,需要手动再添加访问器方法 @property 属性 对...
  • 利用备用Mac的一种方法是...尽管娱乐界正在通过以Netflix,Disney +和Apple TV +之类的服务转向以流媒体中心的存在,但并非所有内容都可以这些服务上查看。您可能光盘上拥有一些内容,这些内容根本无法通过流媒体
  • 电商后台之【商品管理系统】

    千次阅读 2020-06-29 10:34:29
    关于商品管理系统的总结介绍网能够搜索出好多,这里也结合了接触过的系统,借鉴了一些资料,根据个人的理解整理出来,希望能够按计划形成一个完整的供应链系列文章,目的是通过梳理总结让自己原来懵懂的内容清晰,...
  • Linux系统中如何安装mysql的源码包?

    千次阅读 2016-10-31 01:54:54
    1. mysql源码包的下载mysql安装包的官方下载地址:http://dev.mysql.com/downloads/mysql/5.6.html#downloads打开该下载地址后, “Select Version:”处,选择要下载的mysql的版本,我选择的是5.6.34;...
  • 人们对软件架构存在非常多的误解:  其中一个最为普遍的误解就是:将架构和框架混为一谈,其实很简单,一句话:框架就是软件,架构不是... 框架一种特殊的软件,它并能提供完整无缺的解决方案,而是你构建解...
  • 输入编辑器中不存在的UBB代码,看是否起作用 [url=javascript:alert('hello')]链接[/url] [email=javascript:alert('hello')]EMail[/email] [email=yangtao@rising.com.cn STYLE="background-image: url(javascript:...
  • 十大著名思想实验

    千次阅读 2014-10-12 12:58:18
    导读:科学上革命性的提议一般都是思想突发实验,爱因斯坦说:“提出一个问题往往比解决一个问题更重要,因为解决一个问题也许仅是一个数学上的或实验上的技能而已,提出新的问题,新的可能性,从新的角度去看旧...
  • 网络安全概述

    2017-09-06 19:06:58
    2.1 网络空间安全学科的内涵 传统的信息安全强调信息(数据)本身的安全属性,...信息论的基本知识告诉我们,信息能脱离它的载体孤立存在,因此我们能脱离信息系统孤立地谈论信息安全.这也就是说,我们应当从信息系
  • [转]Berkeley DB设计经验

    千次阅读 2016-05-27 20:24:52
    我们将集中关注体系结构——我们是如何开始的,我们设计了什么,我们哪结束了以及为什么。设计能够(而且一定将要)被强迫去适应和改变——重要的是随时间的推移维护原则和一致的愿景。我们也将简要的谈及长期...
  • 今生来世

    千次阅读 2005-03-06 13:08:00
    生命的意义,尽此生漫长短暂的过程中,时间里,每一个有缘或无缘的人生角落,让我们说一些平淡的话,听一些怀旧的歌,读一些浪漫的...不要我编织一个遥可及的梦,剪一枚纸月亮挂暗夜无星的天边。一生便是
  • 您可以下载改进之前和之后的示例应用程序源代码,也可以作者的 Web 服务器上查看两个版本的运行效果。除了 Ajax 技术和最佳实践之外,您还将了解 Ajax 如何通过渐进增强原理改善用户体验。 本文假设您已经牢固...
  • 它将保留用作图形数据的表元素页面上完整无缺,这既可以提高可访问性,又可以设备上不存在JavaScript或应用案例认为适合图形中显示数据时进行智能后备,例如小屏幕上。 用法 您的页面中包含grafici.js ...
  • 一个NBA球队场上球员的组成与软件团队有相通之处,且作一笑谈,不足证: ...而在软件团队中,担任这一角色的莫过于项目经理(项目组长)。项目经理需要调和团队内外的各种关系,组织各种资源进行
  • 当您需要跨不同目录解析文件(如果存在)时(例如,在为站点使用不同主题或语言环境时,解决或适用于您的用例),这将非常有用。 假设您有一个包含文件a.js ,该文件源目录中使用以下配置: import * from '...
  • 架构和框架的区别

    2019-05-07 21:26:05
    人们对软件架构存在非常多的误解,其中一个最为普遍的误解就是:将架构...架构体现“构”字上,理解成构造,是一个动词性的,是一系列动作发生的策略性体现。 框架是一种特殊的软件,它并能提供完整...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,519
精华内容 607
关键字:

为什么存在者存在而无却不在