2013年10月25日星期五

PHP使用SOAP调用.net的WebService问题

项目的需求,需要和一个.net系统进行数据交换,合作方提供了一个WebService接口。这个与一般的PHP POST或GET传值再查库拿数据的思路有点不一样,需要用到SOAP模块,处理方法也很简单,就是有一些需要注意的事情。

首先确认你的PHP.ini开启了.SOAP,就是 extension=php_soap.dll 这前面的分号去咯。

代码很简单:

<?php

$client = new SoapClient('http://www.nowamagic.net/SearchService.asmx?WSDL');

$client->soap_defencoding = 'utf-8';
$client->decode_utf8 = false;
$client->xml_encoding = 'utf-8';

$param = array('param1'=>'01', 'param2'=>'02');

//$param["param1"]="01";
//$param["param2"]="02";

//$result = $client->__soapCall("GetArticle", array( $param ));
$result = $client->__Call("GetArticle", array( $param ));

if (is_soap_fault($result))
{
    trigger_error("SOAP Fault: (faultcode: {$result->faultcode}, faultstring: {$result->faultstring})", E_USER_ERROR);
}
else
{
    $data = $result->GetArticleResult; //这里返回的是类,必须使用->得到元素的值
    print_r($data);
}
?>
需要注意的一点是,参数是数组外再包一层数组,就是 array( array() )
附SOAP接口的一些参数:
以下是 SOAP 1.2 请求和响应示例。所显示的占位符需替换为实际值。
POST /SearchService.asmx HTTP/1.1
Host: 202.105.183.61
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/GetTrafficViolationInfo"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetArticle xmlns="http://tempuri.org/">
      <param1>string</param1>
      <param2>string</param2>
    </GetArticle>
  </soap:Body>
</soap:Envelope>




HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetArticleResponse xmlns="http://tempuri.org/">
      <GetArticleResult>string</GetArticleResult>
    </GetArticleResponse>
  </soap:Body>

</soap:Envelope>


2013年10月19日星期六

Activity的LaunchMode和taskAffinity


  做项目到现在都一直没有理解LaunchMode有什么用,或许根本就没真正花心思去看,所以今天把这部分整理下。
  设置Activity的LaunchMode属性可以决定这个Activity是和当前Task保持关联,还是说每次运行这个Activity是新建一个实例,还是保持单例。
  Task和Back Stack简介
  task是一组Activities的集合,一组Activities被Stack(back stack)所管理。
  在一个应用中,有3个activities,分别是activity1,activity2,activity3,首先activity1被start,此时,如果应用没有创建task则创建,并把activity1压入栈顶,activity1触发onCreate->onStart->onResume。
  
  接着activity1转向到activity2时,activity1先触发onPause,activity2触发onCreate->onStart->onResume,然后activity1触发onPause->onStop,activity2压入栈顶。
  
  以此类推,activity2转向activity3也是一样的步骤。那么当前栈顶是activity3。
  
  当我们按下手机上的返回键时,栈顶的activity3触发onPause,activity2需要从状态stop到pause,所以触发了onPause->onStart->onResume,activity3触发onStop->onDestory,因为activity3从栈顶弹出,所以触发onDestory,此时,activity2在栈顶。
  back stack
  如果继续按返回键,当前栈顶的activity弹出并被destory,直到home界面。当所有的activity都弹出了,这个task也就消亡了。
  当开始一个新的task时,前一个task被设置为后台,在后台,所有的activity都处理stop状态,但是back stack保留了所有后台activity的状态信息,只是丢失了焦点。
task
  反复的在两个activity之间切换,activity会产生多个独立的实例。
  stack
  查阅有关Activity生命周期更多说明。
  两种方式设置LaunchMode属性
  1.  在 manifest文件中设置
复制代码
<activity android:name=".activity.ActivityA"
        android:launchMode="standard">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
复制代码
  2.  使用Intent flags设置
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(ActivityA.this, ActivityB.class);
startActivity(intent);
  四种LaunchMode说明
  standard
   不做任何设置,默认模式就是standard,activity在每次start时,都会有一个新的实例被task管理。下面看下代码实例。
复制代码
//ActivityA.java
Intent intent = new Intent();
intent.setClass(ActivityA.this, ActivityB.class);
startActivity(intent);

//ActivityB.java
Intent intent = new Intent();
intent.setClass(ActivityB.this, ActivityA.class);
startActivity(intent);
复制代码

 操作1:在ActivityA(蓝)和ActivityB(绿)之间重复切换,按返回键推到home界面。
  可以发现(蓝色86和绿色79的taskID)ActivityA和ActivityB都在同一个task,并且每次resume的实例都是不一样的。这说明在一个activity可以有多个实例在同一个task中。
  在按返回按键时,将依次弹出stack。
  singleTop
  和standard一样,可以多次实例,但,如果处于当前栈顶并且接受到一个与当前activity一样类型的intent,那么不会创建一个新实例,而是触发onNewIntent()事件。
复制代码
//ActivityA.java
Intent intent = new Intent();
intent.setClass(ActivityA.this, ActivityA.class);
startActivity(intent);

@Override
protected void onNewIntent(Intent intent) {
    logger.d("onNewIntent " + this.hashCode() + " taskID "
                + this.getTaskId());
    super.onNewIntent(intent);
}
复制代码
复制代码
<activity android:name=".activity.ActivityA" android:label="ActivityA"
            android:launchMode="singleTop">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
复制代码
操作1:点击ActivityA上的按钮
  发现当点击按钮是ActivityA->onPause->onNewIntent->onResume,没有新建新的实例(蓝62)。
  这个模式在这个场景下比较有用,比如:如果有一个其他的应用想启动你的Activity(launch mode为singleTop),而你当前的Activity正好在栈顶,那么就会调用到onNewIntent方法。原文贴上:If an instance of the activity already exists at the top of the current task, the system routes the intent to that instance through a call to its onNewIntent()  method。
  singleTask
  系统会创建一个新task(如果没有启动应用)和一个activity新实例在新task根部,然后,如果activity实例已经存在单独的task中,系统会调用已经存在activity的 onNewIntent() 方法,而不是存在新实例,仅有一个activity实例同时存在。
复制代码
<activity android:name=".activity.ActivityA" android:label="ActivityA" android:launchMode="standard">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>
<activity android:name=".activity.ActivityB" android:label="ActivityB" android:launchMode="singleTask">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
    </intent-filter>
</activity>
<activity android:name=".activity.ActivityC" android:label="ActivityC" android:launchMode="standard">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
    </intent-filter>
</activity>
复制代码
 操作1:ActivityA->ActivityB->ActivityC->ActivityA->ActivityB->ActivityC
  
   可以看到,当再次进入ActivityB时,没有onCreate,而是onNewIntent(绿55)。
   这里我们也可以发现一个现象,当在调用到ActivityB的onNewIntent时,之前的ActivityA和ActivityC都调用了onDestory。也就是说,系统发现栈中存在ActivityB的实例时,ActivityA和ActivityB都弹栈了。
   列出Log日志(这里设ActivityA的LaunchMode为singleTask),ActivityB和ActivityC都在onNewIntent前后调用了onDestory。
  
  singleInstance
    和singleTask相似,除了系统不会让其他的activities运行在所有持有的task实例中,这个activity是独立的,并且task中的成员只有它,任何其他activities运行这个activity都将打开一个独立的task。
复制代码
<activity android:name=".activity.ActivityA" android:launchMode="singleTask">
  <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>
<activity android:name=".activity.ActivityB" android:launchMode="singleInstance">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
  </intent-filter>
</activity>
<activity android:name=".activity.ActivityC">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
   </intent-filter>
</activity>
复制代码

 操作1:ActivityA->ActivityB->ActivityA
  

  可以发现,两个Activity是在不同的Task中,其次,当调用到onNewIntent时,ActivityB没有被Destory,互不干涉。
  操作2:ActivityA->ActivityB->ActivityC,按返回键
  

  图解:
  
  刚进入应用,创建TaskA,ActivityA为栈顶,从ActivityA到ActivityB,ActivityB进入TaskB(如果再次进入ActivityB,则不创建Task,调用onNewIntent),此时TaskB中的ActivityB为栈顶,从ActitivyB到ActivityC,ActivityC为栈顶。
  一直按返回键,先从TaskA中依次将Activity弹出,然后再从TaskB中将ActiviyB弹出。ActiviyC->ActivityA->ActivityB。
  这里分析一个问题,浏览器的LaunchMode为singleTask,所以如果当你点击一个连接下载文件时(由一个activity来处理下载,launchmode为standard),如果再次进入浏览器,那么下载页面就被Destory了,那么这里我们可以把下载页面LaunchMode设置为singleInstance可以解决这个问题。

  Affinity定义

  Affinity更像是表明了activity属于哪个task,默认情况下,应用所有的activities都有相同的affinity,所以都是在相同的task中。然后你可以编辑默认的affinity。Activities定义在不同的应用可以共享一个affinity,或者activities定义在相同的应用中可以被不同的affinities所关联。
  你可以编辑在<activity> 元素中activity的taskAffinity 属性。
   先看看两种不同的情况下affinity的表现:
//ActivityA.java
Intent intent = new Intent();    
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(ActivityA.this, ActivityB.class);
startActivity(intent);
复制代码
<activity android:name=".activity.ActivityA" android:taskAffinity="com.android.demo.affinity1">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
       <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name=".activity.ActivityB" android:taskAffinity="com.android.demo.affinity2">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
   </intent-filter>
</activity>
复制代码
操作1:不同的affinity值,ActivityA->ActivityB
如果已经存在相同affinity,那么新activity运行在这个task中,否则,系统创建新task。
操作2:相同的affinity值,ActivityA->ActivityB
复制代码
<activity android:name=".activity.ActivityA" android:taskAffinity="com.android.demo.affinity1">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
       <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity android:name=".activity.ActivityB" android:taskAffinity="com.android.demo.affinity2">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
   </intent-filter>
</activity>
复制代码
可以看出ActivityA和ActivityB都运行在同一个task中。

  使用来表示是否允许activity重新附属其他Task,还是举例说明吧。
  有两个应用,Demo1和Demo2,Demo1中有2个Activity(ActivityA,ActivityC),ActivityA可以转向到ActivityC,Demo2中有一个Activity(ActivityB),也可以转向到ActivityC。
  操作1:设置ActivityC的allowTaskReparenting属性为true。
      运行Demo2,转向到ActivityC,在ActivityC中打印信息,返回到HOME界面,运行Demo1。
复制代码
//Demo1 
//ActivityA.java
Intent intent = new Intent();
intent.setClass(ActivityA.this, ActivityC.class);
startActivity(intent);

//ActivityC.java
tv.setText(ActivityC.this.toString());

//Demo2
//ActivityB.java
Intent intent = new Intent();
intent.setClassName("com.android.demo","com.android.demo.activity.ActivityC");
ActivityB.this.startActivity(intent);
复制代码
复制代码
//Demo1
<activity android:name=".activity.ActivityA">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>
<activity android:name=".activity.ActivityC" android:allowTaskReparenting="true">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
  </intent-filter>
</activity>

//Demo2
<activity android:name=".ActivityB">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>
复制代码
 运行结果:(黄色Demo1,绿色Demo2)
  
    ActivityB转向到ActivityC,此时ActivityC就关联到Demo2的Task中,TaskID都为231。在运行Demo1时,看到是ActivityC而不是ActivityA。当再次进入Demo2时就看不到ActivityC了。
  操作2:将ActivityC的taskAffinity设置为"com.android.demo.activityc"。
      运行Demo2,转向到ActivityC,在ActivityC中打印信息,返回到HOME界面,运行Demo1。
复制代码
//Demo1
<activity android:name=".activity.ActivityC"
            android:taskAffinity="com.android.demo.activityc"
            android:allowTaskReparenting="true">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
  </intent-filter>
</activity>
复制代码
 运行结果:
  
   从结果中可以看出,Demo1和Demo2都拥有ActivityC,也就是说有2个Task里存在ActivityC,分别被Demo1和Demo2所使用。
  操作3:将ActivityC和ActivityB的taskAffinity都设为"com.android.demo.activityc"。
      运行Demo2,转向到ActivityC,在ActivityC中打印信息,返回到HOME界面,运行Demo1。
复制代码
//Demo2
<activity android:name=".ActivityB" android:taskAffinity="com.android.demo.activityc">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>

//Demo1
<activity android:name=".activity.ActivityC"
            android:taskAffinity="com.android.demo.activityc"
            android:allowTaskReparenting="true">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
  </intent-filter>
</activity>
复制代码
  运行结果:
  
   和操作1相反,再进入Demo2时看到是ActivityC,进入Demo1都是看到ActivityA。

  写到最后越来越崩溃了,如果有什么地方写的不对或不清楚请指明。
分类: Android

2013年10月15日星期二

JAVA处理日期时间常用方法:

1.java.util.Calendar 
Calendar 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000,格里高利历)的偏移量。 

例: 
Java代码  收藏代码
  1. Calendar cal = Calendar.getInstance();//使用默认时区和语言环境获得一个日历。   
  2. cal.add(Calendar.DAY_OF_MONTH, -1);//取当前日期的前一天.   
  3.   
  4. cal.add(Calendar.DAY_OF_MONTH, +1);//取当前日期的后一天.   
  5.   
  6. //通过格式化输出日期   
  7. java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd");   
  8.   
  9. System.out.println("Today is:"+format.format(Calendar.getInstance().getTime()));   
  10.   
  11. System.out.println("yesterday is:"+format.format(cal.getTime()));   


得到2007-12-25日期: 
Java代码  收藏代码
  1. Calendar calendar = new GregorianCalendar(20071125,0,0,0);   
  2. Date date = calendar.getTime();   
  3. System.out.println("2007 Christmas is:"+format.format(date));   

java月份是从0-11,月份设置时要减1. 

GregorianCalendar构造方法参数依次为:年,月-1,日,时,分,秒. 

取日期的部分: 
Java代码  收藏代码
  1. int year =calendar.get(Calendar.YEAR);   
  2.   
  3. int month=calendar.get(Calendar.MONTH)+1;   
  4.   
  5. int day =calendar.get(Calendar.DAY_OF_MONTH);   
  6.   
  7. int hour =calendar.get(Calendar.HOUR_OF_DAY);   
  8.   
  9. int minute =calendar.get(Calendar.MINUTE);   
  10.   
  11. int seconds =calendar.get(Calendar.SECOND);   


取月份要加1. 

判断当前月份的最大天数: 
Java代码  收藏代码
  1. Calendar cal = Calendar.getInstance();   
  2. int day=cal.getActualMaximum(Calendar.DAY_OF_MONTH);   
  3. System.out.println(day);   


2.java.util.Date 
Java代码  收藏代码
  1. java.util.Date today=new java.util.Date();   
  2. System.out.println("Today is "+formats.format(today));   


取当月的第一天: 
Java代码  收藏代码
  1. java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-01");   
  2. java.util.Date firstDay=new java.util.Date();   
  3. System.out.println("the month first day is "+formats.format(firstDay));   

取当月的最后一天: 
Java代码  收藏代码
  1.    
  2. Calendar cal = Calendar.getInstance();   
  3. int maxDay=cals.getActualMaximum(Calendar.DAY_OF_MONTH);   
  4. java.text.Format formatter3=new java.text.SimpleDateFormat("yyyy-MM-"+maxDay);   
  5. System.out.println(formatter3.format(cal.getTime()));   


求两个日期之间相隔的天数: 
Java代码  收藏代码
  1. java.text.SimpleDateFormat format = new java.text.SimpleDateFormat("yyyy-MM-dd");   
  2. java.util.Date beginDate= format.parse("2007-12-24");   
  3. java.util.Date endDate= format.parse("2007-12-25");   
  4. long day=(date.getTime()-mydate.getTime())/(24*60*60*1000);   
  5. System.out.println("相隔的天数="+day);   

一年前的日期: 
Java代码  收藏代码
  1. java.text.Format formatter=new java.text.SimpleDateFormat("yyyy-MM-dd");   
  2. java.util.Date todayDate=new java.util.Date();   
  3. long beforeTime=(todayDate.getTime()/1000)-60*60*24*365;   
  4. todayDate.setTime(beforeTime*1000);   
  5. String beforeDate=formatter.format(todayDate);   
  6. System.out.println(beforeDate);   

一年后的日期: 
Java代码  收藏代码
  1. java.text.Format formatter=new java.text.SimpleDateFormat("yyyy-MM-dd");   
  2. java.util.Date todayDate=new java.util.Date();   
  3. long afterTime=(todayDate.getTime()/1000)+60*60*24*365;   
  4. todayDate.setTime(afterTime*1000);   
  5. String afterDate=formatter.format(todayDate);   
  6. System.out.println(afterDate);   

求10小时后的时间 
Java代码  收藏代码
  1. java.util.Calendar Cal=java.util.Calendar.getInstance();   
  2. Cal.setTime(dateOper);   
  3. Cal.add(java.util.Calendar.HOUR_OF_DAY,10);   
  4. System.out.println("date:"+forma.format(Cal.getTime()));   

求10小时前的时间 
Java代码  收藏代码
  1. java.util.Calendar Cal=java.util.Calendar.getInstance();   
  2. Cal.setTime(dateOper);   
  3. Cal.add(java.util.Calendar.HOUR_OF_DAY,-10);   
  4. System.out.println("date:"+forma.format(Cal.getTime()));   

3.java.sql.Date 
继承自java.util.Date,是操作数据库用的日期类型 
Java代码  收藏代码
  1. java.sql.Date sqlDate = new java.sql.Date(java.sql.Date.valueOf("2007-12-25").getTime());   

日期比较:简单的比较可以以字符串的形式直接比较,也可使用 
java.sql.Date.valueOf("2007-03-08").compareTo(java.sql.Date.valueOf("2007-03-18"))方式来比较日期的大小.也可使用java.util.Date.after(java.util.Date)来比较. 

相差时间: 
long difference=c2.getTimeInMillis()-c1.getTimeInMillis(); 
相差天数:long day=difference/(3600*24*1000) 
相差小时:long hour=difference/(3600*1000) 
相差分钟:long minute=difference/(60*1000) 
相差秒: long second=difference/1000 

补充: 
Java代码  收藏代码
  1. DateFormat df=new SimpleDateFormat("yyyy-MM-dd EE hh:mm:ss");   
  2. System.out.println(df.format(new Date()));   
  3. Date date = new Date();   
  4. DateFormat shortDate=DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);   
  5. DateFormat mediumDate =DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);   
  6. DateFormat longDate =DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);   
  7. DateFormat fullDate =DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);   
  8.   
  9. system.out.println(shortDate.format(date));   
  10. System.out.println(mediumDate.format(date));   
  11. System.out.println(longDate.format(date));   
  12. System.out.println(fullDate.format(date));   
  13.   
  14. 08-4-15 下午3:24   
  15. 2008-4-15 15:24:31   
  16. 2008415日 下午032431秒   
  17. 2008415日 星期二 下午032431秒CST   
  18.   
  19.   
  20. Calendar c = Calendar.getInstance();   
  21.   
  22. c.add(Calendar.MONTH, 1); // 目前時間加1個月   
  23. System.out.println(df.format(c.getTime()));   
  24.   
  25. c.add(Calendar.HOUR, 3); // 目前時間加3小時   
  26. System.out.println(df.format(c.getTime()));   
  27.   
  28. c.add(Calendar.YEAR, -2); // 目前時間減2年   
  29. System.out.println(df.format(c.getTime()));   
  30.   
  31. c.add(Calendar.DAY_OF_WEEK, 7); // 目前的時間加7天   
  32. System.out.println(df.format(c.getTime()));