当前位置:  编程技术>移动开发
本页文章导读:
    ▪Tomcat6推送技术的施用        Tomcat6推送技术的使用       服务器推送技术的基础思想是将浏览器主动查询信息改为服务器主动发送信息,服务器发送一批数据,浏览器显示消息,同时保证与服务器的连接,当服务器需.........
    ▪ Activity札记(5)-Activity生命周期        Activity笔记(5)---Activity生命周期  Android api中提供的Activity生命周期图   创建一个测试项目ActivityLife 在MainActivity.java中 重写onCreate,onStart,onResume,onPause,onStop,onRestart,onDestroy方法   package com.exampl.........
    ▪ storyboard兼容版本处置       storyboard兼容版本处理 //storyboard版本兼容- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 1 UIStoryboard *mainStoryboard = nil; if (SYSTEM_VERSION_GREATER_THAN_OR_E.........

[1]Tomcat6推送技术的施用
    来源: 互联网  发布时间: 2014-02-18
Tomcat6推送技术的使用

      服务器推送技术的基础思想是将浏览器主动查询信息改为服务器主动发送信息,服务器发送一批数据,浏览器显示消息,同时保证与服务器的连接,当服务器需要再一次的发送数据,浏览器显示数据并保持连接。

comet基于HTTP长连接技术,无需安装插件。

 

 

 

  • comet:一个概念,web push
  • pushlet:comet的一个实现。
  • 就是保持长连接的策略问题,有人用jquery写了相应的util

 

  • Pushlet基于HTTP流,这种技术常常用在多媒体视频、通讯应用中,比如QuickTime。与装载HTTP页面之后马上关闭HTTP连接的做法相反,Pushlet采用HTTP流方式将新变动的数据主动地推送到client(客户端),再此期间HTTP连接一直保持打开。有关如何在Java中实现这种Keep-alive的长连接请参看Sun提供的《HTTP Persistent Connection》和W3C的《HTTP1.1规范》

 

  • Tomcat的comet原理其实同样很简单,它无非就是做了一件事情,它允许servlet执行完毕后的response没有被回收,我们只要拿到这个Reponse的引用并保存起来,就可以随时从Server向Client端Push数据了。每个连接一个线程的模型便非常简单。该模型对于 Comet 不大适用,但是,Java 对此同样有解决的办法。为了有效地处理 Comet,需要非阻塞 IO,Java 通过它的 NIO 库提供非阻塞 IO。两种最流行的开源服务器 Apache Tomcat 和 Jetty 都利用 NIO 增加非阻塞 IO,从而支持 Comet.

 

  • 而非阻塞I/O和同步I/O最明显的不同就是同步I/O所有可能被阻塞的地址在非阻塞I/O中都不会被阻塞。如在读取数据时,如果数据暂时无法被读取。那么在非阻塞I/O中会立刻返回,以便程序可以执行其他的代码,然后系统会不断侦测这个未完成的读取操作,直到可以继续读数据时再来完成这个操作。非阻塞式IO的出现的目的就是为了解决这个瓶颈。而非阻塞式IO是怎么实现的呢?非阻塞IO处理连接的线程数和连接数没有联系,也就是说处理10000个连接非阻塞IO不需要10000个线程,你可以用1000个也可以用2000个线程来处理。因为非阻塞IO处理连接是异步的。当某个连接发送请求到服务器,服务器把这个连接请求当作一个请求"事件",并把这个"事件"分配给相应的函数处理。我们可以把这个处理函数放到线程中去执行,执行完就把线程归还。这样一个线程就可以异步的处理多个事件。而阻塞式IO的线程的大部分时间都浪费在等待请求上了。
  • 在comet中,为了保持长连接,如果使用阻塞时IO,则不可避免的对每一个连接保持一个线程。不同于短连接,线程可以及时释放。长连接对应的线程可能永远不能释放,这样一个server能够服务的客户端的数量就受到了线程数量上限的限制。而使用NIO可以伺候多个连接而不必要保持相应数量的线程。就解决了这个问题。

 

  • Tomcat提供了CometProcessor接口,有这种特定标记的Servlet,Tomcat会做特殊处理,Tomcat不会把它当做普通Servlet实行完毕后,会回收request和response。注意:实现CometProcessor接口后不用在servlet中写doGet,doPoset方法,所有事件在BEGIN,READ,END,ERROR中实现。
  • 从event拿到的request和response不会在begin和end/error之间不会被释放,一直有效。可以用来传递消息。Note that the response object and dependent OutputStream and Writer are still not synchronized, so when they are accessed by multiple threads, synchronization is mandatory.
  • BEGIN:初始化参数和获取request和response,结束时,request is commited
  • READ(只有POST方法,才会触发该事件):有数据从request进来,可以从request读取数据。在此事件之外不允许读取request的数据。On some platforms, like Windows, a client disconnect is indicated by a READ event. Reading from the stream may result in -1, an IOException or an EOFException. Make sure you properly handle all these three cases. If you don't catch the IOException, Tomcat will instantly invoke your event chain with an ERROR as it catches the error for you, and you will be notified of the error at that time.
  • END: End may be called to end the processing of the request. Fields that have been initialized in the begin method should be reset. After this event has been processed, the request and response objects, as well as all their dependent objects will be recycled and used to process other requests. End will also be called when data is available and the end of file is reached on the request input (this usually indicates the client has pipelined a request).
  • ERROR: Error will be called by the container in the case where an IO exception or a similar unrecoverable error occurs on the connection. Fields that have been initialized in the begin method should be reset. After this event has been processed, the request and response objects, as well as all their dependent objects will be recycled and used to process other requests.(END,ERROR之后request和response就不要再用了)

 

  • ventSubType.TIMEOUT: The connection timed out (sub type of ERROR); note that this ERROR type is not fatal, and the connection will not be closed unless the servlet uses the close method of the event.
  • EventSubType.CLIENT_DISCONNECT: The client connection was closed (sub type of ERROR). method of the event.
  • EventSubType.IOEXCEPTION: An IO exception occurred, such as invalid content, for example, an invalid chunk block (sub type of ERROR).
  • EventSubType.WEBAPP_RELOAD: The web application is being reloaded (sub type of END).
  • EventSubType.SESSION_END: The servlet ended the session (sub type of END).

BEGIN-READ-READ-Error/TIMEOUT。随时可以event.close()。来终止连接。

 

 

  • writer.flush();writer.close();长轮询和流风格的comet的差别只是取决于是否有第二句(长轮询需要client端在response关闭后再重连)

 

If you are using the NIO connector, you can set individual timeouts for your different comet connections. To set a timeout, simply set a request attribute like the following code shows:

CometEvent event.... event.setTimeout(30*1000);

or

event.getHttpServletRequest().setAttribute("org.apache.tomcat.comet.timeout", new Integer(30 * 1000));

This sets the timeout to 30 seconds. Important note, in order to set this timeout, it has to be done on the BEGIN event. The default value is soTimeout

 

 

      简单的Comet servlet代码示例:

package com.easyway.comet.pushlet;

import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import org.apache.catalina.CometEvent;
import org.apache.catalina.CometProcessor;
import org.apache.catalina.CometEvent.EventType;
/**
 * Tomcat6推送技术通过时现实tomcat的推送接口CometProcessor实现的servlet实现推送技术,在
 * servlet中out.close()方法不能使用,否則不能持續推送信息.
 * <p>功能描述,该部分必须以中文句号结尾。<p>
 *
 * 创建日期  2013-7-21<br>
 * @author  longgangbai <br>
 * @version $Revision$ $Date$
 * @since   3.0.0
 */
public class CometServlet extends HttpServlet implements CometProcessor {
    //
    private static final long serialVersionUID = 1L;

    public void event(CometEvent e) throws IOException, ServletException {
        if (e.getEventType() == EventType.BEGIN) {
            // fill in code handling here
           HttpServletResponse response = e.getHttpServletResponse();
            PrintWriter out = response.getWriter();
            out.write("Hello world");
            out.flush(); 
            //System.out.println("message sent");
        }else if (e.getEventType() == EventType.READ) {
        }else if (e.getEventType() == EventType.ERROR) {
        }else if(e.getEventType() == EventType.END){
        }
      
        // and continue handing other events
    }
}

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>CometTomcat6</display-name>
  <servlet>
     <servlet-name>cometTomcet6</servlet-name>
     <servlet-class>com.easyway.comet.pushlet.CometServlet</servlet-class>
  </servlet>
  <servlet-mapping>
      <servlet-name>cometTomcet6</servlet-name>
      <url-pattern>/cometServlet</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

 

html界面代碼:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
 <script>
 //服务器端代码类似与普通Ajax代码,其中,需要注意的是:request.readyState值如果设置为4,浏览器会处于长期等待状态,而收不到响应消息,设置为3后,firefox浏览器正常,但IE不能正常获得消息
 function CometEx() {
   var request =  new XMLHttpRequest();
   request.open("GET", "http://localhost:8080/CometTomcat6/cometServlet", true);
   request.onreadystatechange = function() {
     if (request.readyState == 3 && request.status == 200) {
            alert(request.responseText);     
     }
   }
   request.send(null);
 }
 </script>
<body onload="CometEx();">

</body>
</html>

 


    
[2] Activity札记(5)-Activity生命周期
    来源: 互联网  发布时间: 2014-02-18
Activity笔记(5)---Activity生命周期

 Android api中提供的Activity生命周期图


 

创建一个测试项目ActivityLife
在MainActivity.java中
重写onCreate,onStart,onResume,onPause,onStop,onRestart,onDestroy方法

 

package com.example.activitylife;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.e(TAG, "~~~onCreate~~~");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "~~~onStart~~~");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e(TAG, "~~~onReStart~~~");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "~~~onResume~~~");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "~~~onPause~~~");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "~~~onStop~~~");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "~~~onDestroy~~~");
    }
}

 

运行该应用程序
下面是不同操作对应的LogCat输出
打开应用程序时,对应下图过程1

 
打开应用程序后,按下BACK键时,对应下图过程2

 
打开应用程序后,按下HOME键时,对应下图过程3


 
在上一操作的基础上,再次打开应用程序时,对应下图过程4

操作流程图:

 ========================================================================
参考文章提出的一个问题:
EditText在状态1时输入一个字符串,如"Hello,Android!",再经过3,4状态后无法保持
看到有评论说  有id的view,android会自动维护状态
经测试,无论EditText无论有无id,字符串都可保持住
测试如下:
修改res/layout/activity_main.xml,在布局中添加一个EditText控件
<? xml version ="1.0" encoding= "utf-8" ?>
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
    xmlns:tools ="http://schemas.android.com/tools"
    android:layout_width ="fill_parent"
    android:layout_height ="fill_parent"
    android:orientation ="vertical"
    android:paddingBottom ="@dimen/activity_vertical_margin"
    android:paddingLeft ="@dimen/activity_horizontal_margin"
    android:paddingRight ="@dimen/activity_horizontal_margin"
    android:paddingTop ="@dimen/activity_vertical_margin"
    tools:context =".MainActivity" >

    <TextView
        android:layout_width ="fill_parent"
        android:layout_height ="wrap_content"
        android:text ="@string/hello_world" />

    <EditText
        android:id ="@+id/editText"
        android:layout_width ="fill_parent"
        android:layout_height ="wrap_content"
        android:inputType ="text" />

</ LinearLayout>
 
再依次运行过程1-->3-->4
在状态1的时候,在EditText控件中写入一个字符串,如Hello,Android!,在经过3,4过程后字符串依旧保持

  ========================================================================
测试状态5
修改res/layout/main_activity.xml,添加一个Button
<? xml version ="1.0" encoding= "utf-8" ?>
< LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
    xmlns:tools ="http://schemas.android.com/tools"
    android:layout_width ="fill_parent"
    android:layout_height ="fill_parent"
    android:orientation ="vertical"
    android:paddingBottom ="@dimen/activity_vertical_margin"
    android:paddingLeft ="@dimen/activity_horizontal_margin"
    android:paddingRight ="@dimen/activity_horizontal_margin"
    android:paddingTop ="@dimen/activity_vertical_margin"
    tools:context =".MainActivity" >

    <TextView
        android:id = "@+id/mainTv"
        android:layout_width ="fill_parent"
        android:layout_height ="wrap_content"
        android:text ="@string/hello_world" />

    <EditText
        android:id = "@+id/mainEt"
        android:layout_width= "fill_parent"
        android:layout_height ="wrap_content"
        android:inputType ="text" />

    <Button
        android:id ="@+id/callDialog"
        android:layout_width ="fill_parent"
        android:layout_height ="wrap_content"
        android:text ="@string/call_dialog" />

</ LinearLayout>
 
添加一个Activity,SecondActivity
并重写onCreate,onStart,onResume,onPause,onStop,onRestart,onDestroy方法
package com.example.activitylife;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class SecondActivity extends Activity {

    private static final String TAG = "SecondActivity";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        
        Log.e(TAG, "~~~onCreate~~~");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "~~~onStart~~~");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e(TAG, "~~~onReStart~~~");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "~~~onResume~~~");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "~~~onPause~~~");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "~~~onStop~~~");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "~~~onDestroy~~~");
    }
}
 
修改MainActivity.java
package com.example.activitylife;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

    private static final String TAG = "MainActivity";
    private Button callDialogBut;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.e(TAG, "~~~onCreate~~~");

        callDialogBut = (Button) findViewById(R.id.callDialog);
        callDialogBut.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClass(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "~~~onStart~~~");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.e(TAG, "~~~onReStart~~~");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "~~~onResume~~~");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "~~~onPause~~~");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "~~~onStop~~~");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "~~~onDestroy~~~");
    }
}
 
修改AndroidManifest.xml文件
<? xml version ="1.0" encoding= "utf-8" ?>
< manifest xmlns:android ="http://schemas.android.com/apk/res/android"
    package ="com.example.activitylife"
    android:versionCode ="1"
    android:versionName ="1.0" >

    <uses-sdk
        android:minSdkVersion ="8"
        android:targetSdkVersion ="17" />

    <application
        android:allowBackup ="true"
        android:icon ="@drawable/ic_launcher"
        android:label ="@string/app_name"
        android:theme ="@style/AppTheme" >
        < activity
            android:name ="com.example.activitylife.MainActivity"
            android:label ="@string/app_name" >
            < intent-filter>
                < action android:name ="android.intent.action.MAIN" />

                < category android:name ="android.intent.category.LAUNCHER" />
            </ intent-filter>
        </ activity>
        < activity
            android:name =".SecondActivity"
            android:label ="@string/app_name"
            android:theme ="@android:style/Theme.Dialog" >
        </ activity>
    </application >

</ manifest>
 
启动应用程序后,点击 调用对话框 按钮,相当于过程5中的onPause

 
在上一步操作的基础上,点击BACK键,相当于过程5中的onResume

 
程序运行截图:
启动应用程序
 
按下 调用对话框 按钮

 
再按下BACKUP键

 
 

 

参考文章:

-----------------------

两分钟彻底让你明白Android Activity生命周期(图文)!


    
[3] storyboard兼容版本处置
    来源: 互联网  发布时间: 2014-02-18
storyboard兼容版本处理
//storyboard版本兼容

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  // 1
  UIStoryboard *mainStoryboard = nil;
  if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")) {
    mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
  } else {
    mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard-legacy" bundle:nil];
  }
 
  // 2
  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  self.window.rootViewController = [mainStoryboard instantiateInitialViewController];
  [self.window makeKeyAndVisible];
 
  return YES;
}

    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
浙ICP备11055608号-3 iis7站长之家
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3