3.<uses-sdk>节点——SDK版本限定
大家都知道,软件对于平台版本是的一定要求的。如果平台版本能够达到软件运行的要求,那就能保证软件的稳定性。比如,大家都知道NFC功能是不能在Android 1.5中运行的,如果正在开发带类似功能的应用程序,那就必须对所在平台有所要求,而<uses-sdk>节点正是用来满足这种需求的。
<uses-sdk>节点使用一个整型值来表达应用程序与一个或多个Android平台版本的兼容性。值得注意的是,这些整型值代表的是API级别。应用程序给定的API级别将和一个给定Android系统的API级别做比较。当然,对于不同的Android设备,这可能会有所不同。需要说明的是,这个节点用于指定API级别,而不是用于指定SDK的版本号或Android平台的。
使用此节点的代码如下所示:
<uses-sdk android:minSdkVersion="integer" android:targetSdkVersion="integer" android:maxSdkVersion="integer"/>
①android:minSdkVersion:用于指定要运行应用程序所需的最小API级别。如果系统的API级别比该属性指定的值要小,则Android系统会阻止用户安装此应用。在大多数情况下,应指定这个属性。如果没有指定该属性,那么系统会认为此属性值为“1”。
②android:targetSdkVersion:用于指定应用程序的目标API级别。
③android:maxSdkVersion:指定最大的API级别。
4.<instrumentation>节点——应用的监控器
<instrumentation>节点用于监控应用程序与系统交互,它会在应用程序组件实例化之前被实例化。这个节点在多数情况下用于单元测试。其语法结构如下:
<instrumentation android:functionalTest=["true"|"false"] android:handleProfiling=["true"|"false"] android:icon="drawable resource" android:label="string resource" android:name="string" android:targetPackage="string">
下面详细说明这些属性:
①android:functionalTest:标识这个Instrumentation类是否作为一个功能测试运行,它的默认值是false。
②android:handleProfiling:标识这个Instrumentation对象是否打开和关闭性能分析,它的默认值是false。
③android:icon:这个属性代表这个Instrumentation类的图标
④android:label:该属性是Instrumentation类的标题。
⑤android:name:该属性是Instrumentation子类的名称,是一个类的Java风格的名称,例如com.example.liyuanjinglyj.myInstrumentation。
⑥android:targetPackage:该属性是需要监控的目标应用程序名称,这个名称来自与目标应用程序AndroidManifest.xml中<manifest>节点的package属性值。
当然在eclipse需要专门创建一个测试项目,而且还要配置这个节点,但是在android studio并不需要这么做,考虑到2015年底谷歌不再支持eclipse,所以只讲解android studio单元测试,而讲解这个节点是因为到现在eclipse依然有大量的开发者使用,所以,讲解了节点的详细说明。
下面举例说明如何进行单元测试:
①创建项目,依然拿我们一直使用的HelloWorld做实验,你会发现项目目录里面有这样一个测试包:
②右键点击这个包,选择NEW-CLASS菜单项,新建MyFirstTest继承自ActivityInstrumentationTestCase2<T>,如下图所示:
package com.example.liyuanjing.helloworld; import android.test.ActivityInstrumentationTestCase2; /** * Created by liyuanjing on 2015/7/14. */ public class MyFirstTest extends ActivityInstrumentationTestCase2<MainActivity>{ public MyFirstTest(){ super(MainActivity.class); } }
在这段代码中,ActivityInstrumentationTestCase2<T>中的<T>要换成我们测试的类,因为我们要测试MainActivity所以换成这个。
③我们测试内容为,在编辑框中输入一些字符,当点击按钮后,文本框等于编辑框输入的字符串,MainActivity代码如下:
public class MainActivity extends FragmentActivity { private static final String SDCARD= Environment.getExternalStorageDirectory()+File.separator; private FileFragment fileFragment=new FileFragment(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if(savedInstanceState==null){ getSupportFragmentManager().beginTransaction().add(android.R.id.content,fileFragment).commit(); } } public static class FileFragment extends Fragment { private View mRootView; public FileFragment(){} @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view=inflater.inflate(R.layout.file_fragment,container,false); final EditText myEdit=(EditText)view.findViewById(R.id.myEdit); final TextView content=(TextView)view.findViewById(R.id.content); Button myBut=(Button)view.findViewById(R.id.myBut); myBut.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { content.setText(myEdit.getText().toString()); } }); this.mRootView=view; return view; } public View getRootView(){ return this.mRootView; } } public FileFragment getFragment(){ return fileFragment; } }
测试类的代码如下:
public class MyFirstTest extends ActivityInstrumentationTestCase2<MainActivity>{ private TextView content; private EditText myEdit; private Button myBut; private MainActivity mainActivity; public MyFirstTest(){ super(MainActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); this.mainActivity=(MainActivity)getActivity(); this.content=(TextView)this.mainActivity.getFragment().getRootView().findViewById(R.id.content); this.myEdit=(EditText)this.mainActivity.getFragment().getRootView().findViewById(R.id.myEdit); this.myBut=(Button)this.mainActivity.getFragment().getRootView().findViewById(R.id.mybut); } public void testButtonClick(){ getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_H); getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_E); getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_L); getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_L); getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_O); getInstrumentation().waitForIdleSync(); getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { myBut.performClick(); } }); getInstrumentation().waitForIdleSync(); SystemClock.sleep(1000); assertEquals(this.content.getText().toString(),this.myEdit.getText().toString()); } }
注意:
Ⅰ在MyFirstTest类的构造放中,由于指定了被测试项目的Activity的详细信息,就使得MyFirstTest与Activity关联上。
ⅡsetUp()方法是一个重写的方法,它的作用是在测试前做必要的设置,比如实例化一些对象,打开网络等,它与tearDown()方法成对出现。这里我们没有实现tearDown()方法,当测试完成以后,框架会自动回调基类,也就是tearDown()方法。
最后,运行测试类,如下图所示:
当系统完成测试后,就可以在Android studio集成开发环境中得到下图所示的结果:
在图中可以看到,编写的Test测试类返回值为OK,这就证明测试达到了预期的目的。