精华内容
下载资源
问答
  • Handler机制及四个组成部分

    千次阅读 2018-06-01 10:51:29
    有关Handler常用类,四个组成部分 Message:消息,被传递和处理的数据。其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。  Message作为传递的消息与Handler...

        转载请注明出处:https://blog.csdn.net/github_38372075/article/details/80534808
        我的简书传送门

         今天我们来了解一下Handler。Android中操作UI控件需要在主线程中进行,为了打破对主线程的依赖(将耗时操作在后台线程执行,而将执行结果在ui线程中操作ui显示),Android引入了Handler消息传递机制。

    Handler

         Handler有这样三个特点:
    a.允许你去发送并处理一条与Runnable对象和MessageQueue相关联的消息。
    b.每一个Handler实例都与一个单独的线程和该线程的MessageQueue相关。
    c.当你创建一个新的处理程序时,它将绑定到正在创建的线程的线程/消息队列——从那个点开始,它将向该消息队列传递消息和runnables,并在它们从消息队列中释放时执行它们。
         实际上,根据我的理解,handler就是我们在各线程间处理发送消息数据的一种机制,实现线程间切换的一种方式。
         Handler有两个主要用途:
    (1)将消息和runnables作为将来的某个点执行
    (2)在不同的线程上执行要执行的操作

    Handler线程模型

         先介绍了一下Handler的基本概念,下面就来说一下handler线程模型与一些handler常用的函数以及相关的类。
    * 我们都知道,android的UI操作必须要在主线程中进行,为什么? 因为在多线程中同时执行UI操作是不安全的
    * 可以把全部的操作都放在主线程中么? 不可以,耗时操作需要在后台线程执行,避免ANR
    Handler线程模型.png
         也就是说,如果我们进行了耗时操作,如网络加载图片后,又想显示在我们的ImageView上,那么就需要进行线程间切换,使用handler将后台线程切换到主线程上后,进行UI操作。

    Handler常用方法

    构造方法

         Handler是Android中实现线程间切换机制的类
    * public Handler() 无参构造,直接new。

        // 若只是执行runnable则不需要覆写handleMessage方法。因为执行runnable会自动忽略handleMessage方法本身。
        Handler handler0 = new Handler();
        // 如果我们要对发送的消息进行操作则需要覆写handleMessage方法。
        Handler handler1 = new Handler(){
             @Override
                public void handleMessage(Message msg) {
                    // 获得消息后操作
                }
        }
    • public Handler(Callback callback)
    • public Handler(Looper looper)
    • public Handler(Looper looper,Callback callback) 参数1,looper;参数2,callback回调函数,相当于实现handler抽象方法handleMessage(Message msg);。
        public interface Callback {
            public boolean handleMessage(Message msg);
        }
    调用函数
    • post(Runnable r) 将Runnable添加到MessageQueue中。此处要强调一点,如果发送的是runnable则会忽略掉handleMessage方法的执行,即使是发送含有runnable的Message则也会忽略掉handleMessage方法的执行
        public interface Callback {
            public boolean handleMessage(Message msg);
        }
    • postAtTime(Runnable r, long updateMillis) 在指定的时间点运行runnable。
    • postDelayed(Runnable r, long delayMillis) 在延迟一段时间后运行runnable。
        // 此处两个方法执行runnable时机一致
        handler.postDelayed(runnable,2000);
        handler.postAtTime(runnable,System.currentTimeMillis() + 2000);
    • postAtFrontQueue(Runnable r) 将Runnable放在队列最前端执行
    • sendEmptyMessage(int what) 发送一个空消息,参数为int型what(消息执行标识)。
    • sendMessage(Message msg) 发送消息。
    • sendMessageAtTime(Message msg,long updateMillis) 在指定时间点发送消息。
    • sendMessageDelayed(Message, long delayMillis) 在延迟一段时间后发送消息。
    • sendMessageAtFrontOfQueue(Message msg) 将message放在消息队列的最前面发送。
      sendMessage方法与post方法最后执行handleMessage方法或执行runnable的线程就是Handler的创建线程。
    取消任务
    • removeCallbacks(Runnable r) 移除当前消息队列中runnable == r的消息。
    • removeCallbacks(Runnable r ,Object token) 移除当前消息队列中target == handler,runnable == r,Object == token 的消息。
    • removeMessages(int what) 取消所有标识为what的消息。
    • removeMessages(int what ,Object token) 取消含有token对象的被what标识的消息。
    • removeCallbacksAndMessages(Object token) 取消含有token的全部消息。

    有关Handler常用类,四个组成部分

    1. Message:消息,被传递和处理的数据。其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
           Message作为传递的消息与Handler密不可分,所以此处我们稍微展开讲解一下Message属性与获得方式:
           Message的属性):
      • public int what 传递的消息执行标识,用于标记不同的消息。
      • public int arg1 类似与bundle来进行携带int类型的数据。
      • public int arg2 如果一个arg1还不够用再来个arg2。
      • public Object object 任意对象传递容器。类似于bundle,用于跨进程专递对象
      • Runnable callback 执行的runnable对象。
      • long when 发送的时机。
      • Handler target 所依附的handler,可以理解为通过这个target,这个消息会找到它该去的地方,然后执行对消息的操作也就是handleMessage方法。
             Message的获得(通常使用Message.obtain()或Handler.obtainMessage()方法来从消息池中获得空消息对象,以节省资源):
      • Message msg0 = new Message();
      • Message msg1 = Message.obtain();
      • public static Message obtain(Handler h)
      • public static Message obtain(Handler h, int what)
      • public static Message obtain(Handler h, int what, Object obj)
      • public static Message obtain(Handler h, int what, int arg1, int arg2)
      • public static Message obtain(Handler h, int what, int arg1, int arg2, Object obj) 参数1:targetHandler,参数2:what标识符,参数3:int型数据,参数4:int型数据,参数5:Object对象。
      • public static Message obtain(Message orig) 相当于拷贝某个Message而获得Message。
      • public static Message obtain(Handler h,Runnable callback) 传入targetHandler与需要回调执行的runnable。
    2. Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。Handler类的主要作用:(有两个主要作用)
      a. 在工作线程中发送消息;
      b. 在主线程中获取、并处理消息。
    3. MessageQueue:消息队列,本质是一个数据结构,用来存放Handler发送过来的消息,并按照FIFO规则(先进先出)执行。当然,存放Message并非实际意义的保存,而是将Message串联起来,等待Looper的抽取。
    4. Looper:消息泵或循环器,不断从MessageQueue中抽取Message。因此,一个MessageQueue需要一个Looper。
    5. Thread:线程,负责调度整个消息循环,即消息循环的执行场所。
      Handler简易关系.png
           此处我们画一个简易图来逐步了解Handler的运行机制。图中Handler(左右两个handler为同一个handler)可以与MessageQueue以及Looper在同线程中,也可在不同线程中。

    Handler进程间切换举例

         到这里,我想我们脑中有了一个对Handler大致的理解,渐渐的看清了它的样子,那么接下来,我们来写一些代码,来看看handler究竟是怎样运行,工作的。

    主线程创建handler

         为了节约版面,我们不列举每一种方法,只举例有代表性的方法,其他的都会提交到我的github中Handler传送门,大家有需要可以去下载研究。
    * 我们先在主线程中创建handler而在非主线程中来调用post(Runnable r),观察是否最后runnable运行的线程为主线程(代码段中post(View v)方法为button点击调用函数)。

    public void post(View v) {
            Log.e("tag", " ------>>> " + "点击Post按钮 " + getThreadName());
            // 在主线程创建handler
            final Handler handler = new Handler();
            // 创建一个非主线程的新线程
            Thread thread = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            Log.e("tag", " ------>>> " + "执行非主线程runnable " + getThreadName());
                            // 此处可以进行一些耗时操作,比如加载网络图片或读写文件等操作。
                            // handler.post(runnable) 去观察是否回到主线程
                            handler.post(
                                    new Runnable() {
                                        @Override
                                        public void run() {
                                            Log.e("tag", " ------>>> " + "post runnable" + getThreadName());
                                        }
                                    }
                            );
                        }
                    }
            );
            // 运行该线程
            thread.start();
        }

         运行结果:

    05-29 14:58:54.234 6268-6268/com.perry.handler E/tag:  ------>>> 点击Post按钮  主线程 
    05-29 14:58:54.238 6268-6320/com.perry.handler E/tag:  ------>>> 执行非主线程runnable  非主线程 
    05-29 14:58:54.253 6268-6268/com.perry.handler E/tag:  ------>>> post runnable 主线程 

         可以看到我们的handler成功的完成了线程间切换的任务,将需要执行的runnable在非主线程进行耗时操作后回到handler所创建的线程也就是主线程运行。
    * 再来看一下sendMessage(Message msg)方法,后执行handleMessage(Message msg)方法的方法体,是否完成了线程间切换。

     public void sendMessage(View view) {
            Log.e("tag", " ------>>> " + "点击sendMessage按钮 " + getThreadName());
            final Handler handler = new Handler() {
                // 此处处理msg需要覆写该方法
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    switch (msg.what) {
                        case 0:
                            Log.e("tag", " ------>>> " + "sendMessage" + getThreadName() + " 参数 = " + msg.obj);
                            break;
                    }
    
                }
            };
            // 创建一个非主线程的新线程
            Thread thread = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            Log.e("tag", " ------>>> " + "执行非主线程runnable " + getThreadName());
                            // handler.sendMessage(msg) 去观察是否回到主线程
                            handler.sendMessage(Message.obtain(handler, 0, "obj参数"));
                        }
                    }
            );
            // 运行该线程
            thread.start();
        }

         运行结果:

    05-29 15:08:53.077 6682-6682/com.perry.handler E/tag:  ------>>> 点击sendMessage按钮  主线程 
    05-29 15:08:53.078 6682-6729/com.perry.handler E/tag:  ------>>> 在非主线程执行 handler.sendMessage(msg)  非主线程 
    05-29 15:08:53.096 6682-6682/com.perry.handler E/tag:  ------>>> sendMessage 参数 = obj参数 主线程 

         可以看到我们的sendMessage(Message msg)方法也成功的完成了线程间切换的任务,将需要执行的对msg的操作在非主线程进行耗时操作后回到主线程运行handleMessage(msg)的方法体。
    * 之前说过如果发送的是runnable则会忽略掉handleMessage方法的执行,即使是发送含有runnable的Message则也会忽略掉handleMessage方法的执行,那么来证明一下。

    public void sendMessageCallback(View view) {
            Log.e("tag", " ------>>> " + "点击sendMessageCallback按钮 ");
            final Handler handler = new Handler() {
                // 此处处理msg需要覆写该方法
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    // handleMessage 执行方法体
                    Log.e("tag", " ------>>> " + "sendMessage  handleMessage");
                }
            };
            // 发送一个Message
            handler.sendMessage(
                    // 创建含有Runnable callback的msg
                    Message.obtain(
                            handler,
                            new Runnable() {
                                @Override
                                public void run() {
                                    // callback 执行方法体
                                    Log.e("tag", " ------>>> " + "sendMessage  Runnable");
                                }
                            }
    
                    )
            );
        }
        // 执行结果
    05-31 14:36:54.975 2083-2083/com.perry.handler E/tag:  ------>>> 点击sendMessageCallback按钮 
    05-31 14:36:54.992 2083-2083/com.perry.handler E/tag:  ------>>> sendMessage  Runnable

         为了看的更清晰,这里去掉了线程的切换与打印,都是在主线程里发送和接收的消息,我们最终发现,执行了runnable的方法体,未执行handleMessage的方法体,所以只要有runnable的存在就会忽略handleMessage方法体的执行
         说到这为止,我们都是从ui线程创建handler最后返回ui线程执行,那如果我们不想在ui线程执行呢?怎么办?

    后台线程创建handler

         前面在介绍handler时由一句话sendMessage方法与post方法最后执行handleMessage方法或执行runnable的线程就是Handler的创建线程。所以先写一个在后台创建的handler试试水,看看会不会如我们期待一样,回到后台线程执行。

    public void postBackgroundThread(View view) {
            Log.e("tag", " ------>>> " + "点击postBackgroundThread按钮 " + getThreadName());
            Thread thread = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            Log.e("tag", " ------>>> " + "执行非主线程runnable " + getThreadName());
                            Handler handler = new Handler();
                            handler.post(
                                    new Runnable() {
                                        @Override
                                        public void run() {
                                             Log.e("tag", " ------>>> " +"postBackgroundThread " + getThreadName());
                                        }
                                    }
                            );
                        }
                    }
            );
            thread.start();
        }

         运行一下,结果发现,程序崩溃,讲道理我们就是在非UI线程创建了个handler然后post了一下,为什么会崩溃呢?日志如下:

    05-30 15:26:07.446 711-711/com.perry.handler E/tag:  ------>>> 点击postBackgroundThread按钮  主线程 
    05-30 15:26:07.486 711-773/com.perry.handler E/tag:  ------>>> 执行非主线程runnable  非主线程 
    05-30 15:26:07.490 711-773/com.perry.handler E/AndroidRuntime: FATAL EXCEPTION: Thread-18868
                                                                   Process: com.perry.handler, PID: 711
                                                                   java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
                                                                       at android.os.Handler.<init>(Handler.java:209)
                                                                       at android.os.Handler.<init>(Handler.java:123)
                                                                       at com.perry.handler.OnBackgroundActivity$2.run(OnBackgroundActivity.java:71)
                                                                       at java.lang.Thread.run(Thread.java:818)
    

         到这里,我们可以清楚的看到,不能在非主线程中创建handler时不调用Looper.prepare()方法。接下来,就看看,如何正确的在非主线程中创建handler。
         1.手动进行Looper.prepare()及Looper.loop()操作。

    public void postNoCrash(View view) {
            Log.e("tag", " ------>>> " + "点击postNoCrash按钮 " + getThreadName());
            Thread thread = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            Log.e("tag", " ------>>> " + "执行非主线程runnable " + getThreadName());
                            Looper.prepare();
    
                            Handler handler = new Handler();
                            handler.post(
                                    new Runnable() {
                                        @Override
                                        public void run() {
                                            Log.e("tag", " ------>>> " + "postNoCrash " + getThreadName());
                                            // 使用后需要退出looper避免线程阻塞
                                            Looper.myLooper().quit();
                                        }
                                    }
                            );
    
                            Looper.loop();
                        }
                    }
            );
            thread.start();
        }
        // 执行Log日志
    05-30 16:40:14.660 6368-6368/com.perry.handler E/tag:  ------>>> 点击postNoCrash按钮  主线程 
    05-30 16:40:14.672 6368-6426/com.perry.handler E/tag:  ------>>> 执行非主线程runnable  非主线程 
    05-30 16:40:14.694 6368-6368/com.perry.handler E/tag:  ------>>> postNoCrash  非主线程 

         2.利用HandlerThread类进行创建。HandlerThread继承Thread,它会启动一个带有looper的新线程,这样我们就可以在非UI线程中创建handler,但是必须要调用start()方法。

    public void handleThread(View view) {
            final HandlerThread handlerThread = new HandlerThread("HandlerThread");
            handlerThread.start();
            Log.e("tag", " ------>>> " + "点击handleThread按钮 " + getThreadName());
            Thread thread = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            Log.e("tag", " ------>>> " + "执行非主线程runnable " + getThreadName());
                            Handler handler = new Handler(handlerThread.getLooper());
                            handler.post(
                                    new Runnable() {
                                        @Override
                                        public void run() {
                                            Log.e("tag", " ------>>> " +"handleThread " + getThreadName());
                                        }
                                    }
                            );
                        }
                    }
            );
            thread.start();
    
        }
        // 执行Log日志
    05-30 16:40:23.301 6368-6368/com.perry.handler E/tag:  ------>>> 点击handleThread按钮  主线程 
    05-30 16:40:23.311 6368-6428/com.perry.handler E/tag:  ------>>> 执行非主线程runnable  非主线程 
    05-30 16:40:23.323 6368-6368/com.perry.handler E/tag:  ------>>> handleThread  非主线程 

         我们的handler的线程间切换的方法介绍的差不多了,无论是在主线程还是在非主线程中进行线程间切换,而且也印证了我们那句话sendMessage方法与post方法最后执行handleMessage方法或执行runnable的线程就是Handler的创建线程。但是还有一个小东西我们要介绍一下,就是MessageQueue的IdleHandler()接口。

    IdleHandler()接口

         该接口的用途是MessageQueue通过实现该方法,将queueIdle()方法的方法体,添加到消息队列里面去,而不使用handler就可以实现。

     public void idleHandler(View view) {
            Log.e("tag", " ------>>> " + "点击idleHandler按钮 " + getThreadName());
            Looper.myQueue().addIdleHandler(
                    new MessageQueue.IdleHandler() {
                        @Override
                        public boolean queueIdle() {
                            Log.e("tag", " ------>>> " + "执行非主线程runnable " + getThreadName());
                            try {
                                Thread.sleep(2000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            Log.e("tag", " ------>>> " + "idleHandler " + System.currentTimeMillis());
                            makeToast("IdleHandler " + getThreadName());
                            return false;
                        }
                    }
            );
        }

         IdleHandler()是在消息队列空闲的时候,也就是说所有的其他消息是需要延时执行时,会执行该方法的方法体。返回值为false时则在空闲的时候会执行一次该方法体,执行一次后不会再执行,而返回true时,若执行一次后,消息队列依旧空闲则还会再执行该方法体。IdleHandler()是在消息队列空闲的时候执行的,所以在当IdleHandler()执行之后的方法,比如是在1s延迟后执行,但是IdleHandler()在这段时间内被执行了而需要耗时2s,则它之后的消息要在2s之后才执行而不是原有的1s之后执行。所以,在IdleHandler()方法中不要做太耗时的操作。
         为了举例证明,IdleHandler()是在消息队列空闲的时候执行的,我们这里先点击了sendMessageDelayed按钮延时1s进行打印log,然后马上点击了idleHandler按钮其中做了2s线程休眠,对比一下执行时间log,结果如下:(想要自己手动实验的小伙伴Handler传送门送给你,可以给我个小星星!)

    05-30 17:05:20.344 9685-9685/com.perry.handler E/tag:  ------>>> 点击sendMessageDelayed按钮 1527671120344
    05-30 17:05:20.828 9685-9685/com.perry.handler E/tag:  ------>>> 点击idleHandler按钮  主线程 
    05-30 17:05:20.836 9685-9685/com.perry.handler E/tag:  ------>>> 执行非主线程runnable  主线程 
    05-30 17:05:22.881 9685-9685/com.perry.handler E/tag:  ------>>> IdleHandler  主线程 
    05-30 17:05:22.881 9685-9685/com.perry.handler E/tag:  ------>>> idleHandler 1527671122881
    05-30 17:05:22.885 9685-9685/com.perry.handler I/Choreographer: Skipped 121 frames!  The application may be doing too much work on its main thread.
    05-30 17:05:22.923 9685-9685/com.perry.handler E/tag:  ------>>> sendMessageDelayed 参数 = obj参数 主线程 
    05-30 17:05:22.923 9685-9685/com.perry.handler E/tag:  ------>>> sendMessageDelayed方法体执行 1527671122923
    取消任务

         如何发送消息我们都列举完了,接下来我们来取消任务。

    public void removeCallbacks(View view) {
            Log.e("tag", " ------>>> " + "removeCallbacks按钮 " + getThreadName());
            Handler handler = new Handler();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    Log.e("tag", " ------>>> " + "postDelayed removeCallbacks " + getThreadName());
                }
            };
            handler.postDelayed(runnable, 1000);
            handler.removeCallbacks(runnable);
        }
    
        // log日志
        05-31 11:27:18.791 25879-25879/com.perry.handler E/tag:  ------>>> removeCallbacks按钮  主线程

         这里点击按钮后只显示了一个点击removeCallbacks按钮的log,即使再等了10s也仍未见到runnable中的log日志,成功的移除了该runnable任务。而其他的remove方法也都大同小异,不过是更详细的定位了,到底是哪个runnable或Message,想了解的小伙伴请看Handler传送门

    退出Looper

         后台线程不需要的时候,这时后台looper我们也不需要了,或者说我们在某个事件后或某个时间点不需要后续的消息进行发送到消息队列中或执行消息,我们可以通过handlerThread.quit()方法或handlerThread.quitSafely(),方法来退出looper。

    public void handlerThreadQuit(View view) {
            Log.e("tag", " ------>>> " + "handlerThreadQuit按钮 " + getThreadName() + System.currentTimeMillis());
            final HandlerThread handlerThread = new HandlerThread("HandlerThread");
            handlerThread.start();
            final Handler handler = new Handler(handlerThread.getLooper());
            Thread t = new Thread(
                    new Runnable() {
                        @Override
                        public void run() {
                            // 首先延迟1s发送一条消息
                            handler.postDelayed(
                                    new Runnable() {
                                        @Override
                                        public void run() {
                                            makeToast("postDelayed 1s runnable");
                                        }
                                    }, 1000
                            );
    
                            // handler执行runnable进行退出looper
                            handler.post(
                                    new Runnable() {
                                        @Override
                                        public void run() {
                                            handlerThread.quit();
                                            makeToast("HandlerThread Loop quit");
                                        }
                                    }
                            );
                        }
                    }
            );
            t.start();
        }

         quit方法执行后handler将不再接收和执行任何消息,而quitSafely执行后,会先看消息是否过线,如图Handler简易关系.png中消息是否可派发分割线,不可派发为未过线,可派发为过线,过线的消息则可继续执行,未过线的消息则不可执行。且执行quitSafely方法需要在API18以上。

    自定义Handler

         写了这么多但回头一看发现,很多方法内部报黄。原来是因为handler内部持有外部类的引用,造成内存无法释放而泄漏。那如何解决呢?这就需要我们来自定义Handler了。
    image.png
         此处我们只要用弱引用,引用我们所需要的资源,就不会发生泄漏了,具体代码见Handler传送门,记住界面销毁要适时的取消任务哦!
    image.png
         在平时的使用中,只要你认真的看过了这篇文章并动手稍加实践,那一定可以很好的掌握handler的原理及用法,若想要深入学习了解,就需要去分析handler的源码,也就是我的下一篇文章handler源码分析。
         下一篇:Handler源码分析。

    展开全文
  • URL的组成部分

    千次阅读 2017-09-30 14:16:53
    URL 的组成部分URL(统一资源定位符)是 URI(通用资源标识)的特定类型。URL 通常在因特网上查找现有资源。当 Web 客户机向服务器发出对资源的请求时,使用 URL。URI 和 URL 的概念由因特网协会和 IETF(因特网工程...

    URL 的组成部分

    URL(统一资源定位符)是 URI(通用资源标识)的特定类型。URL 通常在因特网上查找现有资源。当 Web 客户机向服务器发出对资源的请求时,使用 URL。

    URI 和 URL 的概念由因特网协会和 IETF(因特网工程任务组织)请求评论文档 RFC 2396 统一资源标识(URI):一般语法定义(http://www.ietf.org/rfc/rfc2396.txt)。简要地说,URI 是定义为识别资源的任何一个字符串。URL 定义为按资源的位置或 用户访问它的方式,而不是按资源的名称或其他属性来识别资源的那些 URI。
    HTTP(HTTPS)的 URL 通常由三或四个组成部分组成:

    规则。规则识别用于访问因特网上的资源的协议。它可以是 HTTP(不带 SSL)或 HTTPS(带 SSL)。
    主机。主机名识别拥有资源的主机。例如,www.example.com。服务器在主机的名称中提供服务,但主机和服务器之间没有一对一映射。主机名说明关于主机名的更多信息。
    
    主机名也可以后跟端口号。端口号说明关于这方面的更多内容。通常从 URL 省略服务的常用端口号。因为多数服务器将熟知端口号用于 HTTP 和 HTTPS,所以多数 HTTP URL 省略端口号。
    路径。路径识别主机中 Web 客户机要访问的特定资源。例如,/software/htp/cics/index.html。
    查询字符串。如果使用查询字符串,那么它跟随路径部分,并且提供一串字符串,资源使用这些字符串可以完成某些操作(例如,作为用于搜索的参数或用于处理的数据)。 查询字符串通常是一串名称和值对,例如,q=bluebird。
    

    URL 的规则和主机部分不定义为区分大小写,但是路径和查询字符串是区分大小写的。通常,整个 URL 指定为小写字母。
    URL 的组成部分如下所示进行组合和定界:

    scheme://host:port/path?query

    规则后跟冒号和两个正斜杠。
    如果指定端口号,那么主机名后面是号码,并用冒号分隔。
    路径名以单正斜杠开始。
    如果指定查询字符串,那么在它的前面加个问号。
    

    图 1. HTTP URL 语法

    阅读语法图跳过直观语法图
    .-:80—–.

    -http://–+-host name–+–+———+–/–path component——>
    ‘-IP address-’ ‘-:–port-’

    –+—————–+—————————————–><
    ‘-?–query string-’

    这是 HTTP URL 的示例:

    http://www.example.com/software/index.html

    如果指定了端口号,那么 URL 为:

    http://www.example.com:1030/software/index.html

    URL 的后面可以跟片段标识。URL 与片段标识之间使用的分隔符是字符 #。 片段标识用于使 Web 浏览器指向它刚检索的项中的引用或函数。 例如,如果 URL 标识 HTML 页面,那么可使用片段标识,以子节的标识来指示页面中的子节。对于这种情况,Web 浏览器通常向用户显示页面, 以使用户可以看到子节。根据项的介质类型以及为该介质类型的片段标识所定义含义的不同,Web 浏览器为片段标识所采取的操作也会不同。

    其他协议(如文件传输协议(FTP)或 Gopher)也使用 URL。这些协议使用的 URL 可能与 HTTP 使用的 URL 的语法不同。

    展开全文
  • ios的四个核心部分介绍

    千次阅读 2012-07-16 16:48:27
    ios四个核心部分 1.Cocoa Touch Cocoa Touch层的关键技术。 (1)多任务  iOS SDK 4.0以及以后的SDK构建的程序(且运行在iOS 4.0和以后版本的设备上),用户按下Home按钮的时候程序不会结束;它们会挪到后台...

    ios四个核心部分

    ios的四个核心部分介绍

    1.Cocoa Touch
    Cocoa Touch层的关键技术。
    (1)多任务
          iOS SDK 4.0以及以后的SDK构建的程序(且运行在iOS 4.0和以后版本的设备上),用户按下Home按钮的时候程序不会结束;它们会挪到后台运行。UIKit帮助实现的多任务支持,让程序可以平滑切换到后台,或者切换回来。
    为了节省电力,大多数程序进入后台后马上就会被系统暂停。暂停的程序还在内存里,但是不执行任何代码。这样程序需要重新激活的时候可以快速恢复,但是同时不浪费任何电力。然而,在如下原因下,程序也可以在后台下运行:
    程序可以申请有限的时间完成一些重要的任务。
    程序可以声明支持某种特定的服务,需要周期的后台运行时间。
    程序可以使用本地通知在指定的时间给用户发信息,不管程序是否在运行。
    不管你的程序在后台是被暂停还是继续运行,支持多任务都不需要你做什么额外的事情。系统会在切换到后台或者切换回来的时候,通知程序。在这个时刻,程序可以直接执行一些重要的任务,例如保存用户数据等。
     
    (2)打印
        从iOS 4.2开始,UIKit引入了打印支持,允许程序把内容通过无线网路发送给附近的打印机。关于打印,大部分重体力劳动由UIKit承担。它管理打印接口,和你的程序协作渲染打印的内容,管理打印机里打印作业的计划和执行。
    程序提交的打印作业会被传递给打印系统,它管理真正的打印流程。设备上所有程序的打印作业会被排成队列,先入先出的打印。用户可以从打印中心程序看到打印作业的状态。所有这些打印细节都由系统自动处理。
    注意:仅有支持多任务的设备才支持无线打印。你的程序可使用 UIPrintInteractionController对象来检测设备是否支持无线打印。
     
    (3)数据保护
         iOS4.0起引入了数据保护功能,需要处理敏感用户数据的应用程序可以使用某些设备 内建的加密功能(某些设备不支持)。当程序指定某文件受保护的时候,系统就会把这个文件用加密的格式保存起来。设备锁定的时候,你的程序和潜在入侵者都无法访问这些数据。然而,当设备由用户解锁后,会生成一个密钥让你的程序访问文件。
    要实现良好的数据保护,需要仔细考虑如何创建和管理你需要保护的数据。应用程序必须在数据创建时确保数据安全,并适应设备上锁与否带来的文件可访问性的变化。
     
    (4)苹果推通知服务
       从iOS 3.0开始,苹果发布了苹果推通知服务,这一服务提供了一种机制,即使你的程序已经退出,仍旧可以发送一些新信息给用户。使用这种服务,你可以在任何时候,推送文本通知给用户的设备,可以包含程序图标作为标识,发出提示声音。这些消息提示用户,应该打开你的程序接收查看相关的信息。
    从设计的角度看,要让iOS程序可以发送推通知,需要两部分的工作。首先,程序必须请求通知的发送,且在送达的时候能够处理通知数据。然后,你需要提供一个服务端流程去生成这些通知。这一流程发生在你自己的服务器上,和苹果的推通知服务一起触发通知。
     
    (5)本地通知
        从iOS 4.0开始,苹果推出了本地通知,作为推通知机制的补充,应用程序使用这一方法可以在本地创建通知信息,而不用依赖一个外部的服务器。运行在后台的程序,可以在重要时间发生的时候利用本地通知提醒用户注意。例如,一个运行在后台的导航程序可以利用本地通知,提示用户该转弯了。程序还可以预定在未来的某个时刻发送本地通知,这种通知即使程序已经被终止也是可以被发送的。
    本地通知的优势在于它独立与你的程序。一旦通知被预定,系统就会来管理它的发送。在消息发送的时候,甚至不需要应用程序还在运行。
     
    (6)手势识别器
        从iOS 3.2起,引入了手势识别器,你可以把它附加到view上,然后用它们检测通用的手势,如划过或者捏合。附加手势识别器到view后,设置手势发生时执行什么操作。手势识别器会跟踪原始的触摸事件,使用系统预置的算法判断目前的手势。没有手势识别器,你就必须自己做这些计算,很多都相当的复杂。
    UIKit包含了UIGestureRecognizer 类,定义了所有手势识别器的标准行为。你可以定义自己的定制手势识别器子类,或者是使用UIKit提供的手势识别器子类来处理如下的标准手势:
    点击(任何次数)
    捏合缩放
    平移或者拖动
    划过(任何方向)
    旋转(手指分别向相反方向)
    长按
     
    (7)文件共享支持
        文件共享支持是从iOS 3.2开始引入的,利用它程序可以把用户的数据文件开发给iTunes 9.1以及以后版本。程序一旦声明支持文件共享,那么它的/Documents目录下的文件就会开放给用户。用户可以用iTunes放文件进去,或者取出来。这一特性并不允许你的程序和同一设备里面的其他程序共享文件;那种行为需要用剪贴板,或者文本交互控制对象(UIDocumentInteractionController)来实现。
    要打开文件共享支持,请:
    在程序的Info.plist文件内加入键UIFileSharingEnabled,值设置为YES。
    把你要共享的文件放在程序的Documents目录内。
    设备插到用户电脑时,iTunes在选定设备的程序页下面显示文件共享块。
    用户可以在桌面上增加和删除文件。
    支持文件共享的程序必须能够识别放到Documents目录内的文件,并正确的处理它们。例如,程序应该用自己的界面显示新出现的文件,而不是把这些文件列在目录里,问用户该如何处理这些文件。
     
    (8)点对点对战服务
        从iOS 3.0起引入的Game Kit框架提供了基于蓝牙的点对点对战功能。你可以使用点对点连接和附近的设备建立通讯,是实现很多多人游戏中需要的特性。虽然这主要是用于游戏的,但是也可以用于其他类型的程序中。
    更多关于如何在程序中使用点对点对战功能的信息,参标准系统View Controller
    Cocoa Touch层的很多框架提供了用来展现标准系统接口的View Controller。你应该尽量使用这些View Controller,以保持用户体验的一致性。任何时候你需要做如下操作的时候,你都应该用对应框架提供的View Controller:
    显示和编辑联系人信息 - 使用Address Book UI框架提供的View Controller。
    创建和编辑日历事件 - 使用Event Kit UI框架提供的View Controller。
    编写email或者短消息 - 使用Message UI框架提供的View Controller。
    打开或者预览文件的内容 - 使用UIKit框架里的UIDocumentInteractionController类。
    拍摄一张照片,或者从用户的照片库里面选择一张照片 - 使用UIKit框架内的UIImagePickerController类。
    拍摄一段视频 - 使用UIKit框架内的UIImagePickerController类。
     
    (9)外部显示支持
           iOS 3.2开始,引入了外部显示支持,允许一些iOS设备可以通过支持的缆线连接到外部的显示器上。连接时,程序可以用对应的屏幕来显示内容。屏幕的信息,包括它支持的分辨率,都可以用UIKit框架提供的接口访问。你也可以用这个框架来把程序的窗口连接到一个屏幕,或另外一个屏幕。
     
    (10)Cocoa Touch框架
       下面的章节介绍Cocoa Touch层的框架和它们提供的服务。
      *Address Book UI框架
         Address Book UI框架(AddressBookUI.framework)是一个Objective-C的编程接口,用来显示创建新联系人、编辑和选择已有联系人的标准系统界面。这个框架让你可以轻松的在程序里面显示联系人信息,同时确保你的程序使用和其他程序一样的接口,保持了平台的一致性。
     
      *Event Kit UI框架
       从iOS 4.0开始,引入了Event Kit UI框架(EventKitUI.framework)提供了用来显示和编辑事件的view controller。这个框架基于Event Kit框架提供的事件相关数据结构,参见Event Kit框架。
     
       *Game Kit框架
          iOS 3.0引入了Game Kit框架(GameKit.framework)支持在程序中进行点对点的网络通讯。尤其是这个框架支持了点对点的连接和游戏内的语音通话功能。虽然这些功能主要是用于多人对战网络游戏,但是也可以在非游戏程序中使用。这个框架提供的网络功能是构建在Bonjour之上几个简单的类实现的。这些类抽象了很多网络细节,让没有网络编程经验的开发者也可以轻松地在程序中加入网路功能。
     
       *iAd框架
           iOS 4.0引入了iAd框架(iAd.framework)支持程序中显示banner广告。广告由标准的view构成,你可以把它们插入到你的用户界面中,恰当的时候显示。View本身和苹果的广告服务通讯,处理一切载入和展现广告内容以及响应点击等工作。
     
       *Map Kit框架
           iOS 3.0引入了Map Kit框架(MapKit.framework)提供了一个可以嵌入到程序里的地图接口。基于该接口的行为,它提供了可缩放的地图view,可标记定制的信息。你可以把它嵌入在程序的view里面,编程设置地图的属性,保存当前显示的地图区域和用户的位置。你还可以定义定制标记,或者使用标准标记(大头针标记),突出地图上的区域,显示额外的信息。
    从iOS 4.0开始,这个框架加入可拖动标记和定制覆盖对象的功能。可拖动标记令你可以移动一个已经被放置到地图上的标记,编程,也可以通过用户行为。覆盖对象提供了创建比标记点更复杂的地图标记的能力。你可以使用覆盖对象在地图上来放置信息,例如公交路线,选区图,停车区域,天气信息(如雷达数据)。
     
       *Message UI框架
          iOS 3.0引入了Message UI框架(MessageUI.framewok)提供了编写和查询发建箱消息的能力。编写支持包含了一个可以在程序中显示的view controller接口。你可以在接口中填写你要发送信息的内容。你可以设置收信人,主题和内容,以及附件。用户可以选择信息的优先级。选定后,信息就会在用户的发件箱里面排队等待发送。
    iOS 4.0和以后的系统,这个框架开始支持用来编写短消息的view controller。你可以使用这种view controller来创建和编辑短消息,而不用离开程序。和邮件编写接口一样,这个接口让用户选择发送前是否编辑一下。
     
    2.Media
    Media层提供了图片,音乐,影片等多媒体功能。图像分为2D图像和3D图像, 前者由Quartz2D来支持,后者则是用OpenglES.与音乐对应的模组是Core Audio和OpenAL, Media Player 实现了影片的播放, 而最后还提供了Core Animation来对强大动画的支持。具体介绍如下:
    (1)图像技术(Graphics Technologies)
       高质量图像是所有iPhone应用的一个重要的组成部分。任何时候,开发者可以采用UIKit 框架中已有的视图和功能以及预定义的图像来开发iPhone应用。然而,当UIKit 框架中的视图和功能不能满足需求时,开发者可以应用下面描述的技术和方法来制作视图。
       ① Quartz。核心图像框架(CoreGraphics.framework)包含了Quartz 2D画图API,Quartz与在Mac OS中采用的矢量图画引擎是一样先进的。Quartz支持基于路径(Path-based)画图、抗混淆(Anti-aliased)重载、梯度 (Gradients)、图像(Images)、颜色(Colors)、坐标空间转换(Coordinate-space Transformations)、pdf文档创建、显示和解析。虽然API是基于C语言的,它采用基于对象的抽象表征基础画图对象,使得图像内容易于保存和复用。
       ② 核心动画(Core Animation)。Quartz核心框架(QuartzCore.framework)包含CoreAnimation接口,Core Animation是一种高级动画和合成技术,它用优化的重载路径(Rendering Path)实现复杂的动画和虚拟效果。它用一种高层的Objective-C接口配置动画和效果,然后重载在硬件上获得较好的性能。Core Animation集成到iPhone OS 的许多部分,包括UIKit类如UIView,提供许多标准系统行为的动画。开发者也能利用这个框架中的Objective-C接口创建客户化的动画。
       ③ OpenGL ES。OpenGL ES框架(OpenGLES.framework)符合OpenGL ES v1.1规范,它提供了一种绘画2D和3D内容的工具。OpenGL ES 框架是基于C语言的框架,与硬件设备紧密相关,为全屏游戏类应用提供高帧率(high frame rates)。开发者总是要使用OpenGL框架的EAGL接口,EAGL接口是OpenGL ES框架的一部分,它提供了应用的OpenGL ES画图代码和本地窗口对象的接口。
     (2)音频技术(Audio Technologies)
         iPhone OS的音频技术为用户提供了丰富的音频体验。它包括音频回放,高质量的录音和触发设备的振动功能等。iPhone OS的音频技术支持如下音频格式:AAC、Apple Lossless(ALAC)、A-law、IMA/ADPCM(IMA4)、Linear PCM、μ-law和Core Audio等。
        ① 核心音频(Core Audio Family)。核心音频框架家族(Core Audio family of frameworks)提供了音频的本地支持,如表16-1所示。Core Audio是一个基于C语言的接口,并支持立体声(Stereo Audio)。开发能采用iPhone OS 的Core Audio框架在iPhone 应用中产生、录制、混合和播放音频。开发者也能通过核心音频访问手机设备的振动功能。
    核心音频框架:
    框架(Framework)            服务(Service)
    CoreAudio.framework         定义核心音频的音频数据类型
    AudioUnit.framework            提供音频和流媒体文件的回放和录制,并且管理音
                                                 频文件和播放提示声音
    AudioToolbox.framework    提供使用内置音频单元服务,音频处理模块
         ② OpenAL。iPhone OS 也支持开放音频库(Open Audio Library, OpenAL)。OpenAL是一个跨平台的标准,它能传递位置音频(Positional Audio)。开发者能应用OpenAL在需要位置音频输出的游戏或其他应用中实现高性能、高质量的音频。由于OpenAL是一个跨平台的标准,采用OpenAL的代码模块可以平滑地移植到其他平台。
    (3)视频技术(Video Technologies)
        iPhone OS通过媒体播放框架(MediaPlayer.framework)支持全屏视频回放。媒体播放框架支持的视频文件格式包括.mov, .mp4,.m4v和.3gp,并应用如下压缩标准:
        ① H.264 Baseline Profile Level 3.0 video,在30 f/s 的情况下分辨率达到640×480像素。注意:不支持B frames;
        ② MPEG4规范的视频部分;
        ③ 众多的音频格式,包含在音频技术的列表里,如AAC、Apple Lossless (ALAC)、A-law、IMA/ADPCM(IMA4)、线性PCM、μ-law和Core Audio等。     
     
    3.Core Services
    Core Services在Core OS基础上提供了更为丰富的功能, 它包含了Foundation.Framework和Core Foundation.Framework, 之所以叫Foundation ,就是因为它提供了一系列处理字串,排列,组合,日历,时间等等的基本功能。Foundation是属于Objective-C的API,Core Fundation是属于C的API。另外Core servieces还提供了其他的功能,比如:
        Security, Core Location, SQLite, 和Address Book. 其中Security是用来处理认证,密码管理,按安全性管理的; Core Location是用来处理GPS定位的;SQLLite是轻量级的数据库,而AddressBook则用来处理电话薄资料的。下面是具体介绍:
    (1)电话本
        电话本框架(AddressBook.framework)提供了保存在手机设备中的电话本编程接口。开发者能使用该框架访问和修改存储在用户联系 人数据库里的记录。例如,一个聊天程序可以使用该框架获得可能的联系人列表,启动聊天的进程(Process),并在视图上显示这些联系人信息等。
    (2)核心基础框架
         核心基础框架(CoreFoundation.framework)是基于C语言的接口集,提供iPhone应用的基本数据管理和服务功能。该框架 支持如下功能:
            Collection数据类型(Arrays、 Sets等);
            Bundles;
            字符串管理;
            日期和时间管理;
            原始数据块管理;
            首选项管理;
            URL和Stream操作;
            线程和运行循环(Run Loops);
            端口和Socket通信。
         核心基础框架与基础框架是紧密相关的,它们为相同的基本功能提供了Objective-C接口。如果开发者混合使用Foundation Objects 和Core Foundation类型,就能充分利用存在两个框架中的"toll-free bridging"。toll-free bridging意味着开发者能使用这两个框架中的任何一个的核心基础和基础类型,例如Collection和字符串类型等。每个框架中的类和数据类型的 描述注明该对象是否支持toll-free bridged。如果是,它与哪个对象桥接(toll-free bridged)。
    (3)CFNetwork
        CFNetwork框架(CFNetwork.framework)是一组高性能的C语言接口集,提供网络协议的面向对象的抽象。开发者可以使用 CFNetwork框架操作协议栈,并且可以访问低层的结构如BSD Sockets等。同时,开发者也能简化与FTP和HTTP服务器的通信,或解析DNS等任务。使用CFNetwork框架实现的任务如下所示:
              BSD Sockets;
              利用SSL或TLS创建加密连接;
              解析DNS Hosts;
              解析HTTP协议,鉴别HTTP和HTTPS服务器;
              在FTP服务器工作;
              发布、解析和浏览Bonjour服务。
    (4)核心位置框架(Core Location Framework)
         核心位置框架(CoreLocation.framework)主要获得手机设备当前的经纬度,核心位置框架利用附近的GPS、蜂窝基站或Wi- Fi信号信息测量用户的当前位置。iPhone地图应用使用这个功能在地图上显示用户的当前位置。开发者能融合这个技术到自己的应用中,给用户提供一些位 置信息服务。例如可以提供一个服务:基于用户的当前位置,查找附近的餐馆、商店或设备等。
    (5)安全框架(Security Framework)
         iPhone OS除了内置的安全特性外,还提供了外部安全框架(Security.framework),从而确保应用数据的安全性。该框架提供了管理证书、公钥/私 钥对和信任策略等的接口。它支持产生加密安全的伪随机数,也支持保存在密钥链的证书和密钥。对于用户敏感的数据,它是安全的知识库(Secure Repository)。CommonCrypto接口也支持对称加密、HMAC和数据摘要。在iPhone OS里没有OpenSSL库,但是数据摘要提供的功能在本质上与OpenSSL库提供的功能是一致的。
    (6)SQLite
        iPhone应用中可以嵌入一个小型SQL数据库SQLite,而不需要在远端运行另一个数据库服务器。开发者可以创建本地数据库文件,并管理这些 文件中的表格和记录。数据库SQLite为通用的目的而设计,但仍可以优化为快速访问数据库记录。访问数据库SQLite的头文件位 于<iPhoneSDK>/usr/include/sqlite3.h,其中<iPhoneSDK>是SDK安装的目标路径。
    (7)支持XML
        基础框架提供NSXMLParser类,解析XML文档元素。libXML2库提供操作XML内容的功能,这个开放源代码的库可以快速解析和编辑 XML数据,并且转换XML内容到HTML。访问libXML2库的头文件位于目录<iPhoneSDK>/usr/include /libxml2/,其中<iPhoneSDK>是SDK安装的目标目录。
     
    4.Core OS


    核心服务层为所有应用提供基础系统服务,即使不直接使用这些服务,也应该了解内置在该系统中的技术。


    (1)电话本


    电话本框架(AddressBook.framework)提供了保存在手机设备中的电话本编程接口。开发者能使用该框架访问和修改存储在用户联系人数据库里的记录。例如,一个聊天程序可以使用该框架获得可能的联系人列表,启动聊天的进程(Process),并在视图上显示这些联系人信息等。


    (2)核心基础框架


    核心基础框架(CoreFoundation.framework)是基于C语言的接口集,提供iPhone应用的基本数据管理和服务功能。该框架支持如下功能:


    Collection数据类型(Arrays、 Sets等);


    Bundles;


    字符串管理;


    日期和时间管理;


    原始数据块管理;


    首选项管理;


    URL和Stream操作;


    线程和运行循环(Run Loops);


    端口和Socket通信。


    核心基础框架与基础框架是紧密相关的,它们为相同的基本功能提供了Objective-C接口。如果开发者混合使用Foundation Objects 和Core Foundation类型,就能充分利用存在两个框架中的"toll-free bridging"。toll-free bridging意味着开发者能使用这两个框架中的任何一个的核心基础和基础类型,例如Collection和字符串类型等。每个框架中的类和数据类型的描述注明该对象是否支持toll-free bridged。如果是,它与哪个对象桥接(toll-free bridged)。


    (3)CFNetwork


    CFNetwork框架(CFNetwork.framework)是一组高性能的C语言接口集,提供网络协议的面向对象的抽象。开发者可以使用 CFNetwork框架操作协议栈,并且可以访问低层的结构如BSD Sockets等。同时,开发者也能简化与FTP和HTTP服务器的通信,或解析DNS等任务。使用CFNetwork框架实现的任务如下所示:


    BSD Sockets;


    利用SSL或TLS创建加密连接;


    解析DNS Hosts;


    解析HTTP协议,鉴别HTTP和HTTPS服务器;


    在FTP服务器工作;


    发布、解析和浏览Bonjour服务。


    (4)核心位置框架(Core Location Framework)


    核心位置框架(CoreLocation.framework)主要获得手机设备当前的经纬度,核心位置框架利用附近的GPS、蜂窝基站或Wi- Fi信号信息测量用户的当前位置。iPhone地图应用使用这个功能在地图上显示用户的当前位置。开发者能融合这个技术到自己的应用中,给用户提供一些位置信息服务。例如可以提供一个服务:基于用户的当前位置,查找附近的餐馆、商店或设备等。


    (5)安全框架(Security Framework)


    iPhone OS除了内置的安全特性外,还提供了外部安全框架(Security.framework),从而确保应用数据的安全性。该框架提供了管理证书、公钥/私钥对和信任策略等的接口。它支持产生加密安全的伪随机数,也支持保存在密钥链的证书和密钥。对于用户敏感的数据,它是安全的知识库(Secure Repository)。


    CommonCrypto接口也支持对称加密、HMAC和数据摘要。在iPhone OS里没有OpenSSL库,但是数据摘要提供的功能在本质上与OpenSSL库提供的功能是一致的。


    (6)SQLite


    iPhone应用中可以嵌入一个小型SQL数据库SQLite,而不需要在远端运行另一个数据库服务器。开发者可以创建本地数据库文件,并管理这些文件中的表格和记录。数据库SQLite为通用的目的而设计,但仍可以优化为快速访问数据库记录。访问数据库SQLite的头文件位于<iPhoneSDK>/usr/include/sqlite3.h,其中<iPhoneSDK>是SDK安装的目标路径。


    (7)支持XML
    基础框架提供NSXMLParser类,解析XML文档元素。libXML2库提供操作XML内容的功能,这个开放源代码的库可以快速解析和编辑 XML数据,并且转换XML内容到HTML。访问libXML2库的头文件位于目录<iPhoneSDK>/usr/include /libxml2/,其中<iPhoneSDK>是SDK安装的目标目录。

    展开全文
  • 软件工程之五个层次四个部分

    万次阅读 热门讨论 2013-11-05 21:40:23
    在面向对象技术这一章中,提到了“五个层次”和“四个部分”,对于这两方面以及关系做了一下总结。  首先,说一下“五个层次”。OOA(面向对象的分析)模型由5个层次(主题层、对象类层、结构层、属性层和服务层)...
         在面向对象技术这一章中,提到了“五个层次”和“四个部分”,对于这两方面以及关系做了一下总结。
    

           首先,说一下“五个层次”。OOA面向对象的分析)模型由5个层次(主题层、对象类层、结构层、属性层和服务层)组成。OOA有两个任务,形式地说明我们所面对的应用问题,最终成为软件系统基本构成的对象,还有系统所必须遵从的,由应用环境所决定的规则和约束;明确地规定构成系统的对象如何协同合作,完成指定的功能。

        

    识别类和对象

     

     

    属性层

     

     

    服务层

     

           然后,说一下“四个部分”。OOD(面向对象的设计)模型由4个部分(问题论域部分、人机交互部分、任务管理部分、数据管理部分)组成。

          1、问题论域部分

              执行基本应用功能的对象

              包括与应用问题直接有关的所有类和对象

              在OOD阶段,继续OOA阶段的工作,对OOA中得到的结果改进和增补

          2、人机交互部分

              用于系统的某个特定实现的界面技术

          3、任务管理部分

              指定了那些创建系统时必须建立的操作系统部分

         4、数据管理部分

              主要涉及数据库

              定义了那些与所用数据库技术接口的对象

             下面,说一下这二者之间的关系。OOD继续做OOA阶段的工作,建立软件结构。OOA中的5个层次贯穿在OOD(面向对象的设计)过程中。问题论域部分是继续OOA的工作,是对OOA的细化,对OOA中的某些类、对象、属性的进一步说明;人机交互部分(用户界面设计),OOA已经给出了所需属性和操作,在OOD中进行细节加入到用户界面设计中。

     

    展开全文
  • Linux操作系统的主要组成部分

    千次阅读 2017-08-06 21:20:40
    Linux系统一般有4主要部分:内核、shell、文件系统和应用程序。内核、shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序、管理文件并使用系统。 一.Linux内核 内核是操作系统的核心,...
  • Linux系统一般有4主要部分:内核、shell、文件系统和应用程序。内核、shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序、管理文件并使用系统。 一.Linux内核 内核是操作系统的核心,具有...
  • Linux系统一般有4主要部分:内核、shell、文件系统和应用程序。内核、shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序、管理文件并使用系统。一.Linux内核内核是操作系统的核心,具有很...
  • 计算机组成原理部分知识点

    千次阅读 2019-06-30 21:29:36
    硬布线控制器中,时序信号采用主状态周期-...CPU的基本功能包括四个方面:指令控制、数据加工、操作控制、时间控制。 中断请求不可以中断另一个正在执行的中断处理程序,及时这个中断请求具有更高优先级。 页式虚...
  • 机器人怎样上春晚其实是伪命题,因为机器人终归属于聪明的人类操作着…… 说到机器人就先说说美国耶鲁大学,他们...刚上春晚的广场舞机器人就是基于这类的机器人,那么这样的智能机器人“大妈”又是怎么组成的呢? 机...
  • 机器人主要有哪几部分组成

    万次阅读 2019-02-20 17:07:20
    机器人由机械部分、传感部分和控制部分组成,具体如下: 机械部分 机器人的机械结构系统由机身、手臂、末端操作器三大件组成。每一大件都有若干自由度,构成一多自由度的机械系统。机器人按机械结构划分可...
  • Quartz中用到的设计模式:Builder模式、Factory模式、组件模式、链式模式Quartz组成部分:调度器:scheduler;任务:JobDetail;触发器:Trigger,包括SimpleTrigger和CronTrigger第一Quartz程序实现每隔1...
  • 1、什么是任务 我们设计复杂、大型程序的时候,将这些负责的...UCOSIII就是一可剥夺的多任务系统,我们使用UCOSIII的一重要 的原因就是它的多任务处理能力。 2、UCOSIII中的任务 在UCOSIII中任务就是程序实体...
  • 本文为大家介绍了机器学习中常见的种分类任务。分别是二分类、多类别分类、多标签分类、不平衡分类,并提供了实战代码。 机器学习是一研究领域,其涉及到从示例中学习的算法。 分类是一项需要使用机器学习算法...
  • 物联网由哪层体系结构组成

    千次阅读 2020-09-09 14:24:14
     根据物联网的服务类型和节点等情况,一部分人提出了由感知层、接入层、网络层和应用层组成的物联网层体系结构。  1、感知层  感知层是物联网发展和应用的基础。感知层相当于物联网的皮肤和五官,完成识别...
  • 嵌入式Linux四个软件层次

    千次阅读 2011-10-26 14:10:32
    一个嵌入式Linux系统从软件的角度看通常可以分为四个层次:  1、 引导加载程序。包括固化在固件(firmware)中的boot代码(可选),和BootLoader两大部分。  2、 Linux内核。特定于嵌入式板子的定制内核以及...
  • Scrum敏捷开发流程主要包扩三个角色、四个会议和个三物件。 三个角色 Scrum团队中包括三个角色,他们分别是产品负责人、开发团队和 项目的直接管理者(Scrum Master)。 Scrum 团队是自组织、跨职能的完整...
  • 雷达基本组成及各部分作用

    千次阅读 2020-01-09 10:39:12
    雷达基本组成及各部分作用 第一部 分触发电路(定时器) 每隔一段时产生一尖脉冲,同时送到发射机、接收机、显示器三部分,使它们同步工作。(触发电路决定工作开始的时间) 第二部分 发射系统 触发脉冲到来后,...
  • Activiti6自学之路(七)——个人任务和组任务

    万次阅读 热门讨论 2019-06-16 03:35:26
    Activiti6 任务有个人任务和组任务之分,理解两者的区别...组任务:流程中的某个任务由指定的group来完成,其中group由多user组成 实例分析 1、填写请假申请任务:个人任务,比如张三提交请假申请 2、总监审批任...
  • 云计算技术体系结构由这组成

    千次阅读 2019-04-11 17:05:59
    云计算技术体系结构分为层:物理资源层、资源池层、管理中间件层和SOA构造层。 接下来云容科技就给您仔细分析:物理资源层包括计算机、存储、网络设施、数据库和软件等。资源池层是指将大量相同类型的资源转化为...
  • * 文件名称:任意给出一个四位数, 把它重新组成个四位的最大数和一最小数, 算出两者间的差.  * 作 者: 雷恒鑫 * 完成日期: 2012年03 月10日 * 版 本 号:V1.2  * 对任务及求解方法
  • 计算机视觉四大基本任务(分类、定位、检测、分割)深度学习目前已成为发展最快、最令人兴奋的机器学习领域之一,许多卓有建树的论文已经发表,而且已有很多高质量的开源深度学习框架可供使用。然而,论文通常非常简明...
  • * 程序的版权和版本声明部分 * Copyright (c) 2011, 烟台大学计算机学院学生 * All rights reserved. * 文件名称:编写一控制台应用--分别使用for,while,do-while循环语句计算 n! * 作 者: 雷恒鑫 * ...
  • 章:任务系统这部分主要对任务系统进行设计,游戏的关键因素之一就是任务系统与玩家的交互,但在代码实现中并不算复杂。本篇博客主要通过一下几方面实现任务系统。任务模型的导入与任务UI界面的创建任务的接受...
  • client和jobserver间,以及worker与jobserver间存在通信交互,这两种情况下的通信协议都是由请求包和响应包组成。所有发送到jobserver的包都认为是请求,所有由jobserver发送的包都认为是响应。一种简单的配置例子是...
  • 互联网的组成

    万次阅读 2018-04-23 16:08:37
    1)边缘部分部分由所有连接在互联网上的主机组成。这部分是用户直接使用的,用来进行通信和资源共享。 2)核心部分 由大量网络和连接这些网络的路由器组成。这部分用来为边缘部分提供服务。 二、边缘部分 ...
  • 1 监视任务状态 Hudson提供了丰富的图形化界面,让用户从各方面链接各个人物的当前及历史状态,这包括整体的列表显示、自定义视图、单个任务的具体信息,如构建日志和测试报告...这个页面主要有四个部分组成: 导航菜单
  • 游戏任务系统的设计要素

    千次阅读 2016-11-16 16:32:10
    任务系统的基本流程包括:触发任务、接受任务、进行任务、完成任务,共四个阶段组成。  任务的事件结构就如同记叙文一般,包含其中各方面的要素,即时间、地点、人物、事件、结果等。  时间:何时发生、何时...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 232,227
精华内容 92,890
关键字:

任务的四个组成部分