新换了博客的UI,HTML5扁平化三栏样式。这几天有些忙,还有许许多多要优化的地方没时间修改,后面有时间再进行优化,博客暂且就这样子了~

 

天晴,心情不多云。

Edit By 小树

AndroidAnnotations是一个能够让你快速进行Android开发的开源框架,它能让你专注于真正重要的地方。使代码更加精简,使项目更加容易维护,它的目标就是“Fast Android Development.Easy maintainance”.
 

 

希望此篇能帮到大家,本系列教程目录:转载请链接并注明:转自 小树技术博客 .

AndroidAnnotations注解框架之介绍+配置(一): (飞机票)

[重要]关于Android Application的介绍和用法: (飞机票)
 

1.使用 @EApplication 定义Application

@EApplication
public class MyApplication extends Application {

}

 

2.使用Application

使用 @App 把Application注射到activity或其他组件中

@EActivity
public class MyActivity extends Activity {

@App
MyApplication application;

}

@EBean
public class MyBean {

@App
MyApplication application;

}


 

此后,用法则与普通的android application用法一致,请参考

Android真正的入口:Application的用法介绍:链接

 

AndroidAnnotations是一个能够让你快速进行Android开发的开源框架,它能让你专注于真正重要的地方。使代码更加精简,使项目更加容易维护,它的目标就是“Fast Android Development.Easy maintainance”.
 

 

希望此篇能帮到大家,本系列教程目录:转载请链接并注明:转自 小树技术博客 .

AndroidAnnotations注解框架之介绍+配置(一) (飞机票)

[重要]关于Android Activity的介绍和用法:(飞机票)
 

 

1.使用 @EActivity 定义 Activity

@EActivity注释的Activity,其参数值必须是一个有效的布局资源id,将作为活动视图Content View的内容。

当然,你也可以不使用参数,让value为空,那么你就需要自己在onCreate()中进行视图的初始化

 

@EActivity(R.layout.main)
public class MyActivity extends Activity {

}
 

@EActivity
public class MyListActivity extends ListActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}

}
 

2.注意事项

 

使用 @Activity 注解的 Activity ,与Fragment相同,都会由 AndroidAnnotations框架自动生成一个中间类,Activity_ ,这个类才是真正android系统识别
到和调用到的有内容的类,因此,任何跳转或者是注射,都应该使用这个类,例如:

@EActivity
public class MyActivity extends Activity {
// …
}

将在同一个包,但在另一个源文件夹下,产生以下子类

public final class MyActivity_ extends MyActivity {
// …
}

这个子类将行为添加到您的活动覆盖一些方法,例如onCreate(),委托调用父类。

因此,AndroidManifest.xml中,你必须在所有使用@注解的Activity上,添加下划线_,如:

<activity android:name=”.MyListActivity_” />

Q:如何启动一个带注释的activity?

A:

通常在安卓,你使用以下代码启动一个activity:

startActivity(this, MyListActivity.class);

但是,使用AA框架之后,你的启动代码就要改成:

startActivity(this, MyListActivity_.class);

AA也提供一个静态的助手,让你启动自动生成的activity:

// Starting the activity
MyListActivity_.intent(context).start();

// Building an intent from the activity
Intent intent = MyListActivity_.intent(context).get();

// You can provide flags
MyListActivity_.intent(context).flags(FLAG_ACTIVITY_CLEAR_TOP).start();

// You can even provide extras defined with @Extra in the activity
MyListActivity_.intent(context).myDateExtra(someDate).start();

你可以使用 startActivityForResult() 获取 activity 的返回值

MyListActivity_.intent(context).startForResult();
 

 



### 【Activity

pic 一个Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务,例如拨号、拍照、发送email、看地图。每一个activity被给予一个窗口,在上面可以绘制用户接口。窗口通常充满屏幕,但也可以小于屏幕而浮于其它窗口之上。一个应用程序通常由多个activities组成,他们通常是松耦合关系。通常,一个应用程序中的activity被指定为”main”activity,当第一次启动应用程序的时候呈现给用户的那个activity。每一个activity然后可以启动另一个activity为了完成不同的动作。每一次一个activity启动,前一个activity就停止了,但是系统保留activity在一个栈上(“back stack”)。当一个新activity启动,它被推送到栈顶,取得用户焦点。Back Stack符合简单“后进先出”原则,所以,当用户完成当前activity然后点击back按钮,它被弹出栈(并且被摧毁),然后之前的activity恢复。

当一个activity因新的activity启动而停止,它被通知这种状态转变通过activity的生命周期回调函数。有许多回调函数一个activity可能会收到,源于它自己的状态变化-无论系统创建它、停止它、恢复它、摧毁它-并且每个回调提供你完成适合这个状态的指定工作的机会。例如,当停止的时候,你的activity应该释放任何大的对象,例如网络数据库连接。当activity恢复,你可以重新获得必要的资源和恢复被中断的动作。这些状态转换都是activity的生命周期的部分。

 

### 【Creating an Activity

 

创建一个activity,你必须创建一个Activity的子类(或者一个Activity的子类的子类)。在你的子类中,你需要实现系统回调的回调方法,当activity在它的生命周期的多种状态中转换的时候,例如当activity被创建、停止、恢复或摧毁。两个最重要的回调方法是:

onCreate()你必须实现这个方法。系统调用它当创建你的activity的时候。在你的实现中,你应该初始化你的activity的基本的组件。更重要的是,这里就是你必须调用setContentView()来定义activity用户接口而已的地方。onPause()系统调用这个方法当用户离开你的activity(虽然不总是意味着activity被摧毁)。这通常是你应该提交任何变化,那此将会超越user session而存在的(因为用户可能不再回来)。  有若干其它生命周期回调函数你应该使用为了提供一个流畅的用户体验,并表操作异常中断会引起你的activity被中断甚至被摧毁。

1、Implementing a user interface

一个activity的用户接口被一个层次化的视图提供--继承于View类的对象。每个View控制activity窗口中的一个特定矩形区域并且能响应用户交互。例如,一个view可能是个button,初始化动作当用户触摸它的时候。

Android提供大量预定义的view,你可以使用来设计和组件你的布局。“Widgets”是一种给屏幕提供可视化(并且交互)元素的view,例如按钮、文件域、复选框或者仅仅是图像。“Layouts”是继承于ViewGroup的View,提供特殊的布局模型为它的子view,例如线程布局、格子布局或相关性布局。你可以子类化View和ViewGroup类(或者存在的子类)来创建自己的widget和而已并且应用它们到你的activity布局中。

最普通的方法是定义一个布局使用view加上XML布局文件保存在你的程序资源里。这样,你可以单独维护你的用户接口设计,而与定义activity行为的代码无关。你可以设置布局作为UI使用setContentView(),传递资源布局的资源ID。可是,你也可以创建新Views在你的activity代码,并且创建一个view层次通过插入新Views到ViewGroup,然后使用那个布局通过传递到根ViewGroup给setContentView()。

 

### 【Declaring the activity in the manifest

 

你必须声明你的activity在manifest文件为了它可以被系统访问。要声明你的activity,打开你的manifest文件,添加一个<activity>元素作为<application>元素的子元素。例如:



 

### 【Using intent filters

 

一个<activity>元素也能指定多种intent filters--使用<inetent-filter>元素--为了声明其它应用程序可以激活它。

当你创建一个新应用程序使用Android SDK工具,存根activity自动为你创建,包含一个intent filter,声明了activity响应”main”动作,并且应该被 放置 在”launcher”分类。Intent filter看起来像这个样子。



<action>元素指定这是一个”main”入口点对这个应用程序。<category>元素指定,这个activity应该被列入系统应用程序列表中(为了允许用户启动这个activity)。

如果你希望应用程序自包含,并且不希望别的应用程序激活它的activities,那么你不需要任何其它intent filters。只有一个activity应该有“main”动作和”launcher“分类,就像前面这个例子。你不希望被其它应用程序访问原Activities应该没有intent filters而且你能启动他们通过自己显示的intent。

可是,如果你希望你的activity响应影含的intents,从其它应用程序(和你自己的),那么你必须定义额外的intent filters为这个activity。每一种你希望响应的类型的intent,你必须包含<intent-filter>,包含<action>元素,可选的,一个<category>元素并且/或一个<data>元素。这些元素指定你的activity能响应的intent的类型。

 

### 【Starting an Activity

 

你可以开启另一个activity通过startActivity(),传递一个Intent描述了你希望启动的Activity。Intent指定要么准备的activity你希望启动或描述你希望完成的动作(操作系统选择合适的activity为你,可能来自定不同的应用程序)。一个intent可以传输小量数据被启动的activity使用。

完全工作在你的应用程序之内,你将经常需要简单的启动一个未知的activity。你可以这么通过创建一个intent显示的定义你希望启动的activity,使用类名。例如,下面显示一个activity怎么启动另一个activity命名为SignInActivity:



可是,你的应用程序或许希望执行一些动作,例如发送一份邮件、文件消息或者状态更新,使用你的activity的数据。在这种情况下,你的应用程序或许没有它自己的activity来完成这个动作,因此你可以促使设备上其它应用程序提供的activity来完成你的动作。这才是intent真正有价值的地方--你可以创建一个intent描述一个你希望执行的动作,然后系统启动一个合适的activity从其它应用程序。如果有多种activities可以处理这个intent,那么 用户可以选择哪一个来执行。例如,如果你希望允许用户发送邮件,你可以创建下面的Intent:



EXTRA_EMAIL额外的添加给intent一个字符串数组指定email地址,当一个邮件应用程序响应这个intent的时候,它读取这些字符串数组并且放置他们到相应字段。在这种情况下,email应用程序的activity启动并且当用户执行完,你的activity恢复。

 

### 【Starting an activity for a result

 

有时,你或许希望接收一个结果从你启动的activity。在这种情况下,开启这个activity通过startActivityForResult()(而不是startActivity())。然后从随后的activity接收结果,实现onActiviryResult()回调函数。当随后的activity完成,它返回一个结果给你的onActivityResult()函数通过一个intent。

例如,或许你希望用户选择他们中的一个联系人,所以你的activity可以对这个联系人做些事情。下面是你怎么建立这样一个Intent和操作结果:



这个例子展现了基本的逻辑你应该使用的在你的onActivityResult()函数中,为了操作一个activity的结果。第一个条件检测是否请求成功--如果是,那么 resultCode将会是RESULT_OK--并且是否这个请求是否是这个响应是响知道--在这种情况下,requestCode匹配第二个参数用startActivityForResult()的参数。在那里,代码操作activity结果通过查询返回在intent中的数据(data参数)。

将发生的是,一个ContentResolver实现查询content provider,返回一个Cursor允许读查询的数据。

 

### 【Shut Down an Activity

 

你可以关闭一个activity通过调用自身的finish()方法。你也可以关闭一个独立的activity你之前启动的通过finiActivity()。

注意:在大多数情况下,你不应该显示结果一个activity使用这些方法。正在下文所讨论的关于activity的生命周期,Android系统管理一个activity的生命周期为你,所以你不需要结果你自己的activity。调用这些函数对用户体验有害并且只有在你决对不希望用户返回到这个activity的情况下。

 

### 【Activity四种基本状态

 

1.Active/Runing
一个新 Activity 启动入栈后,它显示在屏幕最前端,处理是处于栈的最顶端(Activity栈顶),此时它处于可见并可和用户交互的激活状态,叫做活动状态或者运行状态(active or running)。

2. Paused

当 Activity失去焦点, 被一个新的非全屏的Activity 或者一个透明的Activity 被放置在栈顶,此时的状态叫做暂停状态(Paused)。此时它依然与窗口管理器保持连接,Activity依然保持活力(保持所有的状态,成员信息,和窗口管理器保持连接),但是在系统内存极端低下的时候将被强行终止掉。所以它仍然可见,但已经失去了焦点故不可与用户进行交互。

3. Stoped

如果一个Activity被另外的Activity完全覆盖掉,叫做停止状态(Stopped)。它依然保持所有状态和成员信息,但是它不再可见,所以它的窗口被隐藏,当系统内存需要被用在其他地方的时候,Stopped的Activity将被强行终止掉。

4. Killed

如果一个Activity是Paused或者Stopped状态,系统可以将该Activity从内存中删除,Android系统采用两种方式进行删除,要么要求该Activity结束,要么直接终止它的进程。当该Activity再次显示给用户时,它必须重新开始和重置前面的状态。




### 【Activity状态的转换

 

当一个 Activity 实例被创建、销毁或者启动另外一个 Activity 时,它在这四种状态之间进行转换,这种转换的发生依赖于用户程序的动作。下图说明了 Activity 在不同状态间转换的时机和条件:



android-activity-four-state


图**1. Activity 的状态转换


如上所示,Android 程序员可以决定一个 Activity 的“生”,但不能决定它的“死”,也就是说程序员可以启动一个 Activity,但是却不能手动的“结束”一个 Activity。当你调用 Activity.finish()方法时,结果和用户按下 BACK 键一样:告诉 Activity Manager 该 Activity 实例完成了相应的工作,可以被“回收”。随后 Activity Manager 激活处于栈第二层的 Activity 并重新入栈,同时原 Activity 被压入到栈的第二层,从 Active 状态转到 Paused 状态。例如:从 Activity1 中启动了 Activity2,则当前处于栈顶端的是 Activity2,第二层是 Activity1,当我们调用Activity2.finish()方法时,Activity Manager 重新激活 Activity1 并入栈,Activity2 从 Active 状态转换 Stoped 状态,Activity1. onActivityResult(int requestCode, int resultCode, Intent data)方法被执行,Activity2 返回的数据通过data参数返回给 Activity1。




### 【Activity栈

 


Android 是通过一种 Activity 栈的方式来管理 Activity 的,一个 Activity 的实例的状态决定它在栈中的位置。处于前台的 Activity 总是在栈的顶端,当前台的 Activity 因为异常或其它原因被销毁时,处于栈第二层的 Activity 将被激活,上浮到栈顶。当新的 Activity 启动入栈时,原 Activity 会被压入到栈的第二层。一个 Activity 在栈中的位置变化反映了它在不同状态间的转换。Activity 的状态与它在栈中的位置关系如下图所示



android-activity-stack


2. Activity 的状与它在中的位置


如上所示,除了最顶层即处在 Active 状态的 Activity 外,其它的 Activity 都有可能在系统内存不足时被回收,一个 Activity 的实例越是处在栈的底层,它被系统回收的可能性越大。系统负责管理栈中 Activity 的实例,它根据 Activity 所处的状态来改变其在栈中的位置。




### 【Activity状态方法通知

 

下面的图显示了Activity的重要状态转换,矩形框表明Activity在状态转换之间的回调接口,开发人员可以重载实现以便执行相关代码,带有颜色的椭圆形表明Activity所处的状态。


android-activity


3. Activity 的状**转换的方法和实现

在上图中,Activity有三个关键的循环:

1. 整个的生命周期,从onCreate(Bundle)开始到onDestroy()结束。Activity在onCreate()设置所有的“全局”状态,在onDestory()释放所有的资源。例如:某个Activity有一个在后台运行的线程,用于从网络下载数据,则该Activity可以在onCreate()中创建线程,在onDestory()中停止线程。

2. 可见的生命周期,从onStart()开始到onStop()结束。在这段时间,可以看到Activity在屏幕上,尽管有可能不在前台,不能和用户交互。在这两个接口之间,需要保持显示给用户的UI数据和资源等,例如:可以在onStart中注册一个IntentReceiver来监听数据变化导致UI的变动,当不再需要显示时候,可以在onStop()中注销它。onStart(),onStop()都可以被多次调用,因为Activity随时可以在可见和隐藏之间转换。

3. 前台的生命周期,从onResume()开始到onPause()结束。在这段时间里,该Activity处于所有 Activity的最前面,和用户进行交互。Activity可以经常性地在resumed和paused状态之间切换,例如:当设备准备休眠时,当一个 Activity处理结果被分发时,当一个新的Intent被分发时。所以在这些接口方法中的代码应该属于非常轻量级的。



AndroidAnnotations是一个能够让你快速进行Android开发的开源框架,它能让你专注于真正重要的地方。使代码更加精简,使项目更加容易维护,它的目标就是“Fast Android Development.Easy maintainance”.
 

 

希望此篇能帮到大家,本系列教程目录:转载请链接并注明:转自 小树技术博客 .

AndroidAnnotations注解框架之介绍+配置(一) (飞机票)
 

 

 

Anno 提供了一种类型安全的方式,让你可以去调用Android SharedPreferences , 下面带来一些Preferences常用的操作,并在最后附上一个项目的Demo片段

 

1.定义Preferences

 

首先,你应该创建一个以@SharedPref定义的接口,作为一个 SharedPreferences

@SharedPref
public interface MyPrefs {

// The field name will have default value "John"
@DefaultString("John")
String name();

// The field age will have default value 42
@DefaultInt(42)
int age();

// The field lastUpdated will have default value 0
long lastUpdated();

}
基于这个操作, AndroidAnnotations框架将会自动构建一个SharedPreferences子类,在你的原类名基础上加上下划线,如MyPref你可以通过@Pref注释得到这个实例

注意: 实例的类型必须以新生成的类为类型

@EActivity
public class MyActivity extends Activity {

@Pref
MyPrefs_ myPrefs;

// ...

}
其中,定义值目前有:

@DefaultBoolean

@DefaultFloat

@DefaultInt

@DefaultLong

@DefaultString

@DefaultStringSet

@DefaultRes
 

 

2.使用pref

 

// Simple edit
myPrefs.name().put(“John”);

// Batch edit
myPrefs.edit()
.name()
.put(“John”)
.age()
.put(42)
.apply();

// Preference clearing:
myPrefs.clear();

// Check if a value exists:
boolean nameExists = myPrefs.name().exists();

// Reading a value
long lastUpdated = myPrefs.lastUpdated().get();

// Reading a value and providing a fallback default value
long now = System.currentTimeMillis();
long lastUpdated = myPrefs.lastUpdated().getOr(now);
 

3.设置默认值

 

注意: anno 3.0 版本之后才有这个功能

@SharedPref
public interface MyPrefs {
@DefaultInt(0)
int versionCode();

@DefaultString("无")
String widgetBackground();

@DefaultBoolean(false)
boolean classTableAsFirstScreen();}</pre>

 

4.使用String 资源

 

注意:anno 3.1 后才有此功能

@SharedPref
public interface MyPrefs {
@DefaultString(value = “John”, keyRes = R.string.myPrefKey)
String name();

@DefaultRes
String defaultPrefAge(keyRes = R.string.myOtherPrefKey);

}
 

5.作用域

 

你还可以通过设置value来设定pref的作用域

例如:

  • ACTIVITY :名为:MyActivity_MyPrefs 的pref

  • ACTIVITY_DEFAULT 名为 MyActivity 的 pref
    ( 可以通过 activity.getPreferences() 获取到);

  • APPLICATION_DEFAULT <span style="font-family: Courier New;">:</span> 使用默认的单例名称
     

 

 

 

 

 

因此,如果一个SharedPreference接口的定义是给一个应用程序application下所有activity所使用的话,应该使用以下作用域:

@SharedPref(value=SharedPref.Scope.UNIQUE)
public interface MyPrefs {

 

6.在PreferenceActivity中使用它

 

同样地,使用 Android PreferenceActivity能够改写任何已用@SharedPref注解的SharedPref

@SharedPref()
public interface MyPrefs {

}

 

public class PrefsActivity extends PreferenceActivity {

public static String PREF_NAME = "MyPrefs";

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

            // Using your MyPrefs values 
    this.getPreferenceManager().setSharedPreferencesName(PREF_NAME);

            // Opening the layout 
    addPreferencesFromResource(R.xml.prefs);
}

}
 

7.实际项目demo片段

 

SharedPref

**

  • @Title:应用程序配置文件AppConfig
  • @Description: 使用SharedPref储存本地数据
  • @author qsuron
  • @date 2014-9-23
  • @email admin@qiushurong.cn
    */
    @SharedPref( value = SharedPref.Scope.UNIQUE)
    public interface AppConfig {

    @DefaultInt(0)
    int versionCode(); // 当前的versionCode

    @DefaultString(“”)
    String userName(); // 用户

    @DefaultString(“”)
    String password(); // 密码
    }
    片段1

     config = new cn.scau.scautreasure.AppConfig_(context);

    RingerMode duringMode = RingerMode.getModeByValue(config.duringClassRingerMode().get());
    RingerMode afterMode = RingerMode.getModeByValue(config.afterClassRingerMode().get());
    


    片段2

    @Pref        cn.scau.scautreasure.AppConfig_  config;

    /**

    • 切换到加载所有课程模式;
      */
      @OptionsItem
      void menu_load_classtable_all(){
      config.classTableShowMode().put(MODE_ALL);
      showClassTable();
      }

      /**

    • 切换到智能加载课程模式;
      */
      @OptionsItem
      void menu_load_classtable_with_params(MenuItem item){
      config.classTableShowMode().put(MODE_PARAMS);
      showClassTable();
      }
       

 

Edit by 小树

作为一门开发语言,反射类机制是必不可少的!android也有类似的开源IOC框架,通过依赖注入(IOC)的实现思想,可以把约定好的一大串代码通过注解@的方式,以IOC技术来生成中间件,AndroidAnnotations在这方面出色,不仅体积小,而且功能强大,极大的减少了代码量,下面将带来一系列的教程。
 

 

希望此篇能帮到大家,本系列教程目录:转载请链接并注明:转自 小树技术博客 .

AndroidAnnotations注解框架之介绍+配置(一):飞机直达

AndroidAnnotations注解框架之@Pref(二): 飞机直达

AndroidAnnotations注解框架之@Activity(三):飞机直达

AndroidAnnotations注解框架之@Application(四): 飞机直达
 

 

 

一 Android Annotations 的介绍

 

AndroidAnnotations官网:AndroidAnnotations首页

开源于github的项目地址:AndroidAnnotations Github

AndroidAnnotations是一个能够让你快速进行Android开发的开源框架,它能让你专注于真正重要的地方。使代码更加精简,使项目更加容易维护,它的目标就是“Fast Android Development.Easy maintainance”.通过一段时间的使用发现,相比原生的Android开发,确实能够让你少些很多代码,它的首页也给出了一个简单的例子,通过例子也可以看到代码比之前几乎少写了一半。由于是开源,所以大家都可以直接拿来使用。

至于使用这个开源框架有什么好处(只有不到50k大小),我这里就不详细翻译github上的介绍了,就简单说一下特性:

1、使用依赖注入(Dependency Injection)#本博接来下几篇的文章将要介绍的开源组件都使用DI, 不熟悉的可以了解一下Inversion of Control(IoC)

2、简化的线程模型(Simplified threading model)

3、事件绑定(Event binding)

4、REST Client

5、No Magic [不知道为什么这样称呼,直译过来就是:无魔法,它的意思是:AndroidAnnotations在编译的时候会产生一个子类(接下来你会明白),你查看这个子类,可以看到它是如何工作的]
 

更多的介绍可以前往官网或者Github上的项目去查看,它带有超级详细和全面的wiki,CookBook和API文档,十分爽心悦目。

 

二 Android Annotations 的部署

 

(一) 环境:

 

开发工具:Eclipse & android stdio & other (本篇以eclipse为例子,其他IDE请参考官网)

JDK版本:jdk1.6 以上

构建工具:Ant(Eclipse默认的build tool,因此无需装额外的插件)

androidannotations:3.1 (请前往 发行地址 下载)

(二) 步骤:

 

1,准备好需要的环境,见上文

2,配置好项目文件

3,配置Ant

4,配置Eclipse
 

1. 新建项目配置JAR包

 

首先需要有一个普通的android项目,下载并解压Anno 3.1的JAR包,解压后有两个jar包,androidannotations-api-2.7.1.jar放置于项目libs文件夹,androidannotations-2.7.1.jar放置于项目compile-libs文件夹下

(compile-libs需要自己创建,创建在项目的根目录下)

 

2. 创建配置文件

 

(在项目根目录下,创建 build.xml和custom_rules.xml)

 

创建build.xml,内容如下:(注意修改项目名,其他不变,C+V即可)

 

<?xml version=”1.0” encoding=”UTF-8”?>
<project name=”这里是项目名” default=”help”>

&lt;property file="local.properties" /&gt;

&lt;property file="ant.properties" /&gt;

&lt;property environment="env" /&gt;
&lt;condition property="sdk.dir" value="${env.ANDROID_HOME}"&gt;
    &lt;isset property="env.ANDROID_HOME" /&gt;
&lt;/condition&gt;

&lt;loadproperties srcFile="project.properties" /&gt;

&lt;fail
        message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
        unless="sdk.dir"
/&gt;

&lt;import file="custom_rules.xml" optional="true" /&gt;
&lt;import file="${sdk.dir}/tools/ant/build.xml" /&gt;

</project>

 

创建 custom_rules.xml,内容如下:C+V即可

 

<?xml version=”1.0” encoding=”UTF-8”?>
<property
name=”generated.dir”
value=”.apt_generated” />
<property
name=”generated.absolute.dir”
location=”${generated.dir}” />
<property
name=”java.compilerargs”
value=”-s &apos;${generated.absolute.dir}&apos;” />
<target name=”-pre-compile” >

&lt;mkdir dir="${generated.absolute.dir}" /&gt;

</target><target
name=”-compile”
depends=”-pre-build, -build-setup, -code-gen, -pre-compile” >

&lt;do-only-if-manifest-hasCode elseText="hasCode = false. Skipping..." &gt;

    &lt;!-- merge the project's own classpath and the tested project's classpath --&gt;

    &lt;path id="project.javac.classpath" &gt;

        &lt;path refid="project.all.jars.path" /&gt;

        &lt;path refid="tested.project.classpath" /&gt;

        &lt;path path="${java.compiler.classpath}" /&gt;

        &lt;fileset
            dir="compile-libs"
            includes="*.jar" /&gt;
    &lt;/path&gt;

    &lt;javac
        bootclasspathref="project.target.class.path"
        classpathref="project.javac.classpath"
        debug="true"
        destdir="${out.classes.absolute.dir}"
        encoding="${java.encoding}"
        extdirs=""
        fork="${need.javac.fork}"
        includeantruntime="false"
        source="${java.source}"
        target="${java.target}"
        verbose="${verbose}" &gt;

        &lt;src path="${source.absolute.dir}" /&gt;

        &lt;src path="${gen.absolute.dir}" /&gt;

        &lt;compilerarg line="${java.compilerargs}" /&gt;
    &lt;/javac&gt;

    &lt;!-- if the project is instrumented, intrument the classes --&gt;

    &lt;if condition="${build.is.instrumented}" &gt;

        &lt;then&gt;

            &lt;echo level="info" &gt;

Instrumenting classes from ${out.absolute.dir}/classes…

        &lt;/echo&gt;

        &lt;!-- build the filter to remove R, Manifest, BuildConfig --&gt;

        &lt;getemmafilter
            appPackage="${project.app.package}"
            filterOut="emma.default.filter"
            libraryPackagesRefId="project.library.packages" /&gt;

        &lt;!--
                 define where the .em file is going. This may have been
                 setup already if this is a library

        --&gt;

        &lt;property
            name="emma.coverage.absolute.file"
            location="${out.absolute.dir}/coverage.em" /&gt;

        &lt;!-- It only instruments class files, not any external libs --&gt;

        &lt;emma enabled="true" &gt;

            &lt;instr
                instrpath="${out.absolute.dir}/classes"
                metadatafile="${emma.coverage.absolute.file}"
                mode="overwrite"
                outdir="${out.absolute.dir}/classes"
                verbosity="${verbosity}" &gt;

                &lt;filter excludes="${emma.default.filter}" /&gt;

                &lt;filter value="${emma.filter}" /&gt;
            &lt;/instr&gt;
        &lt;/emma&gt;
    &lt;/then&gt;
&lt;/if&gt;

&lt;!-- if the project is a library then we generate a jar file --&gt;

&lt;if condition="${project.is.library}" &gt;

    &lt;then&gt;

        &lt;echo level="info" &gt;

Creating library output jar file…

&lt;/echo&gt;

&lt;property
    name="out.library.jar.file"
    location="${out.absolute.dir}/classes.jar" /&gt;

&lt;if&gt;

    &lt;condition&gt;

        &lt;length
            length="0"
            string="${android.package.excludes}"
            trim="true"
            when="greater" /&gt;
    &lt;/condition&gt;

    &lt;then&gt;

        &lt;echo level="info" &gt;

Custom jar packaging exclusion: ${android.package.excludes}

                    &lt;/echo&gt;
                &lt;/then&gt;
            &lt;/if&gt;

            &lt;propertybyreplace
                name="project.app.package.path"
                input="${project.app.package}"
                replace="."
                with="/" /&gt;

            &lt;jar destfile="${out.library.jar.file}" &gt;

                &lt;fileset
                    dir="${out.classes.absolute.dir}"
                    excludes="${project.app.package.path}/R.class ${project.app.package.path}/R$*.class ${project.app.package.path}/BuildConfig.class"
                    includes="**/*.class" /&gt;

                &lt;fileset
                    dir="${source.absolute.dir}"
                    excludes="**/*.java ${android.package.excludes}" /&gt;
            &lt;/jar&gt;
        &lt;/then&gt;
    &lt;/if&gt;
&lt;/do-only-if-manifest-hasCode&gt;

</target>
 

3. 配置eclipse

 

在eclipse中,右键项目,选择属性Properties

Properties>> Java Compiler ,勾上Enable,确保编译器版本为1.6以上

Properties >> Java Compiler >> Annotation Processing >> 勾选Enable annotation processing(开启)

Properties >> Java Compiler >> Annotation Processing >> Factory Path >> 添加jar包,选择该项目,打开compile-libs目录下的androidannotations-2.7.1.jar

 

4,重新编译项目

 

选择eclipse菜单,Project>>clean>>选上该项目>>确定clean

 

5,至此,AndroidAnnotations配置完成

 

这里附上一个简单的Demo,可以导入后,继续Ant和eclipse的配置即可正常使用,如有问题,请留言。

AndroidAnnotationsDemo

 

 

 

注:文章部分内容转载自renqingping(博客园)
Android使用Google Dalvik VM,相对于传统Java VM而言有着很大的不同,在Sun的Java体系中入口点和标准c语言一样是main(),而每个Android程序都包含着一个Application实例,一个Application实例中有多个Activity、Service、ContentProvider或Broadcast Receiver。因为大部分的应用都包含Activity所以,说很多网友认为是Activity的onCreate,但是你没有发现你的工程中有多个Activity吗? 你可能没有见过没有Activity的Android应用吧。

其实在android.app.Application这个包的onCreate才是真正的Android入口点,只不过大多数开发者无需重写该类,他的继承关系如下图:

java.lang.Object

android.content.Context

android.content.ContextWrapper

android.app.Application

android.app.Application类包含了4个公开的方法

void  onConfigurationChanged(Configuration newConfig)
void onCreate() //这里才是真正的入口点。
void onLowMemory()
void onTerminate()

所以希望大家,记住真正的Android入口点是application的onCreate,不过通过源代码可以看出,application的onCreate函数什么事也没有做。你可以看下androidmanifest.xml的包含关系就清楚了,并不是每个应用都必须有Activity的。

 

Application**类**

 

Application和Activity,Service一样是Android框架的一个系统组件,当Android程序启动时系统会创建一个Application对象,用来存储系统的一些信息。

Android系统自动会为每个程序运行时创建一个Application类的对象且只创建一个,所以Application可以说是单例(singleton)模式的一个类。

通常我们是不需要指定一个Application的,系统会自动帮我们创建,如果需要创建自己的Application,那也很简单!创建一个类继承Application并在AndroidManifest.xml文件中的application标签中进行注册(只需要给application标签增加name属性,并添加自己的 Application的名字即可)。

启动Application时,系统会创建一个PID,即进程ID,所有的Activity都会在此进程上运行。那么我们在Application创建的时候初始化全局变量,同一个应用的所有Activity都可以取到这些全局变量的值,换句话说,我们在某一个Activity中改变了这些全局变量的值,那么在同一个应用的其他Activity中值就会改变。

Application对象的生命周期是整个程序中最长的,它的生命周期就等于这个程序的生命周期。因为它是全局的单例的,所以在不同的Activity,Service中获得的对象都是同一个对象。所以可以通过Application来进行一些,如:数据传递、数据共享和数据缓存等操作。

1,应用场景:

 

在Android中,可以通过继承Application类来实现应用程序级的全局变量,这种全局变量方法相对静态类更有保障,直到应用的所有Activity全部被destory掉之后才会被释放掉。

2,实现步骤:

 

1**、继承**Application

 

public class CustomApplication extends Application
{
private static final String VALUE = “Harvey”;

private String value;

@Override
public void onCreate()
{
    super.onCreate();
    setValue(VALUE); // 初始化全局变量
}

public void setValue(String value)
{
    this.value = value;
}

public String getValue()
{
    return value;
}

}
 

注:继承**Application类,主要重写里面的onCreate()方法(android.app.Application包的onCreate()才是真正的Android**程序的入口点),就是创建的时候,初始化变量的值。然后在整个应用中的各个文件中就可以对该变量进行操作了。

2**、在ApplicationManifest.xml文件中配置自定义的**Application

 

<application
android:name=”CustomApplication”>
</application>

 

实例代码:

CustomApplication.java

 

/**

  • 继承Application
  • @author admin
  • */
    public class CustomApplication extends Application
    {
    private static final String VALUE = “Harvey”;

    private String value;

    @Override
    public void onCreate()
    {

    super.onCreate();
    setValue(VALUE); // 初始化全局变量
    

    }

    public void setValue(String value)
    {

    this.value = value;
    

    }

    public String getValue()
    {

    return value;
    

    }
    }
     

FirstActivity.java

 

public class FirstActivity extends Activity
{
private CustomApplication app;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    app = (CustomApplication) getApplication(); // 获得CustomApplication对象

    Log.i("FirstActivity", "初始值=====" + app.getValue()); // 获取进程中的全局变量值,看是否是初始化值

    app.setValue("Harvey Ren"); // 重新设置值

    Log.i("FirstActivity", "修改后=====" + app.getValue()); // 再次获取进程中的全局变量值,看是否被修改

    Intent intent = new Intent();
    intent.setClass(this, SecondActivity.class);
    startActivity(intent);
}

}
 

注:只需要调用**Context getApplicationContext或者ActivitygetApplication方法来获得一个Application对象,然后再得到相应的成员变量即可。它是代表我们的应用程序的类,使用它可以获得当前应用的主题和资源文件中的内容等,这个类更灵活的一个特性就是可以被我们继承,来添加我们自己的全局属性。**

SecondActivity.java

 

public class SecondActivity extends Activity
{
private CustomApplication app;

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

    app = (CustomApplication) getApplication(); // 获取应用程序

   Log.i("SecondActivity", "当前值=====" + app.getValue()); // 获取全局值
}

}
 

AndroidManifest.xml

 

<?xml version=”1.0” encoding=”utf-8”?>
<manifest
xmlns:android=”http://schemas.android.com/apk/res/android
package=”com.android.test”
android:versionCode=”1”
android:versionName=”1.0”>
<uses-sdk
android:minSdkVersion=”8” />

&lt;application
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:name="CustomApplication"&gt;
    &lt;!-- 将我们以前一直用的默认Application设置成自定义的CustomApplication --&gt;
    &lt;activity
        android:name=".FirstActivity"
        android:label="@string/app_name"&gt;
        &lt;intent-filter&gt;
            &lt;action
                android:name="android.intent.action.MAIN" /&gt;
            &lt;category
                android:name="android.intent.category.LAUNCHER" /&gt;
        &lt;/intent-filter&gt;
    &lt;/activity&gt;

    &lt;activity
        android:name=".SecondActivity"
        android:label="@string/app_name"&gt;
    &lt;/activity&gt;
&lt;/application&gt;

</manifest>
 

注:
在某些情况下可能会遇到getApplication返回null的情况,有可能是调用getApplication的时机不对,如果是在类未定义完成的地方(比如变量定义部分),此时无法得到实例,所以就会出现空指针

 

IBM JTS RQM中EXCEL测试用例的导入

 

在IBM公司的软件管理平台JTS上,从EXCEL文件导入测试用例到RQM中是十分之重要和实用的,很多客户也是要求必须要有如此的功能,本篇文档主要是一个工具的指南,因为RQM本身并不可以导入EXCEL,但是IBM公司提供了这么一个工具:RQMExcelWordImporter,that’s Amazing!本文内容大部分参考IBM官网的帮助,写得可能不好,请见谅!
本文档版本:4.0,和5.0应该差不多

实际基于质量管理平台:IBM JazzTeamServer Rational Quality Manager 5.0

修订人:小树 admin@qiushurong.cn # 2014-09-17 @guangzhou Changeman

1. 需要用到的工具:

 

RQM-Extras-RQMExcelWordImporter

1.1. 下载地址:

 

https://jazz.net

1.2. 下载步骤:

 

打开网页后,点击download,选择qm,点击all download,找到RQM-Extras-RQMExcelWordImporter,需要登录,没有用户的话需要注册,登录后进行下载。

 

 

2. 工具的使用:

 

http://www.ibm.com/developerworks/cn/rational/1312_zhangjin_rqmbestpractice/

2.1. 安装并打开importer

注意:

安装需要MicroSoft office 2003 sp3 以上版本,推荐2003或2007.

安装需要.net FramWork 2.0.以上支持.

由于修改了office的菜单和加载项,所以需要杀毒软件的放行.
下载 RQM-Extras-RQMExcelWordImporter-5.0.zip,解压后执行RQMExcelImporterX64setup.exe

安装完成后,启动 Excel,可以看到在 Add-Ins(加载项) 下的 RQM 项。

jts-rqm-5

注意:如果你是X64系统,请使用X64的安装包,如果使用X64的安装包后发现并没有找到这个选项,请直接使用默认安装包即可。(因为有可能你的系统虽然是64位的,但是你的office软件确实X86或者说是32位的)
 

在 RQM 下,选择 Export to Repository,可以看到如图 10 所示窗口:

jts-rqm-1

图 10. Export to RQM

 

2.2. 连接到RQM

 

输入 RQM Server, Username, Password,连接好 RQM Server 之后,选择 Project。这里需要注意的是使用 RQM Excel Importer 连接 RQM 的用户必须有 Data Migration 的角色,如图 11 所示:

jts-rqm-2

图 11. RQM Excel Importer 用户所需要的角色

 

2.3. 测试用例配置文件

 

如图 10 中所示,导入 Test Cases 时我们需要一个配置文件(TestCases.cfg)。在这个文件中我们会配置在 Excel 中的行和列对应到 Test Cases 的各个组成部分,配置文件如清单 5 所示:

 

2.3.1. Test Case配置文件

 

testcase.XLSStartRow=2
testcase.dc:title=B
testcase.dc:description=E
testcase.jzalm:owner=C
testcase.Section(“myns:com.ibm.rqm.planning.editor.section.testCaseDesign”,\”RQM-KEY-TC-DESIGN-TITLE”)=F
testcase.Section(“myns:com.ibm.rqm.planning.editor.section.testCasePreCondition”,\”RQM-KEY-TC-PRE-COND-TITLE”)=K

 

 

2.3.2. Test Case 配置文件的解析

 

在清单 5 中,

第一行表示导入到 RQM 中的 test case 是从 Excel 文档中的第2行开始。

第二行表示 test case 的 title 对应的是 Excel 文件中的 B 列。

第三行表示 test case 的 description 对应的是 Excel 文件中的 E 列。

第四行表示 test case 的 owner 对应的是 Excel 文件中的 C 列。

第五行分别表示 test case 的 Design 对应的是Excel 文件中的 F 列。

第六行分别表示 test case 的 Precondition 对应的是Excel 文件中的和 K 列。

 

//业务域
testcase.category term=”业务域”.value=”01 登记”
//模块
testcase.category term=”模块”.value=”011001_设立税务登记”
//指定工作表
testcase.XLSWorksheetID=”测试用例汇总”
//从第*行开始读取
testcase.XLSStartRow=2
//测试用例-B
testcase.customAttributes identifier=”js_attr_csylbh2”.name=B1.type=”SMALL_STRING”.value=B
//测试用例-标题C
testcase.dc:title=C
//测试用例-优先级D
testcase.priority=D
//测试用例-前置条件E
testcase.Section(“myns:js_section_qztj”,”前置条件”)=RichText(E)
//测试用例-测试操作步骤及内容F
testcase.Section(“myns:js_section_csczbzjnr”,”测试操作步骤及内容”)=RichText(F)
//测试用例-关键点G
testcase.Section(“myns:js_section_gjd”,”关键点”)=RichText(G)
//测试用例-测试数据要求H
testcase.Section(“myns:js_section_cssjyq”,”测试数据要求”)=RichText(H)
//测试用例-关键点预期效果I
testcase.Section(“myns:js_section_gjdyqxg”,”关键点预期效果”)=RichText(I)
//测试用例-用例预期效果J
testcase.Section(“myns:js_section_ylyqxg”,”用例预期效果”)=RichText(J)
//测试用例-关联流程测试用例编号K
testcase.customAttributes identifier=”js_attr_gllccsylbh2”.name=K1.value=RichText(K)
//测试用例-编写人L
testcase.customAttributes identifier=”js_attr_bxr2”.name=L1.type=”SMALL_STRING”.value=L
//测试用例-审核意见M
testcase.customAttributes identifier=”js_attr_shyj2”.name=M1.type=”SMALL_STRING”.value=M
//测试用例-审核人N
testcase.customAttributes identifier=”js_attr_shr2”.name=N1.type=”SMALL_STRING”.value=N
//测试用例-备注O
testcase.Section(“myns:js_section_bz”,”备注”)=RichText(O)
//测试用例-所有者
testcase.alm:owner=”jazzadmin”
//测试用例-权重
testcase.weight=”100”


 

2.4. 具体的Excel

 

jts-rqm-3

2.5. 导入成功

 

当 Export To Repoitory 执行成功后,可以在 RQM 查看导入的 Test Cases,如下:

jts-rqm-4

 

2.6. 总结

 

通过上述介绍对比我们可以看到,RQM中,测试用例的导入的重心就是测试用例EXCEL的配置文件。

 

附上RQM-importer 的英文官方文档

RQM-importer-doc

附上测试用例导入的例子(国税局测试用例)

testcase导入demo

 

最近在项目中,需要去做一个页面的中英文切换,因此用到了struts自带的国际化 i18n 包,由于我所在的项目是 struts 1.x ,但是网上大多都是 struts 2 因此我把两个都一起记录下来了,基本的操作是一样的。
i18n其来源是英文单词 internationalization 的首末字符i和n,18为中间的字符数)是“国际化”的简称。在资讯领域,国际化(i18n)指让产品(出版物,软件,硬件等)无需做大的改变就能够适应不同的语言和地区的需要。对程序来说,在不修改内部代码的情况下,能根据不同语言及地区显示相应的界面。 在全球化的时代,国际化尤为重要,因为产品的潜在用户可能来自世界的各个角落。

一,struts 1.x



## 1,基本的国际化

### 步骤1:配置struts国际化

在struts-config.xml中配置message-resources标签

<message-resource parameter=”MessageResource”/>

其中的参数是国际化配置文件MessageResource.properties的文件名。

### 步骤2:提供国际化配置文件

中文:MessageResource_zh_cn.properties

英文:MessageResource_en_us.properties

源文件:resource.properties表示中文信息

在源文件resource.properties中硬编码中文信息
user.title=用户登录
user.username=用户
user.password=密码
user.button.login=登录

然后用java中提供的工具把这些信息转换为unicode放到相应国际化文件中。

MessageResource_zh_cn.properties文件中

user.title=\u7528\u6237\u767b\u5f55
user.username=\u7528\u6237
user.password=\u5bc6\u7801
user.button.login=\u767b\u5f55

MessageResource_en_us.properties文件中

user.title=User Login
user.username=User Name
user.password=Password
user.button.login=Login

### 步骤3:在jsp页面上用struts标签<bean:message>来读取国际化消息文本

引入标签:

<%@ taglib prefix=”bean” uri=”http://struts.apache.org/tags-bean”%>

<form action=”login.do” method=”post”>
<bean:message key=”user.username”/>:<input type=”text” name=”username”><br>
<bean:message key=”user.password”/>:<input type=”password” name=”password”><br>
<input type=”submit” value=”<bean:message key=”user.button.login”/>”>
</form>

bean:message中的属性key指的是国际化文件中的键。

一个local对应一个session

## 二,国际化的切换

jsp页面:

<a href=”changelang.do?lang=zh”>中文</a>&nbsp&nbsp&nbsp<a href=”changelang.do?lang=en”>英文</a>

添加一个Action:

public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String lang = request.getParameter(“lang”);

//得到Locale
Locale currentLocale = Locale.getDefault();
if (“zh”.equals(lang)) {

//自定义Locale
currentLocale = new Locale(“zh”, “CN”);
}else if(“en”.equals(lang)) {
currentLocale = new Locale(“en”, “US”);
}

//自己设置Locale
//request.getSession().setAttribute(Globals.LOCALE_KEY, currentLocale);
//调用struts中提供的方法设置Locale
this.setLocale(request, currentLocale);
return mapping.findForward(“index”);
}

配置国际化action:

<action path=”/changelang”
type=”com.bjsxt.struts.ChangeLanguageAction”
>
<forward name=”index” path=”/index.jsp”/>
</action>

<message-resources parameter=”res.MessageResources” />

res.MessageResources表示的是res包下的MessageResources文件。

## 三,动态信息的国际化

如果是与后台交互的数据,那么在国际化文件中就用占位符进行配置

resource.properties源文件:

user.login.success={0},登录成功
user.not.found=用户不能找到,用户名称=[{0}]
user.password.error=密码错误
user.login.error=登录失败

MessageResource_zh_cn.properties文件:

user.login.success={0},\u767b\u5f55\u6210\u529f
user.not.found=\u7528\u6237\u4e0d\u80fd\u627e\u5230\uff0c\u7528\u6237\u540d\u79f0=[{0}]
user.password.error=\u5bc6\u7801\u9519\u8bef
user.login.error=\u767b\u5f55\u5931\u8d25MessageResource_en_us.properties文件:

user.login.success={0},Login Success
user.not.found=User Not Found,UserName[{0}]
user.password.error=Password Error
user.login.error=Login Error

Action中的代码:

package com.bjsxt.struts;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;

/* 用户登录的Action
@author Administrator
*/
public class LoginAction extends Action {

public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
LoginActionForm laf = (LoginActionForm)form;
String username = laf.getUsername();
String password = laf.getPassword();

ActionMessages messages = new ActionMessages();
try {
UserManager.getInstance().login(username, password);

//创建国际化消息文本
ActionMessage message = new ActionMessage(“user.login.success”, username);
//ActionMessage message = new ActionMessage(“user.login.success”, new Object[]{username});//其中Object数组表示的是占位符
messages.add(“loginSuccess1”, message);

ActionMessage message1 = new ActionMessage(“user.login.success”, username);
messages.add(“loginSuccess2”, message1);

//传递国际化消息文本
this.saveMessages(request, messages);
return mapping.findForward(“success”);
}catch(UserNotFoundException unfe) {
unfe.printStackTrace();

//创建国际化消息文本
ActionMessage message = new ActionMessage(“user.not.found”, username);
messages.add(“error1”, message);

//传递国际化消息文本
this.saveErrors(request, messages);
}catch(PasswordErrorException pee) {
pee.printStackTrace();
//创建国际化消息文本
ActionMessage message = new ActionMessage(“user.password.error”);
messages.add(“error2”, message);

//传递国际化消息文本
this.saveErrors(request, messages);
}
return mapping.findForward(“error”);
}

}

一个ActionMessage表示一条国际化信息。

Action配置:

<message-resources parameter=”res.MessageResources” />

 

 

二,struts 2

 

1.首先在struts.properties文件中加入以下内容:

struts.custom.i18n.resources=messageResource
或在struts.xml中加入
<constant name=”struts.custom.i18n.resources” value=”messageResource”></constant>

2.资源文件的命名格式:

名称语言代码国家代码. Properties
如果创建中文和英语国际化,那么资源文件名称为
messageResource_zh_CN.properties和messageResource_en_US.properties

3. jsp页面的国际化


通过使用标签<s:text name=”label.helloWorld”/>输出国际化
label.helloWorld为资源文件中定义的key

在messageResource_en_US.properties加入以下内容
label.hello=hello {0}
label.helloWorld=hello,world

在messageResource_zh_CN.properties加入以下内容
label.hello=你好 {0}
label.helloWorld=你好,世界

(1). <s:text name=”label.helloWorld”/>
<s:property value=”%{getText(‘label.helloWorld’)}”/>
上面两个都为输出一个hello word的两种表示

<s:textfield name=”name” key=”label.helloWorld”/>
<s:textfield name=”name” label=”%{getText(‘label.helloWorld’)}”/>
显示一个文本框,文本框的标题进行国际化

(2). 使用<s:i18n>标签指定从某个特定的资源文件中取数据
<s:i18n name=”messageResource”>
<s:text name=”label.helloWorld”></s:text>
</s:i18n>
指定在从messageResource取资源

(3).
<s:text name=”label.hello”>
<s:param>callan</s:param>
</s:text>
使用带参数的资源.<s:param>可以替换label.hello=hello {0}中的{0}

4. Action的国际化

Action的国际化主要是通过getText(String key)方法实现的

String str1 = getText(“label.helloWorld”);

5. 参数化国际化

在messageResource_en_US.properties加入以下内容
userName=userName
userName.required=${getText(‘userName’)} is required

在messageResource_zh_CN.properties加入以下内容
userName=用户名
userName.required=${getText(‘userName’)} 不能为空

在Action中
String str4 = getText(“userName.required”);
System.out.println(str4);

userName.required=${getText(‘userName’)}会取国际化的用户名

6. 使用校验框价时,提示信息可以国际化

<field name=”userName”>
<field-validator type=”requiredstring”>
<message key=”userName.required”> </message>
</field-validator>
</field>

 

三,项目解决方案:

由于老板的需求,是要在配置文件里面进行单一性质的修改,所以我的解决方案如下:

修改struts配置文件web.xml
添加/WEB-INF/language.xml分支

/WEB-INF/language.xml设置要读取的字库

读取
config/Language_Chinese.properties
config/Language_English.properties

JSP页面

包含struts-lib
<%@ taglib prefix=”bean” uri=”http://struts.apache.org/tags-bean”%>

使用标签
<bean:message key=”hello”/>

切换语言方法:找到 WEB_INF/language.xml 按照注释内容进行修改

 

在许许多多的android项目中,下拉刷新是必不可少的一个小模块,最近的一个项目中,很多模块都需要实现这么一个功能,最后采用的是Github上很火的开源项目,PullToRefresh,下面,简单说一下PullToRefresh的使用方法和个人的心得。
开源项目地址:https://github.com/johannilsson/android-pulltorefresh

1 使用方法

1.1 导入lib项目,设置项目关联

到开源项目的官网下载整个项目,导入到eclipse中,到你的主项目,右键,项目属性,选择android,在最下面,把刚刚导入进来的pulltorefresh项目add成为一个lib引用。如图:点击放大

pulltorefresh-1

1.2 在需要使用下拉刷新的layout中,添加下拉刷新list(或者其他类型),如图:点击放大

pulltorefresh-2

附上代码以及解释:

   <!-- 带下拉刷新的ListView -->
   <com.handmark.pulltorefresh.library.PullToRefreshListView
        xmlns:ptr="http://schemas.android.com/apk/res-auto"
        android:id="@+id/pull_refresh_list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:cacheColorHint="#00000000"
        android:divider="#19000000"
        android:dividerHeight="4dp"
        android:fadingEdge="none"
        android:fastScrollEnabled="false"
        android:footerDividersEnabled="false"
        android:headerDividersEnabled="false"
        android:smoothScrollbar="true"
        ptr:ptrAnimationStyle="rotate" //下拉时,图标的动画,rotate是旋转
        ptr:ptrHeaderBackground="#FFF8F8F8" //下拉时,滑出的下拉块背景颜色
        ptr:ptrMode="both" //下拉刷新的模式,both是上拉和下拉
    ptr:ptrDrawable="@drawable/loading4"> //下拉时候的图标

1.3 在代码中对下拉刷新进行更详细的配置

首先是获取实例

mPullRefreshListView = (PullToRefreshListView) 
    parentView.findViewById(R.id.pull_refresh_list);
设置音效
        SoundPullEventListener<ListView> soundListener = new SoundPullEventListener<ListView>(parentActivity);
        soundListener.addSoundEvent(State.PULL_TO_REFRESH, R.raw.pull_event);
        soundListener.addSoundEvent(State.RESET, R.raw.reset_sound);
        soundListener.addSoundEvent(State.REFRESHING, R.raw.refreshing_sound);
        mPullRefreshListView.setOnPullEventListener(soundListener);
设置提示文字
//设置提示信息
ILoadingLayout startLabels = mPullRefreshListView
        .getLoadingLayoutProxy();
startLabels.setPullLabel("向下拉刷新...");// 刚下拉时,显示的提示
startLabels.setRefreshingLabel("松开刷新...");// 刷新时
startLabels.setReleaseLabel("正在加载中...");// 下来达到一定距离时
关于设置提示文字的,有一个地方要说的是, mPullRefreshListView.getLoadingLayoutProxy(参数,参数); 这一句,不传参数的话,默认是同时设置 下拉刷新 和 上拉加载更多 的文本。 添加参数:true,false 是设置 下拉刷新 的文本。 添加参数:false,true 是设置 上拉加载更多 的文本。 例如:
        //设置 下拉刷新 提示信息
        ILoadingLayout startLabels = mPullRefreshListView.getLoadingLayoutProxy(true,false);
        startLabels.setPullLabel("下拉重新刷新...");// 刚下拉时,显示的提示
        startLabels.setRefreshingLabel("不要命刷新中...");// 刷新时
        startLabels.setReleaseLabel("松开重新刷新...");// 下来达到一定距离时
        //设置 加载更多 提示信息
        ILoadingLayout endLabels = mPullRefreshListView.getLoadingLayoutProxy(false,true);
        endLabels.setPullLabel("上拉加载更多...");// 刚下拉时,显示的提示
        endLabels.setRefreshingLabel("不要命加载中...");// 刷新时
        endLabels.setReleaseLabel("松开加载更多...");// 下来达到一定距离时
效果: [![pulltorefresh-3](http://www.qiushurong.cn/wp-content/uploads/2014/08/pulltorefresh-3-300x191.jpg)](http://www.qiushurong.cn/wp-content/uploads/2014/08/pulltorefresh-3.jpg) ### 1.4 添加一个监听器
// 设置刷新监听器
mPullRefreshListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
    @Override
    public void onRefresh(PullToRefreshBase<ListView> refreshView) {
        // 设置最近刷新时间为当前时间
        String label = DateUtils.formatDateTime(parentActivity.getApplicationContext(), System.currentTimeMillis(),
                DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL);
        refreshView.getLoadingLayoutProxy().setLastUpdatedLabel(label);

        // 在这这个GetDataTask线程里面进行刷新处理
        new GetDataTask().execute();
    }
});
这样就完成了一个下拉刷新的操作了 但是我们现在并没有添加任何UI,一般来说,都是利用这个下拉刷新listview本身进行条目UI的操作的。 ### 1.5 在PullToRefreshListView中获取我们要的listView 如下:直接获取这个PullToRefreshListView的里面嵌套的listview,来存放我们要显示的内容
ListView actualListView = mPullRefreshListView.getRefreshableView();
//这个actualListView 就是我们真正可以用来放数据的视图view
// 注册视图
registerForContextMenu(actualListView);
//实例化一个list,存放我们的数据
mListItems = new LinkedList<String>();
mListItems.add("初始化数据");
//实例化一个适配器,把数据和UI进行关联
mAdapter = new ArrayAdapter<String>(parentActivity,
    android.R.layout.simple_list_item_1, mListItems);

1.6 区分 下拉刷新 和 上拉加载更多 [重要]

既然有 下拉刷新 和 上拉加载更多,但他们都是同一个被调用的方法,那么怎么区分呢?

方法:修改开源项目,添加对header和footer的判断,通过header和footer的是否显示 来判断是上拉还是下拉

首先,在我们之前导入的项目中,找到PullToRefreshAdapterViewBase这个类

添加这么2个方法

    public boolean isHeaderShown() {
        return getHeaderLayout().isShown();
    }  

    public boolean isFooterShown() {  
        return getFooterLayout().isShown(); 
    }  
然后clean一下主项目,让他重建一下lib包,之后在主项目的监听器里面,进行判断
mPullRefreshListView.setOnRefreshListener(new OnRefreshListener<ListView>() {
    @Override
    public void onRefresh(PullToRefreshBase<ListView> refreshView) {

        //这2个方法是我修改了 PullToRefresh 项目后添加进去的,原本开源的项目是没有的。

        //判断是 上拉 还是 下拉
        if(mPullRefreshListView.isHeaderShown()){
            String label = DateUtils.formatDateTime(parentActivity.getApplicationContext(), System.currentTimeMillis(),DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL);
            refreshView.getLoadingLayoutProxy(true,false).setLastUpdatedLabel(label);
            // 开始下拉刷新
                    }else if(mPullRefreshListView.isFooterShown()){
            String label = DateUtils.formatDateTime(parentActivity.getApplicationContext(), System.currentTimeMillis(),DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL);
            refreshView.getLoadingLayoutProxy(false,true).setLastUpdatedLabel(label);
            // 开始加载更多
                    }
    }
});
这样子就初步实现了一个区分的功能了 ### 1.7 在list尾端添加监听器 有时候我们需要在用户滑动到list尾端的时候进行一个提示,或者进行数据的加载,那么会用到这个:
// 在list尾端添加一个监听器
        mPullRefreshListView.setOnLastItemVisibleListener(new OnLastItemVisibleListener() {
            @Override
            public void onLastItemVisible() {
                Toast.makeText(parentActivity, "到达尾端,上拉可加载更多...", Toast.LENGTH_SHORT).show();
            }
        });

2 使用心得

(明天再续)