1,关于文字的阴影:在布局文件中的控件设置shadowCollor(背景色);shadowDx,shadowDy(x,y坐标的偏移量),shadowRadius(偏移角度)。
2,去除标题栏:
manifest清单文件中:
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.dialogdemo.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
资源目录下的style.xml文件:因为在清单文件中的主题样式调用的就是这个style.xml文件中的AppTheme。
true
3,获取应用版本号:
manifest清单文件中有版本号,利用PackageManager来获取
versionCode:当前版本号,
versionName:版本号的名称
代码如下:
PackageManager pm=getPackageManager( );
PackageInfo info=pm . getPackageInfo(packageName,flags);
//第一个参数是应用程序包名,使用getPackageName()获得当前应用程序包名,返回一个String,和自己写的包名一样,用此方法不会写错。
第二个参数flags指定标签。比如填写GET_PERMISSIONS,才可以获取权限。一般情况下填写0就可以了,可以获取基本信息
Sting versionName=info . versionName;//获取版本名称
4,解析JSON数据
//比如此时的JSON串为{“code”:”2.0” , “apkurl”:”xxxxx” , “des”:”新版本内容”}
//以下是自定义的工具方法,用于把从服务器获取的流转换为字符串并将其返回。
public static String parserStreamUtil(InputStream in)throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(in));
StringWriter sw=new StringWriter();
String s=null;
while((str=br.readLine())!=null){
sw.write(s);
}
sw.close();
br.close();
return sw.toString();
}
5,获取网络链接
URL url=new URL("http://www.baidu.com");
HttpURLConnection conn=(HttpURLConnecton)url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if(conn.getResponseCode()==200){
InputStream in=conn.getInputStream();
String json=parserStreamUtil(in);
//如下是解析json数据
JSONObject jsonObject = new JSONObject(json);
//如下三行代码是获取JSON串中的code,apkurl和des
//比如这个code是从服务器返回的版本号,那么用code.equals(getVersionName)来比较服务器版本和当前软件的版本是否一致。
String code=jsonObject.getString("code");
String apkurl=jsonObject.getString("apkurl");
String des=jsonObject.getString("des");
}else{
syso("链接失败");
}
**6:判断SD卡是否挂Environment.getExternalStorageState( ).equals(Environment . MEDIA_MOUNTED ) nvironment.getExternalStorageState( )获得SD卡的状态
//MEDIA_MOUNTED的意思是SD卡是否进行过读写操作
7:打开安装界面
安装其实就是打开系统应用的PackageInstaller
//以下是匹配的intent。DataAndType是文件路径,也就是安装的路径。
Intent intent =new Intent();
intent.setAction("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.setDataAndType(Uri.from(new File("文件路径")) , "application/vnd.android.package-archive");//
8:启动activity返回结果
startActivityForResult(intent , requestCode)要配合重写onActivityResult()方法才可以,调用前者触发后者方法。
startActivityForResult可以区分是哪个Activity打开的此Activity,通过请求码来分区。
9:关于android异常的处理,
每个异常最好都发处TOAST来显示错误,定义常量来代表异常,可以提示如错误:404,错误:3,等提示语句,方便后期测试查找定位异常。
异常最好是每个异常都单独处理,只有定义工具类的时候才throw异常。
10:关于用到context上下文的地方
1:activity.this:代表的就是此Activity
2:getApplicationContext( ):返回的是一个Context
虽然两种方法返回的都是Context,但是activity.this明确表示在Activity中。他们的生命周期也不同,前者生命周期取决于当前Activity,后者取决于整个应用。
getContext:一般用在单元测试和自定义控件中。
11:关于gravity,padding和margin
gravity:设置内容的居中位置
layout_gravity:设置控件相对于父控件的居中位置
padding:距离空间内边框的距离
margin:距离某空间的距离
12:GridView和ListView都继承AbsListView
GridView同样需要设置适配器,复写一个继承自BaseAdapter,重写方法。
numColums属性可以选择列数
verticalSpacing属性可以改变行间距
View.inflate(context,resource,root)方法是把布局文件转化为View
13:TextView的singleLine属性可以让文本单行显示。
ellipsize属性可以让文字滚android :ellipsize=”none” 省略后面文字
android :ellipsize=”start” 隐藏前面文字
android :ellipsize=”middle” 隐藏中间文字
android :ellipsize=“end” 隐藏后面文字
以下几个属性配合才能让文字滚动
android :ellipsize=“marquee” 滚动
android :focusableInTouchMode=“ture”触摸获取焦点
android :focusable=”true” 设置可以获取焦点
android:marqueeRepeatLimit=”marquee_forever” 设置滚动次数:关于自定义的TextView
继承TextView有三个构造方法
public class MyTextView extends TextView{
//这个构造方法一般用于代码中使用例如 MytextView m=new MyTextView(context)
public MyTextView(Context context){
super(context);
}
//这个构造方法的第二个参数是代表控件的属性,布局虽然是XML格式的文件,最终也会也会被编译,和java代码一样,系统会根据属性的不同去调用构造方法,
public MyTextView(Context context,AttributeSet attrs){
super(context,attrs);
}
//这个构造方法和第二个一样,就是多了一个style样式的参数,它等同于value文件中的style
public MyTextView(Context context,AttributeSet attrs,int defstyle){
super(context);
}
}
在使用自定义空间的时候,在XML文件中声明出使用的控件,一定需要是完整的类名,其中包括包名,可以ctrl加左键点击空间来检验是否引用了控件对应正确的类。
14:相对布局控件的排布以及分割线
使用layout_below可以设置在某个控件下面,其他雷同。
布局中的分割线其实就是用一个高度很小,并且背景填充为黑色的View布局来代替
15:创建可复用布局的方式
MyView是继承自RelativeLayout的一个布局类,创建一个方法并在方法内用addView()方法加载复用的布局,并在每个构造方法中都调用这个方法,当在初始化的时候就会调用这方法。这样在创建布局文件的时候,就可以用这个自定义的布局类作为标签,达到复用的目的,并且还可以使用RelativeLayout的属性。
public class MyView extends RelativeLayout {
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context) {
super(context);
init();
}
private void init(){
View v=View.inflate(getContext(), R.layout.activity_main, null);
this.addView(v);
}
}
//View v=View.inflate(getContext(), R.layout.activity_main, null);
this.addView(v);
View.inflate(getContext(), R.layout.activity_main, this);
这两种方式很类似,第一种是给View设置了布局,并且给它里面添加一个子View
第二种方式是把这个自定义布局类自己作为父控件,然后创建加载的View作为自己的子控件。
16:关于CheckBox
CheckBox天生具有焦点和点击事件,如果想要取消这种效果在XML布局文件中添加属性
android:focusable=”false” //不可使用焦点
android:clickable=”false” //不可点击
17:关于根据CheckBox更改是否提示更新的对话框
//自定义布局,布局里可以更改子控件的文本,CheckBox的状态等
public class MyView extends RelativeLayout {
private TextView tv_title;
private TextView tv_des;
private CheckBox cb_setting;
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context) {
super(context);
init();
}
private void init(){
//下面两行代码,是给MyView加载布局
View view=View.inflate(getContext(), R.layout.setting_item, null);
this.addView(view);
//初始化3个控件,目的是让MyView的实例通过调用自己自定义的方法来触发各个控件改变值的语句。
tv_title=(TextView) view.findViewById(R.id.tv_title);
tv_des=(TextView) view.findViewById(R.id.tv_des);
cb_setting=(CheckBox) view.findViewById(R.id.cb_setting);
}
public void setTitle(String title){
tv_title.setText(title);
}
public void setDes(String des){
tv_des.setText(des);
}
public void setChecked(boolean isCheck){
cb_setting.setChecked(isCheck);
}
public boolean isChecked(){
return cb_setting.isChecked();
}
}
MyView的布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="提示更新"
android:textSize="18sp"
/>
<TextView
android:id="@+id/tv_des"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="提示更新"
android:textSize="12sp"
android:paddingTop="30dp"
/>
<CheckBox
android:id="@+id/cb_setting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/cb_setting"
android:layout_alignBottom="@+id/cb_setting"
android:layout_alignParentRight="true"
android:gravity="center_vertical"
android:focusable="false"//这两个属性决定CheckBox不可获得焦点和不可以被点击。防止发生组件的冲突
android:clickable="false"
/>
</RelativeLayout>
在Activty_main的布局中引用这个自定义布局MyView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.dialogdemo.MyView //引用自定义布局,需要写全名
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
></com.example.dialogdemo.MyView>
</RelativeLayout>
在Activity中的设置
public class MainActivity extends Activity {
MyView myView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myView=(MyView) findViewById(R.id.main);
myView.setTitle("通知");
myView.setDes("打开提示更新");
myView.setChecked(true);
myView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {//逻辑判断,根据CheckBox的状态来改变提示,并且以后可以根据此可以改是否出现更新对话框
if(myView.isChecked()){
myView.setChecked(false);
myView.setDes("打开提示更新");
}else{
myView.setChecked(true);
myView.setDes("关闭提示更新");
}
}
});
}
}
CheckBox的状态可以通过SharePrefence保存一个键值对(这里保存一个boolean值,保存到config这个文件中)到手机里,然后下次可以根据保存的状态去判断。
18:自定义属性
在values文件夹在创建名字为attrs的XML文件,系统会识别attrs这个名字的文件。
<?xml version="1.0" encoding="utf-8"?>
<resourcrs>
<declare-styleable name="com.yuyang.TestDemo.MyTextView"><!--name代表一个控件,这里可以是TextView等,自定义的空间必须写全名-->
<attrs name="title" format="string"> <!--name是属性名,format:是类型-->
<attrs name="des" format="string">
</declare-styleable>
</resources>
自定义的这些属性,这里有title,des都会在R文件中生成,attr的类,并且生成关于属性的字段,并且都赋值一个int型的id相匹配。
public final class R{
public static final class attr{
public static final int title=0x7f010000;
public static final int des=0x7f010001;
}
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.dialogdemo.MyView
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="wrap_content"
></com.example.dialogdemo.MyView>
</RelativeLayout>
xmlns:android="http://schemas.android.com/apk/res/android"
上面这句代码的xmlns:是xml name space,XML命名空间的的意思
如android:layout_weight=”match_parent” 就是可以用android这个名词来引用,也就是引用后面的字符串这个命名空间
如果是用自定义控件的自定义属性可以这样声明命名空间
xmlns:yuyang="http://schemas.android.com/apk/res/com.yuyang.TestDemo"
就是在http://schemas.android.com/apk/res/后面使用自己的包名
之后就可以用yuyang:title=”标题名称”这样来使用属性了
在自定义控件MyView中
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
attrs.getAttributeValue(namespace,name); //第一个参数是命名空间,第二个参数是属性名,通过这两个参数可以获得属性的值。这个方法返回一个String类型的值,
}
19:通过AlertDialog对话框进行密码输入,和确认密码的输入框的操作
AlertDialog.Builder builder=new AlertDialog.Builder(this);
View view=View.inflate(context,resource,root);
builder.addView(view);//对话框可以用一个View来填充。
builder.setCancelable(false);//设置不可取消
builder.show();//显示对话框
AlertDialog dialog=builder.create();
dialog.show();
/*创建对话框对象,为什么要创建AlertDialog对象?因为我们是用的自己创建的组合布局,里面有两个EditText,一个确定按钮,一个取消按钮,并没有使用AlertDialog对话框的
builder.setPositiveButton(text, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});这个设置积极消极按钮的监听器,这里的监听器的onClick方法有一个参数是dialog,可以调用dialog.dismiss()方法来隐藏
所以这里我们自己用builder.create()来创建一个AlertDialog对象,才可以设置对话框的隐藏方法。*/
//builder.show();//显示对话框
EditText ed_password=(EditText)view.findViewById(R.id.ed_password);
EditText ed_password2=(EditText)view.findViewById(R.id.ed_password2);
Button btn_ok=(Button)view.findViewById(R.id.btn_ok);
Button btn_cancel=(Button)view.findViewById(R.id.btn_cancel);
//确认按钮
btn_ok.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
//取消按钮
btn_ok.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();//隐藏对话框
}
});
20:dialog有一个设置视图的方法。
dialog.setView(view,viewSpacingLeft,viewSpacingTop,viewSpacingRight,viewSpacingBottom),
后面四个参数是设置上下左右内边框的距离。
21:判断字符串是否为空
String s=”“;
TextUtils . isEmpty(s);//null,没有内容没有内存,”“有内存地址但是没有内容。这个方法判断是否为空。
对于输入密码的操作,第一次设置密码的时候可以用SharePrefence的putString()方法保存到SharePrefence设置的文件中,通过key,value的方式。当下次需要输入密码的时候,用SharePrefence的getString()方法取得,从文本框中得到的字符串与SharePrefence取得的字符串进行比较(注意用TextUtils判断非空操作),进行密码错误和密码正确的不同流程操作。
22:MD5加密
Message Digest:消息摘要
public class MD5 {
public static void main(String[] args) {
String s = null;
try {
s = MD5.md5Encode("12345678");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(s);
}
public static String md5Encode(String inStr) throws Exception {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
}
byte[] byteArray = inStr.getBytes("UTF-8");
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
}
23:EditText中设置inputType文本类型为password,可以让文本变为小圆点或星号。
可以通过在XML文件去设置控件文本的类型
android:inputType=”textPassword”显示为密码形态,或android:inputType=”none”正常的不隐藏形态
也可以通过代码去设置
EditText ed=(EditText)findViewById(R.id.et);
ed.setInputType(0);
ed.setInputType(129);
//方法参数接收一个int值,这个0代表的是不隐藏,129代表的是隐藏,相对应于源码data/res/values/attrs.xml文件里设置的值的ID,源码里面的值是16进制的值,转换成十进制之后填到参数列表中就可以了。
24:TextView旁边的小图标
TextView空间的XML文件中
android:drawableLeft=”” 放入图片资源就可以了,上下左右都可以
25:ImageView在RelativeLayout中居中显示
anroid:layout_centerInParent=”true”
26:一个简单的小算法一个锁的图标点击一次加锁,再点击解锁
int count=0;
if(count%2=0){
//加锁
}else{
//解锁
}
count++;
27:按钮等控件的状态选择器
比如说按钮普通状态和点击状态
创建一个在drawable文件下创建一个button.xml文件
//设置选择器
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
android:drawable="@drawable/pressed"/> <!--按下的状态-->
<item android:drawable="@drawable/normal"/> <!---普通的状态->
</seletor>
//使用选择器
<Button
android:layout_height="wrap_content"
android:layout_width="wrap_content"
anroid:background="@drawable/button"/>//直接引用前面设置的状态选择器,也就是button.xml文件。
28:抽取样式
比如说:
activity_main XML文件下
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下一页"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:drawableLeft="@drawable/ic_luncher"
android:onClick="next"/>
acitivity_second XML文件下
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下一页"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:drawableLeft="@drawable/ic_luncher"
android:onClick="next"/>
这两个一样的控件可以抽取出来到valuse文件夹下的styles文件中
<style name="next">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:text">下一页</item>
<item name="android:layout_alignParentRight">true</item>
<item name="android:layout_alignParentBottom">true</item>
<item name="android:onClick">next</item>
</style>
使用的时候如activitiy_main中
<Button
style="@style/next"
//android:text="替换了文本" //如果想要复用这个style但是文本需要改变,直接在后面设置就好了,它会覆盖前面的设置
//android:drawableLeft="@drawable/ic_luncher"//如果这个Button中的左边图片想要取消可以这么写
// android:drawableLeft="@null"//这样就可以取消了
/>
直接用一个style标签引用这个自定义的style文件就可以了
29:android系统特有的 .9 图片
可以设置几个点来划分可以拉伸的区域。(可以用一个带圆角的小正方形图片拉伸成长方形,而不用担心变形,因为制作的 .9图片已经设置好防拉伸的设置区域了。)
.9制作工作在sdk/tools/draw9patch.bat文件,打开画圆点制作图片就可以了。
30:onKeyDown()方法,监听手机物理按钮的点击事件
keyCode:物理按钮的标识,如BACK键,HOME键
event:按键的处理事件
@override
public boolean onKeyDonw(int keyCode,KeyEvent event){
if(keyCode==KeyEvent.KEYCODE_BACK){
//return true; //返回ture可以屏蔽按键的事件,但是不能屏蔽HOME键的事件,为了安全。
//这里可以添加自己的逻辑代码操作
}
return super.onKeyDown(keyCode,event);
}
31:Activity之间的平移动画
在res资源文件夹下创建一个anmi的文件,然后在这个文件里创建一个in.xml文件,这个文件就可以自定义命名了
<?xml version="1.0" encoding="utf-8"?>
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="100%"//从X轴的100%开始,100%代表屏幕的X轴整个宽度,
android:toXDelta="0"//到X轴的0%结束,
android:duration="500"//持续时间,单位是毫秒
>
</translate>
out.xml是退出的动画
<?xml version="1.0" encoding="utf-8"?>
<translate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"//从0开始
android:toXDelta="-100%"//到X轴的-100%结束,实际上是向左平移了一个屏幕的距离
android:duration="500">//持续时间,单位是毫秒
>
</translate>
在代码中使用的示例如下:
overridePendingTransition(R.anmi.in,R.anmi.out);
//第一个参数是进入屏幕的那个界面的进入动画,第二个参数是退出屏幕的那个界面的退出动画。
//比如从Activity1向左滑动然后带动Activity2从屏幕右侧滑进屏幕,
//第一个参数是进入动画,也就是Activity2的进入动画;
//第二个参数是退出动画,也就是Activity1的退出动画。
在触屏的时候要做手GestureDetector gestureDetector=new GestureDetector(Context context, OnGestureListener listener)nGestureListener可以写一个实现类去重写那些方法,也可以继承SimpleOnGestureListener这个类,选择性的重写几个方法
触屏的事件监听
@Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);//这里调用手势识别去监听MotionEvent,
return super.onTouchEvent(event);
}
在速度识别监听器里重写滑动方法
@Override //参数e1代表刚接触屏幕的事件,e2代表手离开屏幕的事件,velocityX是X轴运动的速率,velocityY是Y轴运动的速率。
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
float start=e1.getRawX();//X轴开始的坐标
float end=e2.getRawX();//X轴结束的坐标
float startY=e1.getRawY();//Y轴开始的坐标
float endY=e2.getRawY();//Y轴结束的坐标
if((Math.abs(startY-endY))>50){//以下都是一些逻辑判断
return false;
}
if((end-start)>100){
Intent intent=new Intent(SecondActivity.this,MainActivity.class);
startActivity(intent);
finish();
overridePendingTransition(R.anim.in2, R.anim.out2);
}
return super.onFling(e1, e2, velocityX, velocityY);
}
32:设置shape图形资源
在res/drawable目录下创建一个shape类型的XML文件
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"//这里可以设置图形的类型,如圆形,长方形
>
<corners android:radius="10dp"/>//设置弧度
<solid android:color="#ff0000"/>//设置颜色
<stroke android:width="3dp"/>//设置虚线
<gradient android:startColor="#ff0000" android:centerColor="#00ff000" android:endColor="#0000ff">//设置渐变颜色
</shape>
shape的使用:凡是能使用drawable的地方都可以,一般用在TextView或者Button中。
33:获取SIM卡序列号
TelephonyManager tel=getSystemService(TELEPHONY_SERVICE);
String s=tel.getSimSerialNumber();
34:发送短信
需要权限:
SmsManager smsManager=SmsManager.getDefault();
smsManager.sendTextMessage(destinationAddress,scAddress,text,sentIntent,deliveryIntent);
//destinationAddress:联系人
//scAddress:短信中心地址,一般填写null
//text:短信内容
//sentIntent:这是一个PendingIntent,是否发送成功,延迟发送,一般为null
//deliveryIntent:短信的协议,一般为null
35:获取手机联系人
步骤:
1,创建ListView显示联系人列表
2,使用适配器
3,把联系人添加到一个List集合里面,作为ListView的参数内容
ContactsContract.CommonDataKinds.Phone.CONTENT_URI:这个是URI地址
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME:联系人姓名
ContactsContract.CommonDataKinds.Phone.NUMBER:联系人号码
他们都是ContactsContract.CommonDataKinds.Phone里存储的内容
使用getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder)返回一个Cursor对象,第一个参数是URI。
手机联系人的文件路径是:
data/data/com.android.providers.contacts/databases/contact2.db 存储在这个数据库中。
contact2.db这个数据库中的raw_contacts这张表是存储了联系人和号码。
public class MainActivity extends Activity {
ListView listView;
ArrayAdapter<String> adapter;
List<String> contactsList=new ArrayList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView=(ListView) findViewById(R.id.listView);
adapter=new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contactsList);
listView.setAdapter(adapter);
getContacts();
}
private void getContacts() {
Cursor cursor = null;
try {
cursor=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
while(cursor.moveToNext()){
String displayName=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
if((!TextUtils.isEmpty(displayName))&&(!TextUtils.isEmpty(number))){
contactsList.add(displayName+"\n"+number);
}
}
} catch (Exception e) {
// TODO: handle exception
}finally{
if(cursor!=null){
cursor.close();
}
}
}
(Tips:注意结束的时候关闭Cursor,还有注意查询联系人需要权限,还有一个重点是查询联系人的时候最好判断得到的数据是否为空,比如查询的联系人中有一个被删除了,其实记录仍然存在,但是在数据库中的id为null,这样查询出来的结果可能会报错。)
36:关于业务的也就是关系到数据库的,一般都进行单元测试。
单元测试一般都单独创建一个测试工程,然后创建一个类继承自AndroidTestCase,然后在这个类里面创建一个方法,方法里去执行要测试的内容,最后点击这个方法右键去测试。
37:关于异步加载
自己定义异步加载的类
mport android.content.IntentSender.SendIntentException;
import android.os.Handler;
import android.os.Message;
public abstract class MyAyncTask {
Handler handler=new Handler(){
public void handleMessage(Message msg) {
postTask();
};
};
public abstract void preTask();
public abstract void 执行preTask();方法
public abstract void postTask();
public void excute(){
preTask();//在线程之前执行preTask();方法
new Thread(){
public void run() {
doinTask();//线程中执行执行doinTask()方法
handler.sendEmptyMessage(0);//在线程末尾整形,发送消息给handler,在handler中执行postTask();
};
}.start();
}
}
使用这个自己一定以的异步加载工具类
去实现抽象方法
new MyAyncTask() {
@Override
public void preTask() {}
@Override
public void postTask() {}
@Override
public void doinTask() {}
}.excute();
38:定义进度条
可以定义一个比如旋转的动画,
然后在ProgressBar,XML文件中添加属性
android:indeterminateDrawable=”@drawable/。。。。”/>
去调用那个动画,进度条的动画就改变了。
39:短信拦截
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsMessage;
public class SmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Object[] objs=(Object[]) intent.getExtras().get("pdus");
for(Object obj:objs){
SmsMessage smsMessage=SmsMessage.createFromPdu((byte[])obj);//创建短信实例
String body=smsMessage.getMessageBody();//获取短信内容
String sender=smsMessage.getOriginatingAddress();//获取联系人
//根据接收的短信内容,解析出来并且执行一些操作,为了安全可以拦截短信不被系统接收,防止被其他人看到。
//这里用"#*warn*#".equals(body)而不是"body".equals(#*warn*#)是为了可以防止空指针异常
if("#*warn*#".equals(body)){
abortBroadcast();//拦截短信,如果此广播接收者优先级高于系统的优先级,可以拦截,如果低于系统优先级,那么系统会先收到。
}else if("#*手机被偷*#".equals(body)){
abortBroadcast();
}else if("#*银行卡被盗*#".equals(body)){
abortBroadcast();
}
}
}
}
清单文件的注册
接收短信的权限
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<receiver android:name="com.example.phonenumber.SmsReceiver">
<intent-filter android:priority="1000">//这里的优先级是1000,系统的优先级是0,高于系统优先级可以拦截短信
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>//选择接收的广播
</intent-filter>
</receiver>
40:手机定位
3种定位方法
1:Wifi定位,IP定位,根据IP地址获取你的地理位置,精确度不高
2:基站定位,根据距离信号塔的距离,精确度比较高,精确度取决于基站个数
3:GPS定位,通过光波和定位卫星通讯来获取位置坐标,精确度很高,但是耗电高,不需要联网。AGPS技术是通过联网来修正获取的坐标,准确度特别高。
一般使用百度定位sdk的第三方 它也是基于gps定位
还有高德地图
41:音乐播放器
如果一个类里面有一个播放音乐的功能,那么new出多个这个类的对象来同时播放音乐,会出现重复音,那么把这个MediaPlayer的对象定义为静态成员变量,那么它在内存中就只有一份,
private static MediaPlayer mediaPlayer =MediaPlayer.create(context,R.music.baojingyinyue);//第二个参数是音乐资源ID
if(mediaPlayer !=null){
mediaPlayer.replace();//释放资源
}
mediaPlayer.start();//开始播放,这样就不会重复播放了
42:把号码归属地的数据库导入到项目中(可以直接将数据库复制到assets文件中)
一般把关于数据库操作的类后缀为DAO。
private void copyDb(){
File file=new File(getCacheDir(), "address.db");
if(!file.exists()){//判断手机中是否存在这个数据库,有就跳过if语句,没有就去创建
//从assets目录中将数据库读取出来
//1,获取assets的管理者
AssetManager am=getAssets();
InputStream in=null;
FileOutputStream out=null;
try {
//2,读取数据库
in=am.open("address.db");//assets目录下拷贝的文件,这里的文件是不会安装到手机的
//写入流
//getCacheDir:获取缓存的路径,通过上下文来获取,在Activity中其实是this.new File(getFilesDir(),"address.db"),如果在自定义的类中,就必须传一个Context来作为上下文了。
//getFilesDir:获取文件的路径
out=new FileOutputStream(new File(getFilesDir(),"address.db"));//把数据库写入到getFilesDir()文件中,文件名是"address.db"
//3,读写操作
//设置缓冲区
byte[] b=new byte[1024];
int length=-1;
while((length=in.read(b))!=-1){
out.write(b, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(in!=null){
in.close();
}
if(out!=null){
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
43:布局文件 Xml文件以及图片资源文件名不能大写,图片名不能有数字,会造成R文件数据丢失。
44:监听EditText文本变化的监听器,类似网站的文本编辑框的输入关键词的自动搜索
editText.setTextChangeListener(new TextWatcher(){
@override//当文本变化时触发该方法
public void onTextChanged(CharSequence s,int start,int before,int count){
}
@override
public void beforeTextChanged(CharSequence s,int start,int count){
}
@override
public void afterTextChanged(Editable s){
}
});
45:一些动画效果可以通过APIDEMO去参考,自己查找线索,根据线索可以Ctrl+H去进行搜索。
46:手机震动Vibrator
震动需要权限
<uses-permission android:name="android.permission.VIBRATE"/>
//1,获取震动的管理者
Vibrator vibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE);
//2,震动的时间(毫秒)
vibrator.vibrate(Long m);
//3,震动的频率
vibrator.vibrate(long[] pattern, int repeat);//第一个参数是震动频率;第二个参数是循环,-1为不循环,非-1的整数代表从从long数组中第几个元素开始。
47:判断service是否在运行
//自定义方法判断Service是否在运行,是否存活
public static boolean inRunningService(String className,Context context){
//获取ActivityMannager,它是进程的管理者,活动的管理者
ActivityManager activityManager=(ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
//获取正在运行的服务
List<RunningServiceInfo> runningServiceInfos=activityManager.getRunningServices(100);//参数100代表获得信息的上限,
//遍历集合
for (RunningServiceInfo runningServiceInfo : runningServiceInfos) {
//获取控件的标识
ComponentName componentName=runningServiceInfo.service;
//获取正在运行的服务的全类名
String name=componentName.getClassName();
//将获取到的正在运行的服务的全类名和传递过来的类名比较,如果一致返回true,不一致返回false
if(className.equals(name)){
return true;
}
}
return false;
}
}
48:关于移动控件后,把位置信息保存到SharePreference中,下次打开从SharePreference中读取位置,称为回显操作。
必须得到父容器的LayoutParams,才能去设置位置,这里的父容器为RelativeLayout,因为他有margin属性,所以才能设置位置。
SharePrefence sp=getSharePreference("config",MODE_PRIVATE);//第一个参数是设置的文件路径,第二个是模式
int x=sp.get("x",0);//取得之前保存在SharePreference中的x,y键,获取相应的值
int y=sp.get("y",0);
TextView tv=(TextView)findViewById(R.id.textView);
RelativeLayout.LayoutParams params=(RelativeLayout)tv.getLayoutParams();
params.leftMargin=x;//分别把x,y的值设置为左边距和顶边距,。这两行代码表示给params设置左右边距
params.topMargin=y;
tv.setLayoutParams=params;//给控件设置布局属性
设置属性和重新绘制控件有根本的区别,
绘制控件需要先初始化控件后,才能重新绘制;
设置属性是初始化控件之前,相当与添加了相对于父控件的属性。
如下是根据手指移动重新绘制控件的例子,类似与静帧动画。
tv.setOnTouchListener(new OnTouchListener() {
//用于记录起始位置x,y的变量
int startX=0;
int startY=0;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {//获取event事件的动作
case MotionEvent.ACTION_DOWN:
//记录按下位置的坐标
startX=(int) event.getRawX();
startY=(int) event.getRawY();
System.out.println("按下");
break;
case MotionEvent.ACTION_MOVE:
//获取手指移动到的新位置,
int newX=(int) event.getRawX();
int newY=(int) event.getRawY();
//计算出与上一次位置的偏移量
int distanceX=newX-startX;
int distanceY=newY-startY;
//计算新的控件位置,获取控件的左边距加上位移的距离就是新的左位置,右边位置就是新的左边位置加上控件宽度
int l=tv.getLeft()+distanceX;
int t=tv.getTop()+distanceY;
int r=l+tv.getWidth();
int b=t+tv.getHeight();
//获取屏幕宽高
WindowManager windowManager=(WindowManager) getSystemService(WINDOW_SERVICE);
int windowWidth=windowManager.getDefaultDisplay().getWidth();
int windowHeight=windowManager.getDefaultDisplay().getHeight();
//如果控件超出范围就不会重绘,直接break,等待下次位移的重绘
if(l<0||t<0||r>windowWidth||b>windowHeight){
break;
}
//设置新的控件位置
tv.layout(l, t, r, b);
//重置控件的起始位置
startX=newX;
startY=newY;
System.out.println("移动");
break;
case MotionEvent.ACTION_UP:
break;
}
return false;
}
});
49:关于触摸事件和点击时间的冲突
onTouch:有三个事件:按下,移动,抬起
onClick:有一个组合事件:按下+抬起,组合成一个事件
如果一个控件同时实现了onTouch和onClick,那么在屏幕上进行操作的时候,
先会触发onTouch的MotionEvent.ACTION_DOWN这个按下事件,如果在onTouch的方法里最后返回了true,那么代表事件被消费了,会依次触发后面的移动,抬起等操作,因为不是false,就不会被其他拦截,便不会触发onClick的事件。
如果是false的情况,表示事件被拦截了,此时onTouch的按下事件被执行,然后拦截onTouch,既然被拦截了,那么这个按下的操作也会触发onClick的按下事件,由于onClick需要监听完按下+抬起的动作,此时正处于按下状态,它会一直监听着事件。这个onClick在等待抬起操作,此时onTouch会往后面执行,当它执行完抬起之后,onClick也会触发完整个事件。
50:关于双击的按钮点击事件
51:关于帧动画
anim文件夹下的XML文件,fly.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">//true代表执行一次,false代表循环播放
<item android:drawable="@drawable/image_first" android:duration="200"/>//设置静帧图片,以及持续时间
<item android:drawable="@drawable/image_second" android:duration="200"/>
</animation-list>
//imageView布局
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@anim/fly.xml"
/>
//初始话ImageView
ImageView iv=(ImageView)findViewById(R.id.iv);
//根据ImageView得到AnimationDrawable对象,并开启动画
AnimationDrawable ad=(AnimationDrawable)iv.getBackground();
ad.start();
52:从Service跳转到Activity的情况
因为service没有任务栈,所以在跳转activity的时候要添加任务栈
Intent intent=new Intent(MyService.this,MyActivity.class);
intent.setFlags(Intent.FLAG_ACITIVITY_NEW_TASK);//添加任务栈
startActivity(intent);
53:渐变动画
AlphaAnimation alphaAnimation=new AlphaAnimation(0,1);
alphaAnimation.setDuration(1000);//持续时间,单位是毫秒
ImageView iv=(ImageView)findViewById(R.id.iv);
iv.startAnimation(alphaAnimation);
54:发送延迟消息
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//xxxxxx
}
}, delayMillis);
55:创建数据库
一般放在com.yu.textdemo.db包下,对数据库操作的类放在com.yu.textdemo.db.dao包下
public class MyOpenHelper extends SQLilteOpenHelper{
public static final String DB_NAME="info";//表名,创建为成员变量为了后期修改方便。
public MyOpenHelper(Context context){
super(context,"blacknum.db",null,1);//第二个参数是数据库名称,第三个是游标工厂,第四个是版本号
}
@override
public void onCreate(SQLiteDatabase db){//第一次创建数据库的时候调用,方法体力自己执行创建表结构。
db.execSQL("create table "+DB_NAME+"(_id integer primary key autoincrement,badNum varChar(20),mode varchar(2))");//执行SQL语句,一定要在SQL软件里面测试以下是否能正确执行,然后执行单元测试也很有要,因为这个属于业务操作,所以要保证安全性。
}
@override
public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){//当数据库版本放生变化的时候调用
}
}
使用数据库实现增删改查,对数据库操作的类放在com.yu.textdemo.db.dao包下
public class BadNumDao{
//定义模式的常量
public static final int CALL=0;
public static final int SMS=1;
public static final int ALL=2;
private MyOpenHelper myOpenHelper;
public BadNumDao(Context context){
myOpenHelper=new MyOpenHelper(context);
}
public void addBadNum(String num,String mode){
//获取数据库
SQLiteDatabase sql=myOpenHelper.getWritableDatabase();
//添加数据的操作
ContentValues values=new ContentValues();
values.put("badNum ",num);//添加的键是数据库中的键,值为参数传进来的值
values.put("mode",mode);
sql.insert(MyOpenHelper.DB_NAME,null,values);//插入操作,第一个是表名,第二个是null,第三个是值。
sql.close();//关闭数据库,防止内存溢出
}
//更新数据,更新相应号码的屏蔽类型
public void upDataBadNum(String num,String mode){
SQLiteDatabase sql=myOpenHelper.getWritableDatabase();
ContentValues values=new ContentValues();
values.put("mode",mode);
sql.update(MyOpenHelper.DB_NAME,values,"badNum=?",new String[]{num});
sql.close();
}
//查询数据
public int queryBadNumMode(String num){
String mode=null;
SQLiteDatabase sql=myOpenHelper.getReadableDatabase();//查询用.getReadableDatabase()方法只读就行
//table:表名
//columns:查询的字段
//selection:查询条件 相当于where=?
//seletionArgs:查询条件的参数
//groupBy:分组
//having:去重
//orderBy:排序
//sql.query(table,selection,seletionArgs,groupBy,having,orderBy);
Cursor cursor=sql.query(MyOpenHelper.DB_NAME,new String(){"mode"},"badNum=?",num,null,null,null);
while(cursor.moveToNext){
String mode=cursor.getNext();
}
cursor.close();
sql.close();
return mode;
}
//删除数据
public void deleteBadNum(String num){
SQLiteDatabase sql=myOpenHelper.getWritableDatabase();
sql.delete(MyOpenHelper.DB_NAME,"badNum=?",new String(){num});
sql.close();
}
//查询所有数据
public List<Person> queryAll(){
List<Person> list=new Array<Person>();
SQLiteDatabase sql=myOpenHelper.getWritableDatabase();
Cursor cursor=sql.query(MyOpenHelper.DB_NAME,new String[]{"badNum","mode"},null,null,null,null);
while(cursor.moveToNext){}
String num=cursor.getString(cursor.getIndexColumns("badNum"));
String mode=cursor.getString(cursor.getIndexColumns("mode"));
Person person=new Person(num,mode);
List.add(person);
}
cursor.close();
sql.close();
return list;
}
package com.yu.textdemo.bean
public class Person {//java bean类,用于此对象的存取数据。放在bean包下
private String badNum;
private String mode;
public Person() {
super();
}
public Person(String badNum, String mode) {
super();
this.badNum = badNum;
this.mode = mode;
}
public String getBadNum() {return badNum;}
public void setBadNum(String badNum) {this.badNum = badNum;}
public String getMode() {return mode;}
public void setMode(String mode) {this.mode = mode;}
@Override
public String toString() {
return "Person [badNum=" + badNum + ", mode=" + mode + "]";
}
}
56:断言
assertEquals(expected,actual);//第一个参数是期望的值,第二个参数是实际的值,这个方法可以判断数据库查找的测试
57:findViewById是从根布局查找,挨个查找布局里面的控件,如果根布局里面有两个布局,然后每个布局里面各有三个TextView,如果想要找到并初始化根布局下第二个布局的第三个TextView,那么它会利用二叉树遍历多次才能找到这个控件。
58:ListView列表中删除一个元素
BadNumDao.deleteBadNum(person.getBadNum());//1,利用数据库业务类删除数据库中的元素
listView.remove(position);//2,删除指定的元素
adapter.notifyDataSetChanged();//3,因为listView是通过adapter适配器来显示的,所以需要更新适配器adapter
//(Tips:注意这里的顺序,先删除数据库,然后删除listView里的元素,再更新适配器adapter)
ListView中添加一个元素:
listView.add(0,new Person(“26950526”,”1”));//把元素添加到下标为0的位置,后面的依次往后排
59:数据库的降序排列
sql.query(MyOpenHelper.DB_NAME,new String[]{“badNum”,”mode”},null,null,null,”_id desc”);//按_id降序
按_id正序排列是”_id esc”
查找20条数据的SQL语句
select badNum from info order by _id desc limit 20 offset 20
//查询badNum字段从info表中,排序按照_id的降序,查询20个,查询的起始位置是偏移量20的位置。
limit:查询的总个数
offset:查询的起始位置
60:RadioGroup包含RadioButton,
radioGroup.getCheckedRadioButtonId();//获取被选中的那一个单选按钮的ID,返回一个int值。
61:ListView滑动监ListView listView=(ListView) findViewById(R.id.listView);
//获取listView在当前未滑动屏幕状态下显示的最后一个条目
listView.getLastVisiblePosition();
//滑动监听
listView.setOnScrollListener(new OnScrollListener() {
//当滑动状态改变的时候
//参数view:就是ListView
//scrollState:滑动的状态
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
OnScrollListener.SCROLL_STATE_IDLE;//空闲状态
OnScrollListener.SCROLL_STATE_TOUCH_SCROLL;//缓慢滑动状态
OnScrollListener.SCROLL_STATE_FLING;//快速滑动的状态
}
//当滑动的时候调用的方法
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
});android在单元测试类测试方法的时候需要注意
需要把成员变量和其他所有需要的实例等等代码全部放到测试方法的里面,否则会空指针,因为是点击方法去执行的测试方法。
63:删除通话记录的方法
//获取进来的号码
String num="12343123879";
//获取内容解析者
ContentResolver resolver=getContentResolver();
//添加地址 content://是内容提供者写URI的时候的固定写法 call_log是路径,calls是数据库表名
Uri uri=Uri.parse("content://call_log/calls");
//删除表中的数据
resolver.delete(uri,"number=?","new String[]{num}");
64:获取安装的应用程序
public static List<AppInfo> getAppInfos(Context context){
List<AppInfo> list = new ArrayList<AppInfo>();
//获取包管理者,
PackageManager pm = context.getPackageManager();
//获取安装程序,以包名显示,返回一个list集合
List<PackageInfo> installedPackages = pm.getInstalledPackages(0);
for (PackageInfo packageInfo : installedPackages) {
//获取包名
String packageName = packageInfo.packageName;
//获取版本号
String versionName = packageInfo.versionName;
//获取应用信息
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
//获取应用图标
Drawable icon = applicationInfo.loadIcon(pm);
//获取应用的名字,因为在清单文件中,application标签中的laber标签代表了应用程序的名字
String name = applicationInfo.loadLabel(pm).toString();
//判断系统程序,还是用户的程序
boolean isUser;
int flags = applicationInfo.flags;
//(applicationInfo.FLAG_SYSTEM & flags) == applicationInfo.FLAG_SYSTEM,判断FLAG是否是系统的标签
if ((applicationInfo.FLAG_SYSTEM & flags) == applicationInfo.FLAG_SYSTEM) {
//不是用户程序
isUser = false;
}else{
//是用户程序
isUser = true;
}
//是否安装在SD卡中,FLAG_EXTERNAL_STORAGE是外部存储的标签,也就是SD卡
boolean isSD;
if ((applicationInfo.FLAG_EXTERNAL_STORAGE & flags) == applicationInfo.FLAG_EXTERNAL_STORAGE) {
//是外部存储
isSD = true;
}else{
//不是外部存储
isSD = false;
}
//添加到Bean类中
AppInfo appInfo = new AppInfo(name, icon, packageName, versionName, isSD, isUser);
//把Bean类对象添加到集合中
list.add(appInfo);
}
//返回集合,拿到所有应用的信息
return list;
}
Bean类
public class AppInfo {
//应用名
private String name;
//应用图标
private Drawable icon;
//应用包名
private String packagName;
//应用程序版本号
private String versionName;
//判断是否是SD安装
private boolean isSD;
//判断是用户自己安装的程序,还是系统程序
private boolean isUser;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Drawable getIcon() {
return icon;
}
public void setIcon(Drawable icon) {
this.icon = icon;
}
public String getPackagName() {
return packagName;
}
public void setPackagName(String packagName) {
this.packagName = packagName;
}
public String getVersionName() {
return versionName;
}
public void setVersionName(String versionName) {
this.versionName = versionName;
}
public boolean isSD() {
return isSD;
}
public void setSD(boolean isSD) {
this.isSD = isSD;
}
public boolean isUser() {
return isUser;
}
public void setUser(boolean isUser) {
this.isUser = isUser;
}
public AppInfo() {
super();
// TODO Auto-generated constructor stub
}
public AppInfo(String name, Drawable icon, String packagName,
String versionName, boolean isSD, boolean isUser) {
super();
this.name = name;
this.icon = icon;
this.packagName = packagName;
this.versionName = versionName;
this.isSD = isSD;
this.isUser = isUser;
}
@Override
public String toString() {
return "AppInfo [name=" + name + ", icon=" + icon + ", packagName="
+ packagName + ", versionName=" + versionName + ", isSD="
+ isSD + ", isUser=" + isUser + "]";
}
}
65:NoPointExecption空指针异常
一般都是person.speak(),前面这个实例调用了一个方法,如果这个实例为空,就报空指针。
person.speak(“chinese”,”man”);如果参数为空,也会报空指针。
66:获取条目位置的坐标x,y的值,储存到一个数组当中。
int[] i=new i[2];
view.getLocationInWindow(i);
67:PopupWindow弹窗控件
PopupWindow是Android上自定义弹出窗口,使用起来很方便。
PopupWindow的构造函数为
public PopupWindow(View contentView, int width, int height, boolean focusable)
contentView为要显示的view,width和height为宽和高,值为像素值,也可以是MATCHT_PARENT和WRAP_CONTENT。
focusable为是否可以获得焦点,这是一个很重要的参数,也可以通过
public void setFocusable(boolean focusable)
来设置,如果focusable为false,在一个Activity弹出一个PopupWindow,按返回键,由于PopupWindow没有焦点,会直接退出Activity。如果focusable为true,PopupWindow弹出后,所有的触屏和物理按键都有PopupWindows处理。
如果PopupWindow中有Editor的话,focusable要为true。
68:先提到一些
关于有些控件是getApplicationCoxtext()的,比如说dialog弹出的对话框,如果此时按返回键,那么这个Activity会销毁,那么之前显示在Activity上方的dialog对话框就找不到需要挂载的地方,此时可能会报错,但是不一定会造成程序崩溃。所以,如果需要的话,在退出Activity的时候,也就是在onDestory()方法里,把对话框也销毁掉。其他控件同理。
69:通过在自己的程序打开系统卸载界面,卸载其他卸载程序
(Tips:有些程序是系统程序,所以可能需要超级管理员权限)
Intent intent=new Intent();
intent.setAction(“android.intent.action.DELETE”);
intent.addCatagory(“android.intent.category.DEFAULT”);
intent.setData(Uri.parse(“package:”+所要卸载的应用程序包名));
startActivityForResult(intent,0);//第二个参数是标志位
70:在自己的程序里启动其他程序
PackageManager pm=getPackageManager();
Intent intent=pm.getLaunchIntentForPackage(“包名”);
startActivity(intent);
71:打开APP软件详情界面
Intent intent=new Intent();
intent.setAction(“android.setting.APPLICATION_DETAILS_SETTINGS”);
intent.setData(Uri.parse(“package:”+APP包名));
startActivity(intent);
72:获取SD卡可用空间
//获取SD卡路径
File path=Environment.getExternalStorageDirectory();
//关于硬盘的API操作
StatFs stat=new StatFs(path.getPath());
long blockSize=stat.getBlockSize();//获取每块的大小
long totalBlocks=stat.getBlockCount();//获取总块数
long availableBlocks=stat.getAvailableBlocks();//获取可用的块数
availableBlocks*blockSize;//通过计算获取剩余,获取到的都是long类型,单位是kb
73:获取可用内存空间
//获取内存路径
File path=Environment.getDataDirectory();
//关于硬盘的API操作
StatFs stat=new StatFs(path.getPath());
long blockSize=stat.getBlockSize();//获取每块的大小
long totalBlocks=stat.getBlockCount();//获取总块数
long availableBlocks=stat.getAvailableBlocks();//获取可用的块数
availableBlocks*blockSize;//通过计算获取剩余,获取到的都是long类型,单位是kb
74:获取系统中的所有进程信息
//获取进程管理者
ActivityManager activityManager=(ActivityManager) getSystemService(ACTIVITY_SERVICE);
//获取包管理者
PackageManager pm=getPackageManager();
//获取正在运行的进程信息
List<RunningAppProcessInfo> list=activityManager.getRunningAppProcesses();
for (RunningAppProcessInfo runningAppProcessInfo : list) {
//获取进程名,也就是包名
String packageName=runningAppProcessInfo.processName;
//获取进程所占有的内存空间,参数是一个int数组,
MemoryInfo[] memoryInfo=activityManager.getProcessMemoryInfo(new int[]{runningAppProcessInfo.pid});
//获取内存空间大小的值
int ramIntSize=memoryInfo[0].getTotalPss();
long ramLongSize=ramIntSize*1024;
try {
//获取Application信息
ApplicationInfo applicationInfo=pm.getApplicationInfo(packageName, 0);
//获取图标
Drawable drawable=applicationInfo.loadIcon(pm);
//获取标签
String label=applicationInfo.loadLabel(pm).toString();
} catch (NameNotFoundException e) {
e.printStackTrace();
}
}
75:在listView中的checkBox常见的一个bug
就是在利用viewHolder进行优化时,自定义的view内有checkBox控件,因为利用缓存 convertView,所以它会有可能在滑动时,checkBox显示错乱,解决方法是把checkBox的状态设置到bean类中,比如说person.setischecked,需要用到的时候再从bean类中去取相应对象值就好了,从bean类对象中去取值就不会出现错误。
比如去判断以下
if(person.ischecked){
viewHolder.checkBox.setChecked(true);
}else{
viewHolder.checkBox.setChecked(false);
}
76:android中的进程
1:前台进程:正在操作的进程,正在运行的进程,不能被杀死
2:可见进程:没有焦点,但是可见的进程,比如说有一个被dialog遮挡住的进程
3:服务进程:包含服务的进程,当内存不足时,会被杀掉,当内存充足的时候,重新启动服务进程
4:后台进程:当点击home键之后,类似被最小化的进程
5:空进程 :当退出时,保留一个空进程,为了下次能够快速的启动。
后台进程和空进程这两个是可以通过代码杀死的。
77:清理进程
ActivityManager activityManager=(ActivityManager)getSystemService(ACTIVITY_SERVICE);
activityManager.killBackgroundProcesses(packageName);//参数填写进程的包名,可以杀掉进程,有些进程杀不掉。
78:进程占用内存空间
long memory=进程名.getRamSize();//单位是kb
String size=Fomatter.formatFileSize(getApplicationContext(),memory);//根据大小转换成MB,GB。
windows操作系统内存分块,最小单位是4kb,比如创建一个文档,里面随便添加几个文字,它的最小容量就是4kb。
79:获取当前包名:getPackageName();
80:在自定义Adapter中的getView()方法,如果在方法里用了if做判断,那么必须有else才可以,否则可能出现一些奇怪的错误。
81:获取内存信息
第一种方式
ActivityManager activityManager=getSystemService(ACTIVITY_SERVICE);
//获取内存的信息,保存到memoryinfo中
MemoryInfo memoryInfo=new MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
//获取空闲的内存,返回类型是long,单位同样是kb
memoryInfo.availMem;
//获取总内存,返回类型是long
memoryInfo.totalMem;
第二种方式
它是一个文件,记录了内存的信息
路径为”/proc/meminfo”
82:获取SDK当前版本
int sdk=android.os.Build.VERSION.SDK_INT;
83:查看源码的时候
在类名的前面添加了@RemoteView的,都是可以当做桌面小控件widget的
如果没有@RemoteView注解的,那么就不能作为桌面小控件的。
86:监听锁屏,解锁的事件监听不能在清单文件中注册,可以用广播接收者通过代码注册
public class MainActivity extends Activity {
private MyBroadcastReceiver broadcastReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册广播
broadcastReceiver=new MyBroadcastReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);//注册的广播监听锁屏事件
registerReceiver(broadcastReceiver, filter);
System.out.println("onCreate");
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
//在销毁方法中取消注册广播,并且把广播接受者置为空!
if(broadcastReceiver!=null){
unregisterReceiver(broadcastReceiver);
broadcastReceiver=null;
}
}
private class MyBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TAG", "锁屏了");
//在广播接收者的onReceive方法中也可以进行Activity的跳转
Intent intent2=new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent2);
}
}
}
87:android屏幕适配的简单方法:1:px和dp之间的转换 2:屏幕较小手机一个屏幕显示不全控件,外面套一层ScrollView,但是ScrollView标签里只能有一个子控件,比如说只能有一个LinnearLayout。
px和dp之间的转化,注意在java代码中的数值都是px
/**
* 根据手机的分辨率从 dip 的单位 转成为 px(像素)
*/
public static int dipToPx(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density; //getDisplayMetrics()获取尺寸宽高,.density的意思是获取密度
return (int) (dpValue * scale + 0.5f);//加0.5f的意义是为了四舍五入,java中的浮点数字3.9四舍五入是3.0,
}
/**
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp
*/
public static int pxtToDip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
88:创建桌面快捷方式
public void addshortcut(View v){
//给桌面发送一个广播,参数的内容是系统的固定写法,寓意是创建一个桌面快捷方式
Intent intent=new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
//设置快捷方式名称
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME,"快捷方式拨打电话");
//设置快捷方式的图标
Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON,bitmap);
//设置拨打电话的操作
Intent intent2=new Intent();
intent2.setAction(Intent.ACTION_CALL);
intent2.setData(Uri.parse("tel:"+110));
//设置快捷方式执行的操作
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT,intent2);
sendBroadcast(intent);
}
//别忘记在清单文件中写权限
这是系统中的自定义权限,
89:自定义权限之后补充
90:监听用户打开的程序
ActivityManager am=(ActivityManager)getSystemService(ACTIVITY_SERVICE);
//获取正在运行的任务栈,如果任务栈运行,就代表打开过,没有被销毁
//参数3代表最多返回几个
//获取运行的任务栈,需要权限 android.permission_GET_TASKS
List<RunningTaskInfo> runningTasks=am.getRunningTasks(3);
for(RunningTaskInfo runningTaskInfo:runningTasks){
//获取任务栈,栈底的activity。栈顶的activity: runningTaskInfo.topActivity
ComponentName baseActivity=runningTaskInfo.baseActivity;
//获取这个activity的包名,也就代表了这个程序的名字
String packageName=baseActivity.getPackageName();
}
如果想随时监听运行的程序,应该写在服务service当中,在里面循环的监听用while(true){ },就可以一直循环,也可以循环间隔睡几秒监听,还有就是service是主线程的,所以耗时操作要开始子线程去执行。
如果当此时打开了一个应用后,进行自己的逻辑判断,比如说打开短信,然后我监听到之后,去打开电话的界面
if(packageName.equals("com.android.mms")){ //"com.android.mms"是短信的包名
//进行自己的逻辑操作
//因为服务和广播接收者没有任务栈,所以如果想在这里跳转Activity的话,需要添加一个任务栈。
Intent intent=new Intent(MyService.this,MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//给想要跳转到的Activity添加任务栈,否则报错。
startActivity(intent);
}
91:关于数据库同时进行读操作,和写操作的问题!!!!!!!!!!!!!!!!!
byte[] b=new byte[1024];//随便创建一个对象
public void addData(){
//在方法里同步一个对象,把MyOpenHelper设置成单例模式
synchronized(b){
SQLiteDatabase db=MyOpenHelper.getWritableDatabase();//
}
}
92:比如说在onCreate()方法中用子线程去循环执行一些操作,比如用while(true){……}来执行循环,那么想在onDestory()方法中结束子线程的话,那么就设置一个标签
public class MyActivity extends Activity{
boolean isLock=false;
onCreate(){
//....
//new Thread(){
isLock=true;
public void run(){
while(true){
//....
}
}
}
}
onDestory(){
super onDestory();
isLock=false;
}
}
93:关于activity的启动模式
1,standard:标准启动模式,会在栈顶不断累加。
2,singleTop:栈顶复用模式,如果在栈顶就复用,不在栈顶会继续累加,并且就算栈内有也不会跳转到栈里的activity
3,singleTask:栈内复用模式,如果任务栈中有此activity就会跳转到该activity,并且上方的activity会被清除。
4,singleInstance:开辟一个单独的新任务栈
94:长按Home键会有一个列表提供最近使用软件显示