----------------------------------------------一.WEB項目的執行流程---------------------------------
1.web項目的運行流程大致如下:
啟動tomcat,先到web.xml里面查看<context-param><listener><filter><servlet>等等幾個tag,查看里面的配置,查找相應的配置文件。
如下列文件所示:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="
<display-name>SpringMVC12</display-name>
<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>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config/springAnnotation-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config/springAnnotation-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<!-- encoding filter for jsp page -->
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>openSession</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSession</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
首先查看那幾個標簽,找到對應的配置文件,如<context-param>中配置的classpath*:config/springAnnotation-*.xml。
---------------------------------------2.到配置文件查看相關信息----------------------------------------------
(1)<context-param>里的classpath*:config/springAnnotation-*.xml,即在config目錄下匹配springAnnotation-*.xml的文件

(1.1)查看springAnnotation-core.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "<!ENTITY contextInclude SYSTEM "org/springframework/web/context/WEB-INF/contextInclude.xml">
]>
<beans>
<import resource="classpath*:com/zyh/web/controller/spring/springAnnotation-import.xml"/>
</beans>
對應的路徑如下com/zyh/web/controller/spring/springAnnotation-import.xml
(1.2)查看springAnnotation-import.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "<!ENTITY contextInclude SYSTEM "org/springframework/web/context/WEB-INF/contextInclude.xml">
]>
<beans>
<bean id="userDao" class="com.zyh.web.controller.dao.UserDAO">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="userManagerBase" class="com.zyh.web.controller.service.UserManager">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userManager" parent="transactionBese">
<property name="target" ref="userManagerBase"></property>
</bean>
</beans>
對應關于就已經配置在容器里面了。
(2.1)查看springAnnotation-hibernate.xml(配置數據源,sessionFactory,和事物)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "<!ENTITY contextInclude SYSTEM "org/springframework/web/context/WEB-INF/contextInclude.xml">
]>
<beans>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/test1?useUnicode=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hiberante.format_sql">true</prop>
</props>
</property>
<property name="configLocations">
<list>
<value>
classpath*:com/zyh/web/controller/hibernate/hibernate.cfg.test.xml
</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="transactionBese" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" lazy-init="true" abstract="true">
<property name="transactionManager" ref="transactionManager"></property>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="insert*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="modify*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="delete*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="get*">PROPAGATION_NEVER</prop>
</props>
</property>
</bean>
</beans>
配置的對應的 classpath*:com/zyh/web/controller/hibernate/hibernate.cfg.test.xml
(3)springAnnotation-servlet.xml,內容如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=" xmlns:context=" xmlns:p=" xmlns:mvc=" xmlns:xsi=" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
<!-- 注解掃描包 -->
<context:component-scan base-package="com.zyh.web.controller" />
<!-- 開啟注解 -->
<mvc:annotation-driven/>
<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean> -->
<!-- 靜態資源訪問 -->
<mvc:resources location="/img/" mapping="/img/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8" />
<property name="maxUploadSize" value="10485760000" />
<property name="maxInMemorySize" value="40960" />
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=" xmlns:context=" xmlns:p=" xmlns:mvc=" xmlns:xsi=" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
<!-- 注解掃描包 -->
<context:component-scan base-package="com.zyh.web.controller" />
<!-- 開啟注解 -->
<mvc:annotation-driven/>
<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean> -->
<!-- 靜態資源訪問 -->
<mvc:resources location="/img/" mapping="/img/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8" />
<property name="maxUploadSize" value="10485760000" />
<property name="maxInMemorySize" value="40960" />
</bean>
</beans>
springAnnotation-hibernate.xml<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "<!ENTITY contextInclude SYSTEM "org/springframework/web/context/WEB-INF/contextInclude.xml">
]>
<beans>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/test1?useUnicode=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hiberante.format_sql">true</prop>
</props>
</property>
<property name="configLocations">
<list>
<value>
classpath*:com/zyh/web/controller/hibernate/hibernate.cfg.test.xml
</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="transactionBese" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" lazy-init="true" abstract="true">
<property name="transactionManager" ref="transactionManager"></property>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="insert*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="modify*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="delete*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="get*">PROPAGATION_NEVER</prop>
</props>
</property>
</bean>
</beans>
這個寫的有點亂,理清思路,其實很簡單,就是配置spring容器,里面掃描了所有的bean及一些依賴關系,hibernate配置數據源建立數據庫連接,SessionFactory用于管理數據庫,還有就是Springmvc用于控制視圖與后臺之間的頁面轉向,傳遞數據,發送請求。
配置工作就到此結束,然后就是寫bean,dao,service,control與聯系配置文件的對應關系,實際開發中當然不會把配置文件都寫好才來寫java代碼。我的做法是同時進行,漏了就相應的加上。
-----------------------------------------------------------3對應的實現--------------------------------------
3.1 為了簡單,我們建立一個單表的添刪改查,就一個對象吧User,對應的表T_User,里面有userName和age兩個屬性,當然還要建立一個主鍵id,如下列代碼所示:
com.zyh.web.controller.entity.User
package com.zyh.web.controller.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name="T_USER")
public class User {
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
@Column(length=32)
@Id
private String id;
@Column(length=32)
private String userName;
@Column(length=32)
private String age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
3.2 dao層結構如下:接口IUserDAO與實現類UserDAO,我們實現添刪改查,查詢包括一個User和所以User
com.zyh.web.controller.dao.IUserDAO
package com.zyh.web.controller.dao;
import java.util.List;
import com.zyh.web.controller.entity.User;
public interface IUserDAO {
public void addUser(User user);
public List<User> getAllUser();
public User getUser(String id);
public boolean delUser(String id);
public boolean updateUser(User user);
}
實現類UserDAO:
package com.zyh.web.controller.dao;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import com.zyh.web.controller.entity.User;
public class UserDAO implements IUserDAO {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public void addUser(User user) {
// TODO Auto-generated method stub
sessionFactory.getCurrentSession().save(user);
}
@Override
public List<User> getAllUser() {
// TODO Auto-generated method stub
String hql = "from User";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
return query.list();
}
@Override
public User getUser(String id) {
// TODO Auto-generated method stub
String hql = "from User u where u.id=?";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setString(0, id);
return (User) query.uniqueResult();
}
@Override
public boolean delUser(String id) {
// TODO Auto-generated method stub
String hql = "delete User u where u.id=?";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setString(0, id);
return (query.executeUpdate()>0);
}
@Override
public boolean updateUser(User user) {
// TODO Auto-generated method stub
String hql = "update User u set u.userName=?,u.age=? where u.id=?";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setString(0, user.getUserName());
query.setString(1, user.getAge());
query.setString(2, user.getId());
return (query.executeUpdate()>0);
}
}
3.3 service層結構如下:接口IUserManager與實現類UserManager,我們實現添刪改查,查詢包括一個User和所以User
com.zyh.web.controller.service.IUserManager
package com.zyh.web.controller.service;
import java.util.List;
import com.zyh.web.controller.entity.User;
public interface IUserManager {
public void addUser(User user);
public List<User> getAllUser();
public boolean delUser(String id);
public User getUser(String id);
public boolean updateUser(User user);
}
實現類UserManager.java
package com.zyh.web.controller.service;
import java.util.List;
import com.zyh.web.controller.dao.IUserDAO;
import com.zyh.web.controller.entity.User;
public class UserManager implements IUserManager {
private IUserDAO userDao;
public void setUserDao(IUserDAO userDao) {
this.userDao = userDao;
}
@Override
public void addUser(User user) {
// TODO Auto-generated method stub
userDao.addUser(user);
}
@Override
public List<User> getAllUser() {
// TODO Auto-generated method stub
return userDao.getAllUser();
}
@Override
public boolean delUser(String id) {
// TODO Auto-generated method stub
return userDao.delUser(id);
}
@Override
public User getUser(String id) {
// TODO Auto-generated method stub
return userDao.getUser(id);
}
@Override
public boolean updateUser(User user) {
// TODO Auto-generated method stub
return userDao.updateUser(user);
}
}
4.Control層結構如下:實現類UserController.java,代碼如下:
package com.zyh.web.controller;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.zyh.web.controller.entity.User;
import com.zyh.web.controller.service.IUserManager;
@Controller
@RequestMapping("/user")
public class UserController {
@Resource(name="userManager")
private IUserManager userManager;
@RequestMapping("/toAddUser")
public String toAddUser(){
return "/addUser";
}
@RequestMapping("/addUser")
public String addUser(User user){
userManager.addUser(user);
return "redirect:/user/getAllUser";
}
@RequestMapping("/getAllUser")
public String getAllUser(HttpServletRequest request){
List<User> user = userManager.getAllUser();
request.setAttribute("user", user);
return "/userManager";
}
@RequestMapping("/delUser")
public void delUser(String id,HttpServletResponse response){
String result = "{\"result\":\"error\"}";
if(userManager.delUser(id)){
result = "{\"result\":\"success\"}";
}
response.setContentType("application/json");
PrintWriter pw;
try {
pw = response.getWriter();
pw.write(result);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@RequestMapping("/getUser")
public String getUser(String id,HttpServletRequest request){
User user = userManager.getUser(id);
request.setAttribute("user", user);
return "editUser";
}
@RequestMapping("/updateUser")
public String updateUser(User user,HttpServletRequest request){
if(userManager.updateUser(user)){
userManager.getUser(user.getId());
request.setAttribute("user", user);
return "/editUser";
}else{
return "/error";
}
}
}
package com.zyh.web.controller;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.zyh.web.controller.entity.User;
import com.zyh.web.controller.service.IUserManager;
@Controller
@RequestMapping("/user")
public class UserController {
@Resource(name="userManager")
private IUserManager userManager;
@RequestMapping("/toAddUser")
public String toAddUser(){
return "/addUser";
}
@RequestMapping("/addUser")
public String addUser(User user){
userManager.addUser(user);
return "redirect:/user/getAllUser";
}
@RequestMapping("/getAllUser")
public String getAllUser(HttpServletRequest request){
List<User> user = userManager.getAllUser();
request.setAttribute("user", user);
return "/userManager";
}
@RequestMapping("/delUser")
public void delUser(String id,HttpServletResponse response){
String result = "{\"result\":\"error\"}";
if(userManager.delUser(id)){
result = "{\"result\":\"success\"}";
}
response.setContentType("application/json");
PrintWriter pw;
try {
pw = response.getWriter();
pw.write(result);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@RequestMapping("/getUser")
public String getUser(String id,HttpServletRequest request){
User user = userManager.getUser(id);
request.setAttribute("user", user);
return "editUser";
}
@RequestMapping("/updateUser")
public String updateUser(User user,HttpServletRequest request){
if(userManager.updateUser(user)){
userManager.getUser(user.getId());
request.setAttribute("user", user);
return "/editUser";
}else{
return "/error";
}
}
}
package com.zyh.web.controller.service;
import java.util.List;
import com.zyh.web.controller.dao.IUserDAO;
import com.zyh.web.controller.entity.User;
public class UserManager implements IUserManager {
private IUserDAO userDao;
public void setUserDao(IUserDAO userDao) {
this.userDao = userDao;
}
@Override
public void addUser(User user) {
// TODO Auto-generated method stub
userDao.addUser(user);
}
@Override
public List<User> getAllUser() {
// TODO Auto-generated method stub
return userDao.getAllUser();
}
@Override
public boolean delUser(String id) {
// TODO Auto-generated method stub
return userDao.delUser(id);
}
@Override
public User getUser(String id) {
// TODO Auto-generated method stub
return userDao.getUser(id);
}
@Override
public boolean updateUser(User user) {
// TODO Auto-generated method stub
return userDao.updateUser(user);
}
}
package com.zyh.web.controller.service;
import java.util.List;
import com.zyh.web.controller.entity.User;
public interface IUserManager {
public void addUser(User user);
public List<User> getAllUser();
public boolean delUser(String id);
public User getUser(String id);
public boolean updateUser(User user);
}
3.2 dao層結構如下:接口IUserDAO與實現類UserDAO,我們實現添刪改查,查詢包括一個User和所以User
com.zyh.web.controller.dao.IUserDAO
package com.zyh.web.controller.dao;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import com.zyh.web.controller.entity.User;
public class UserDAO implements IUserDAO {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public void addUser(User user) {
// TODO Auto-generated method stub
sessionFactory.getCurrentSession().save(user);
}
@Override
public List<User> getAllUser() {
// TODO Auto-generated method stub
String hql = "from User";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
return query.list();
}
@Override
public User getUser(String id) {
// TODO Auto-generated method stub
String hql = "from User u where u.id=?";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setString(0, id);
return (User) query.uniqueResult();
}
@Override
public boolean delUser(String id) {
// TODO Auto-generated method stub
String hql = "delete User u where u.id=?";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setString(0, id);
return (query.executeUpdate()>0);
}
@Override
public boolean updateUser(User user) {
// TODO Auto-generated method stub
String hql = "update User u set u.userName=?,u.age=? where u.id=?";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setString(0, user.getUserName());
query.setString(1, user.getAge());
query.setString(2, user.getId());
return (query.executeUpdate()>0);
}
}
package com.zyh.web.controller.dao;
import java.util.List;
import com.zyh.web.controller.entity.User;
public interface IUserDAO {
public void addUser(User user);
public List<User> getAllUser();
public User getUser(String id);
public boolean delUser(String id);
public boolean updateUser(User user);
}
package com.zyh.web.controller.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name="T_USER")
public class User {
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
@Column(length=32)
@Id
private String id;
@Column(length=32)
private String userName;
@Column(length=32)
private String age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
posted @
2013-06-01 10:49 Terry Zou 閱讀(4150) |
評論 (0) |
編輯 收藏
public static Bitmap getPicFromBytes(byte[] bytes, BitmapFactory.Options opts) {
if (bytes != null)
if (opts != null)
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);
else
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
return null;
}
這里我們主要來介紹一個BitmapFactory.Options這個類
BitmapFactory.Options這個類的詳解如下:
public Bitmap | inBitmap | If set, decode methods that take the Options object will attempt to reuse this bitmap when loading content. |
public int | inDensity | The pixel density to use for the bitmap. |
public boolean | inDither | If dither is true, the decoder will attempt to dither the decoded image. |
public boolean | inInputShareable | This field works in conjuction with inPurgeable. |
public boolean | inJustDecodeBounds | If set to true, the decoder will return null (no bitmap), but the out… |
public boolean | inMutable | If set, decode methods will always return a mutable Bitmap instead of an immutable one. |
public boolean | inPreferQualityOverSpeed | If inPreferQualityOverSpeed is set to true, the decoder will try to decode the reconstructed image to a higher quality even at the expense of the decoding speed. |
publicBitmap.Config | inPreferredConfig | If this is non-null, the decoder will try to decode into this internal configuration. |
public boolean | inPurgeable | If this is set to true, then the resulting bitmap will allocate its pixels such that they can be purged if the system needs to reclaim memory. |
public int | inSampleSize | If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory. |
public boolean | inScaled | When this flag is set, if inDensity and inTargetDensity are not 0, the bitmap will be scaled to match inTargetDensity when loaded, rather than relying on the graphics system scaling it each time it is drawn to a Canvas. |
public int | inScreenDensity | The pixel density of the actual screen that is being used. |
public int | inTargetDensity | The pixel density of the destination this bitmap will be drawn to. |
public byte[] | inTempStorage | Temp storage to use for decoding. |
public boolean | mCancel | Flag to indicate that cancel has been called on this object. |
public int | outHeight | The resulting height of the bitmap, set independent of the state of inJustDecodeBounds. |
public String | outMimeType | If known, this string is set to the mimetype of the decoded image. |
public int | outWidth | The resulting width of the bitmap, set independent of the state of inJustDecodeBounds. |
這個表格是從android sdk文檔里摘出來的,簡單看一下說明就明白是什么意思了。
下面我們回到我們的主題上來:怎樣獲取圖片的大小?
思路很簡單:
首先我們把這個圖片轉成Bitmap,然后再利用Bitmap的getWidth()和getHeight()方法就可以取到圖片的寬高了。
新問題又來了,在通過BitmapFactory.decodeFile(String path)方法將突破轉成Bitmap時,遇到大一些的圖片,我們經常會遇到OOM(Out Of Memory)的問題。怎么避免它呢?
這就用到了我們上面提到的BitmapFactory.Options這個類。
BitmapFactory.Options這個類,有一個字段叫做 inJustDecodeBounds 。SDK中對這個成員的說明是這樣的:
If set to true, the decoder will return null (no bitmap), but the out…
也就是說,如果我們把它設為true,那么BitmapFactory.decodeFile(String path, Options opt)并不會真的返回一個Bitmap給你,它僅僅會把它的寬,高取回來給你,這樣就不會占用太多的內存,也就不會那么頻繁的發生OOM了。
示例代碼如下:
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inJustDecodeBounds = true;
- Bitmap bmp = BitmapFactory.decodeFile(path, options);
- /* 這里返回的bmp是null */
復制代碼
這段代碼之后,options.outWidth 和 options.outHeight就是我們想要的寬和高了。
有了寬,高的信息,我們怎樣在圖片不變形的情況下獲取到圖片指定大小的縮略圖呢?
比如我們需要在圖片不變形的前提下得到寬度為200的縮略圖。
那么我們需要先計算一下縮放之后,圖片的高度是多少
- /* 計算得到圖片的高度 */
- /* 這里需要主意,如果你需要更高的精度來保證圖片不變形的話,需要自己進行一下數學運算 */
- int height = options.outHeight * 200 / options.outWidth;
- options.outWidth = 200;
- options.outHeight = height;
- /* 這樣才能真正的返回一個Bitmap給你 */
- options.inJustDecodeBounds = false;
- Bitmap bmp = BitmapFactory.decodeFile(path, options);
- image.setImageBitmap(bmp);
復制代碼
這樣雖然我們可以得到我們期望大小的ImageView
但是在執行BitmapFactory.decodeFile(path, options);時,并沒有節約內存。要想節約內存,還需要用到BitmapFactory.Options這個類里的 inSampleSize 這個成員變量。
我們可以根據圖片實際的寬高和我們期望的寬高來計算得到這個值。
- inSampleSize = options.outWidth / 200;
另外,為了節約內存我們還可以使用下面的幾個字段:
- options.inPreferredConfig = Bitmap.Config.ARGB_4444; // 默認是Bitmap.Config.ARGB_8888
- /* 下面兩個字段需要組合使用 */
- options.inPurgeable = true;
- options.inInputShareable = true;
posted @
2013-05-29 11:36 Terry Zou 閱讀(2829) |
評論 (0) |
編輯 收藏
1) 用第一種方式的弊端:
a. 會將原來系統中的對應的apk覆蓋掉,所以,最好先備份出來一份,用如下命令:
adb pull /system/app/xxxx.apk /home/
b. 有時候,會出現如下形式的錯誤信息:
failed to copy '/home/SoundRecorder.apk' to '/system/app/SoundRecorder.apk': Read-only file system
很明顯,/system/app目錄是只讀的,不能將文件push到這個目錄下。
解決方法,用直接安裝的方式進行安裝,如下:
adb install -r /home/SoundRecorder.apk //注: -r 表示強制安裝
這樣,會將應用程序安裝到 /data/local/tmp/ 目錄下。
2) 用第二種方式的話,設備中不回保存apk文件,如果以后刪除了這個應用,就要重新找到對應的apk,才能安裝。
posted @
2013-05-29 09:21 Terry Zou 閱讀(373) |
評論 (0) |
編輯 收藏
<context-param>的作用:
web.xml的配置中<context-param>配置作用
1. 啟動一個WEB項目的時候,容器(如:Tomcat)會去讀它的配置文件web.xml.讀兩個節點: <listener></listener> 和 <context-param></context-param>
2.緊接著,容器創建一個ServletContext(上下文),這個WEB項目所有部分都將共享這個上下文.
3.容器將<context-param></context-param>轉化為鍵值對,并交給ServletContext.
4.容器創建<listener></listener>中的類實例,即創建監聽.
5.在監聽中會有contextInitialized(ServletContextEvent args)初始化方法,在這個方法中獲得ServletContext = ServletContextEvent.getServletContext();
context-param的值 = ServletContext.getInitParameter("context-param的鍵");
6.得到這個context-param的值之后,你就可以做一些操作了.注意,這個時候你的WEB項目還沒有完全啟動完成.這個動作會比所有的Servlet都要早.
換句話說,這個時候,你對<context-param>中的鍵值做的操作,將在你的WEB項目完全啟動之前被執行.
7.舉例.你可能想在項目啟動之前就打開數據庫.
那么這里就可以在<context-param>中設置數據庫的連接方式,在監聽類中初始化數據庫的連接.
8.這個監聽是自己寫的一個類,除了初始化方法,它還有銷毀方法.用于關閉應用前釋放資源.比如說數據庫連接的關閉.
如:
<!-- 加載spring的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml,/WEB-INF/action-servlet.xml,/WEB-
INF/jason-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
又如: --->自定義context-param,且自定義listener來獲取這些信息
<context-param>
<param-name>urlrewrite</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>cluster</param-name>
<param-value>false</param-value>
</context-param>
<context-param>
<param-name>servletmapping</param-name>
<param-value>*.bbscs</param-value>
</context-param>
<context-param>
<param-name>poststoragemode</param-name>
<param-value>1</param-value>
</context-param>
<listener>
<listener-class>com.laoer.bbscs.web.servlet.SysListener</listener-class>
</listener>
public class SysListener extends HttpServlet implements ServletContextListener {
private static final Log logger = LogFactory.getLog(SysListener.class);
public void contextDestroyed(ServletContextEvent sce) {
//用于在容器關閉時,操作
}
//用于在容器開啟時,操作
public void contextInitialized(ServletContextEvent sce) {
String rootpath = sce.getServletContext().getRealPath("/");
System.out.println("-------------rootPath:"+rootpath);
if (rootpath != null) {
rootpath = rootpath.replaceAll("
\\\\", "/");
} else {
rootpath = "/";
}
if (!rootpath.endsWith("/")) {
rootpath = rootpath + "/";
}
Constant.ROOTPATH = rootpath;
logger.info("Application Run Path:" + rootpath);
String urlrewrtie =
sce.getServletContext().getInitParameter("urlrewrite"); boolean burlrewrtie = false;
if (urlrewrtie != null) {
burlrewrtie = Boolean.parseBoolean(urlrewrtie);
}
Constant.USE_URL_REWRITE = burlrewrtie;
logger.info("Use Urlrewrite:" + burlrewrtie);
其它略之....
}
}
/*最終輸出
-------------rootPath:D:\tomcat_bbs\webapps\BBSCS_8_0_3\
2009-06-09 21:51:46,526 [com.laoer.bbscs.web.servlet.SysListener]-[INFO]
Application Run Path:D:/tomcat_bbs/webapps/BBSCS_8_0_3/
2009-06-09 21:51:46,526 [com.laoer.bbscs.web.servlet.SysListener]-[INFO]
Use Urlrewrite:true
2009-06-09 21:51:46,526 [com.laoer.bbscs.web.servlet.SysListener]-[INFO]
Use Cluster:false
2009-06-09 21:51:46,526 [com.laoer.bbscs.web.servlet.SysListener]-[INFO]
SERVLET MAPPING:*.bbscs
2009-06-09 21:51:46,573 [com.laoer.bbscs.web.servlet.SysListener]-[INFO]
Post Storage Mode:1
*/
context-param和init-param區別
web.xml里面可以定義兩種參數:
(1)application范圍內的參數,存放在servletcontext中,在web.xml中配置如下:
<context-param>
<param-name>context/param</param-name>
<param-value>avalible during application</param-value>
</context-param>
(2)servlet范圍內的參數,只能在servlet的init()方法中取得,在web.xml中配置如下:
<servlet>
<servlet-name>MainServlet</servlet-name>
<servlet-class>com.wes.controller.MainServlet</servlet-class>
<init-param>
<param-name>param1</param-name>
<param-value>avalible in servlet init()</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
在servlet中可以通過代碼分別取用:
package com.wes.controller;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
public class MainServlet extends HttpServlet ...{
public MainServlet() ...{
super();
}
public void init() throws ServletException ...{
System.out.println("下面的兩個參數param1是在servlet中存放的");
System.out.println(this.getInitParameter("param1"));
System.out.println("下面的參數是存放在servletcontext中的");
System.out.println(getServletContext().getInitParameter("context/param"));
}
}
第一種參數在servlet里面可以通過getServletContext().getInitParameter("context/param")得到
第二種參數只能在servlet的init()方法中通過this.getInitParameter("param1")取得.
文章來源自:
http://www.cnblogs.com/hzj-/articles/1689836.html
posted @
2013-05-27 11:45 Terry Zou 閱讀(174) |
評論 (0) |
編輯 收藏
回調函數其實用起來比較簡單,主要有三個部分
第一部分:定義一個接口用于回調;
如下所示:
public interface CallBackInterface {
public void doSome();
public void exectueMethod();
}
第二部分:在一個類里面把它當做參數并用到該參數
如下所示:
public class MethodB {
public double getTime(CallBackInterface callBack){
long start = System.currentTimeMillis();
callBack.exectueMethod();
long end = System.currentTimeMillis();
System.out.println("cost time="+(end-start));
return end-start;
}
}
第三部分:在另外一個類里面調用到getTime方法并實現回調函數
如下所示:
public class MethodA {
public static void main(String[] args) {
MethodB b = new MethodB();
double d = b.getTime(new CallBackInterface() {
@Override
public void exectueMethod() {
// TODO Auto-generated method stub
new MethodA().testMethod();
}
@Override
public void doSome() {
// TODO Auto-generated method stub
}
});
System.out.println("d="+d);
}
public void testMethod(){
for(int i=0;i<10000;i++)
System.out.print("");
}
}
輸出結果:
cost time=31
d=31.0
理解“回調函數”
所謂回調,就是客戶程序CLIENT調用服務程序SERVER中的某個函數SA,然后SERVER又在某個時候反過來調用CLIENT中的某個函數CB,對于CLIENT來說,這個CB便叫做回調函數。例如Win32下的窗口過程函數就是一個典型的回調函數。
一般說來,CLIENT不會自己調用CB,CLIENT提供CB的目的就是讓SERVER來調用它,而且是CLIENT不得不提供。由于SERVER并不知道CLIENT提供的CB叫甚名誰,所以SERVER會約定CB的接口規范(函數原型),然后由CLIENT提前通過SERVER的一個函數R告訴SERVER自己將要使用CB函數,這個過程稱為回調函數的注冊,R稱為注冊函數。Web SERVERerviCliente以及Java的RMI都用到回調機制,可以訪問遠程服務器程序。
下面舉個通俗的例子:
某天,我打電話向你請教問題,當然是個難題,:),你一時想不出解決方法,我又不能拿著電話在那里傻等,于是我們約定:等你想出辦法后打手機通知我,這樣,我就掛掉電話辦其它事情去了。過了XX分鐘,我的手機響了,你興高采烈的說問題已經搞定,應該如此這般處理。故事到此結束。這個例子說明了“異步+回調”的編程模式。其中,你后來打手機告訴我結果便是一個“回調”過程;我的手機號碼必須在以前告訴你,這便是注冊回調函數;我的手機號碼應該有效并且手機能夠接收到你的呼叫,這是回調函數必須符合接口規范。
通過上面個人感覺到回調函數更多的應用就是結合異步。比如:ajax中jServer通過組件和服務器的異步通信。
什么是回調函數
精妙比喻:回調函數還真有點像您隨身帶的BP機:告訴別人號碼,在它有事情時Call您
回調用于層間協作,上層將本層函數安裝在下層,這個函數就是回調,而下層在一定條件下觸發回調,例如作為一個驅動,是一個底層,他在收到一個數據時,除了完成本層的處理工作外,還將進行回調,將這個數據交給上層應用層來做進一步處理,這在分層的數據通信中很普遍。
其實回調和API非常接近,他們的共性都是跨層調用的函數。但區別是API是低層提供給高層的調用,一般這個函數對高層都是已知的;而回調正好相反,他是高層提供給底層的調用,對于低層他是未知的,必須由高層進行安裝,這個安裝函數其實就是一個低層提供的API,安裝后低層不知道這個回調的名字,但它通過一個函數指針來保存這個回調,在需要調用時,只需引用這個函數指針和相關的參數指針。
其實:回調就是該函數寫在高層,低層通過一個函數指針保存這個函數,在某個事件的觸發下,低層通過該函數指針調用高層那個函數。
【參考】
http://blog.csdn.net/sweetwxh/article/details/2067139
http://liutiemeng.blog.51cto.com/120361/18874
http://kidult.iteye.com/blog/148982
public static void main(String[] args) {
MethodB b = new MethodB();
double d = b.getTime(new CallBackInterface() {
@Override
public void exectueMethod() {
// TODO Auto-generated method stub
new MethodA().testMethod();
}
@Override
public void doSome() {
// TODO Auto-generated method stub
}
});
System.out.println("d="+d);
}
public void testMethod(){
for(int i=0;i<10000;i++)
System.out.print("");
}
posted @
2013-05-27 11:13 Terry Zou 閱讀(154) |
評論 (0) |
編輯 收藏
摘要: --------------------------------------------------(一)androidpn-server服務器端啟動的理解和分析-----------------------------------------------
在Androidpn的底層主要采用的兩大框架mina和openfire兩大框架,其中mi...
閱讀全文
posted @
2013-05-24 17:05 Terry Zou 閱讀(5208) |
評論 (1) |
編輯 收藏
這個方法的含義說明:
這個方法的意思就是在jvm中增加一個關閉的鉤子,當jvm關閉的時候,會執行系統中已經設置的所有通過方法addShutdownHook添加的鉤子,當系統執行完這些鉤子后,jvm才會關閉。所以這些鉤子可以在jvm關閉的時候進行內存清理、對象銷毀等操作。
測試類如下:
- public class RunTimeTest {
-
-
-
- public static void main(String[] args) {
- Thread thread1 = new Thread() {
- public void run() {
- System.out.println("thread1...");
- }
- };
- Thread thread2 = new Thread() {
- public void run() {
- System.out.println("thread2...");
- }
- };
- Thread shutdownThread = new Thread() {
- public void run() {
- System.out.println("shutdownThread...");
- }
- };
- Runtime.getRuntime().addShutdownHook(shutdownThread);
- thread1.start();
- thread2.start();
- }
- }
打印結果為:
thread2...
thread1...
shutdownThread...
或者:
thread2...
thread1...
shutdownThread...
結論:
無論是先打印thread1還是thread2,shutdownThread 線程都是最后執行的(因為這個線程是在jvm執行關閉前才會執行)。
posted @
2013-05-23 16:34 Terry Zou 閱讀(233) |
評論 (0) |
編輯 收藏
對Java程序來說,只要還有一個前臺線程在運行,這個進程就不會結束,如果一個進程中只有后臺線程在運行,這個進程就會結束。前臺線程是相對后臺線程而言的,前面所介紹的線程都是前臺線程。那么什么樣的線程是后臺線程呢?如果某個線程對象在啟動(調用start()方法)之前調用了setDaemon(true)方法,這個線程就變成了后臺線程。下面來看一下進程中只有后臺線程在運行的情況,如下所示:
范例:ThreadDaemon.java
01 public class ThreadDaemon
02 {
03 public static void main(String args[])
04 {
05 ThreadTest t = new ThreadTest() ;
06 Thread tt = new Thread(t) ;
07 tt.setDaemon(true) ; // 設置后臺運行
08 tt.start();
09 }
10 }
11
12 class ThreadTest implements Runnable
13 {
14 public void run()
15 {
16 while(true)
17 {
18 System.out.println(Thread.currentThread().getName()+"is running.");
19 }
20 }
21 }
從上面的程序和運行結果(圖9-4)上,可以看到:雖然創建了一個無限循環的線程,但因為它是后臺線程,整個進程在主線程結束時就隨之終止運行了。這驗證了
進程中只有后臺線程運行時,進程就會結束的說法。
posted @
2013-05-23 09:09 Terry Zou 閱讀(460) |
評論 (0) |
編輯 收藏
1、PendingIntent作用
根據字面意思就知道是延遲的intent,主要用來在某個事件完成后執行特定的Action。PendingIntent包含了Intent及Context,所以就算Intent所屬程序結束,PendingIntent依然有效,可以在其他程序中使用。
常用在通知欄及短信發送系統中。
PendingIntent一般作為參數傳給某個實例,在該實例完成某個操作后自動執行PendingIntent上的Action,也可以通過PendingIntent的send函數手動執行,并可以在send函數中設置OnFinished表示send成功后執行的動作。
2.舉例(通知欄應用)
界面A 定義一個notification
NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
int icon = R.drawable.notification;
long when = System.currentTimeMillis()+2000;
Notification n = new Notification(icon,"標題",when);
n.defaults = Notification.DEFAULT_SOUND;
n.flags |= Notification.FLAG_AUTO_CANCEL;
Intent intent = new Intent(this,B.class);
PendingIntent pi = new PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_CANCEL_CURRENT);
n.setLatesEventInfo(this,"通知欄demo提醒title","通知欄demo提醒text",pi);
nm.notify(0,n);
B.界面Intent intent = getIntent();
String title = intent.getStringExtra("title");
效果,當A界面顯示,生成一個按鈕,點擊該按鈕生成如上所示的通知欄,點擊通知欄,則顯示B界面,參數title為所顯示的值。
3、Intent和PendingIntent的區別a. Intent是立即使用的,而PendingIntent可以等到事件發生后觸發,PendingIntent可以cancel
b. Intent在程序結束后即終止,而PendingIntent在程序結束后依然有效
c. PendingIntent自帶Context,而Intent需要在某個Context內運行
d. Intent在原task中運行,PendingIntent在新的task中運行
posted @
2013-05-22 15:34 Terry Zou 閱讀(245) |
評論 (0) |
編輯 收藏
PhoneStateListener
1.對特定的電話狀態的監聽,包括服務的狀態、信號強度、消息等待指示(語音信箱)、通話轉移、呼叫狀態、設備單元位置、數據連接狀態、數據流量方向。一些電話信息受權限保護,應用程序不會收到受保護的信息的更新,除非在manifest文件中有適當的權限聲明。凡申請許可,有適當的LISTEN_標志。
2.對監聽的話做處理
Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case LISTEN_SERVICE_STATE:/*Listen for changes to the network service state (cellular).對網絡服務狀態監聽*/
PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);
break;
case LISTEN_SIGNAL_STRENGTH:/*Listen for changes to the network signal strength (cellular).對網絡信號強度變化監聽*/
PhoneStateListener.this.onSignalStrengthChanged(msg.arg1);
break;
case LISTEN_MESSAGE_WAITING_INDICATOR:/*Listen for changes to the message-waiting indicator.對消息等待指示的變化監聽*/
PhoneStateListener.this.onMessageWaitingIndicatorChanged(msg.arg1 != 0);
break;
case LISTEN_CALL_FORWARDING_INDICATOR:/*Listen for changes to the call-forwarding indicator.對通話轉移指示的變化監聽*/
PhoneStateListener.this.onCallForwardingIndicatorChanged(msg.arg1 != 0);
break;
case LISTEN_CELL_LOCATION:/*Listen for changes to the device's cell location. Note that this will result in frequent callbacks to the listener.對設備單元位置的變化監聽,這會導致頻繁的監聽回調。*/
PhoneStateListener.this.onCellLocationChanged((CellLocation)msg.obj);
break;
case LISTEN_CALL_STATE:/*Listen for changes to the device call state.對設備呼叫狀態的變化監聽。*/
PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj);
break;
case LISTEN_DATA_CONNECTION_STATE:/*Listen for changes to the data connection state (cellular).對數據連接狀態的變化監聽。*/
PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1, msg.arg2);
PhoneStateListener.this.onDataConnectionStateChanged(msg.arg1);
break;
case LISTEN_DATA_ACTIVITY:/*Listen for changes to the direction of data traffic on the data connection (cellular).對數據流量移動方向的變化監聽*/
PhoneStateListener.this.onDataActivity(msg.arg1);
break;
case LISTEN_SIGNAL_STRENGTHS:/*Listen for changes to the network signal strengths (cellular).對網絡信號強度的變化監聽*/
PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
break;
}
}
};
3.監聽變化后發送消息
IPhoneStateListener callback = new IPhoneStateListener.Stub() {
public void onServiceStateChanged(ServiceState serviceState) {
Message.obtain(mHandler, LISTEN_SERVICE_STATE, 0, 0, serviceState).sendToTarget();
}
public void onSignalStrengthChanged(int asu) {
Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTH, asu, 0, null).sendToTarget();
}
public void onMessageWaitingIndicatorChanged(boolean mwi) {
Message.obtain(mHandler, LISTEN_MESSAGE_WAITING_INDICATOR, mwi ? 1 : 0, 0, null)
.sendToTarget();
}
public void onCallForwardingIndicatorChanged(boolean cfi) {
Message.obtain(mHandler, LISTEN_CALL_FORWARDING_INDICATOR, cfi ? 1 : 0, 0, null)
.sendToTarget();
}
public void onCellLocationChanged(Bundle bundle) {
CellLocation location = CellLocation.newFromBundle(bundle);
Message.obtain(mHandler, LISTEN_CELL_LOCATION, 0, 0, location).sendToTarget();
}
public void onCallStateChanged(int state, String incomingNumber) {
Message.obtain(mHandler, LISTEN_CALL_STATE, state, 0, incomingNumber).sendToTarget();
}
public void onDataConnectionStateChanged(int state, int networkType) {
Message.obtain(mHandler, LISTEN_DATA_CONNECTION_STATE, state, networkType, null).
sendToTarget();
}
public void onDataActivity(int direction) {
Message.obtain(mHandler, LISTEN_DATA_ACTIVITY, direction, 0, null).sendToTarget();
}
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength).sendToTarget();
}
};
posted @
2013-05-18 09:38 Terry Zou 閱讀(349) |
評論 (0) |
編輯 收藏