android 设置环境变量:
ANDROID_SDK_HOME D:\android
如果不指定该变量,那么模拟器文件将存放在默认c:\documents and settings\user
(当计算机用户名为中文时,可以通过该变量解决模拟器无法创建的问题)
android-sdk\platforms文件里面放的是 所有android版本
android常用命令(android-sdk\tools里面的命令):
列出所有创建的模拟器
android list avds
列出所有SDK可用版本
android list targets
创建模拟器命令:
android create avd -n(--name) <名字> -t(--target)
adb常用命令(android-sdk\platform-tools里面的命令):
列出所有连接手机或模拟器设备
adb devices
进入设备根目录,取得对设备的控制权(进入后可使用LINUX命令)
adb shell (ls:显示目录列表)
安装apk
单设备命令:adb install xxx.apk
多设备命令:adb install -s emulator-5554 xxx.ap (指定安装到哪个手机)
如果已经安装,提示不能再安装时,可以通过如下命令:
adb install -r xxx.apk
软件卸载
adb uninstall <包名>
向sdcard中放入文件
adb push
从手机空间或sdcard取出文件
adb pull
例:adb push the9.png /sdcard/
启动一个模拟器
emulator -avd
创建sdcard
mksdcard 256M e:\program\android\sdcard.img (创建一个236M的sdcard)
android,Activity跳转界面:
Intent itt=new Intent(FirstActivity.this,SecondActivity.class);
intent.putExtra("cid", 2); //往intent里面放数据,如果要传对象,就要把对象Serializable,后面得到对象用getSerializableExtra
//Intent itt=new Intent();
//itt.setClassName(FirstActivity.this, "com.kt1127.SecondActivity");
startActivity(itt);
android,Activity弹出类似对话框(有返回值的):
Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent, REQUESTID);
//重写onActivityResult方法 得到对话框返回的值
每一个Activity都必须在AndroidManifest.xml中使用
让一个Activity对话框风格:
在AndroidManifest.xml文件中
在Activity加入这样一句话:
android:theme="@android:style/Theme.Dialog"
在values的string.xml里定义一个字符串数组:
并在Activity里面调用该数组:
Resources res=getResources();
String[] strs=res.getStringArray(R.array.strArr);//这里用的是R.array.了, 而不是R.string.
在AndroidManifest.xml设置权限:
实现打电话(下面的方法需要在AndroidManifest.xml添加权限):
Intent intent=new Intent();
intent.setAction(Intent.ACTION_CALL); //设置行为--打电话
Uri uri=Uri.parse("tel:"+u.getPhone()); //uri 必须为 tel:********
intent.setData(uri);
startActivity(intent);
在TextView中设置android:id="@android:id/empty", 表示界面什么也没有时显示该TextView,(这是在使用 系统的ListView 的前提下的)
弹出一个小文本信息:
Toast.makeText(TestLayoutActivity.this, str, 1000).show(); //显示1秒 ,str--要显示的字符串
android:layout_gravity="center_horizontal" //表示 自己在布局 居中
android:gravity="center" //表示里面的内容 居中
发送短信的两种方式:
1. 我们程序直接发送(需要在AndroidManifest.xml添加权限):
SmsManager smsManager=SmsManager.getDefault(); //这里导包,要的是 android.telephony.SmsManager的,另外一个过时了
String tel=telEt.getText().toString();
String content=smsEt.getText().toString();
ArrayList
for(String s:contents){
smsManager.sendTextMessage(tel, null, s, null, null);
Toast.makeText(SmsActivity.this, "发送成功!", 1000).show();
}
2. 利用第三方(也就是系统软件),会跳转界面再点击发送(不需要添加权限):
Intent intent=new Intent();
intent.setAction(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("smsto:"+tel));
intent.putExtra("sms_body", content);
startActivity(intent);
布局中FrameLayout是从左上角开始显示,不能指定位置,但是允许多个控件显示(是直接覆盖);
AbsoluteLayout 现在一般不用了;
RelativeLayout :
android:layout_toRightOf="@id/tel_label" //表示在tel_label的右边,用 id 来做相对布局
android:layout_below="@id/content" //表示在content的下面
删除ListView的item:
users.remove(position); //移除adapter里面的数据
adapter.notifyDataSetChanged();
ListView:
ListView成为勾选列表:
/*
**R.layout.checkitem这个布局里面用CheckedTextView,
**并且要有属性android:checkMark="?android:attr/listChoiceIndicatorSingle" //设置勾选中了, 是圆点
**
*/
adapter = new ArrayAdapter
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
ListView的优化:
1. 如果自定义适配器,那么在getView方法中要考虑方法传进来的参数contentView是否为null,如果为null就创建contentView并返回,如果不为null则直接使用。在这个方法中尽可能少创建view。
2. 给contentView设置tag(setTag()),传入一个viewHolder对象,用于缓存要显示的数据,可以达到图像数据异步加载的效果。
//实例:
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = View.inflate(MainActivity.this, R.layout.item, null);
holder = new ViewHolder();
holder.imgV = (ImageView) convertView.findViewById(R.id.img);
holder.textV = (TextView) convertView.findViewById(R.id.text);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.imgV.setImageResource((Integer) data.get(position).get("img"));
holder.textV.setText((String) data.get(position).get("text"));
return convertView;
}
class ViewHolder {
ImageView imgV;
TextView textV;
}
3. 如果listview需要显示的item很多,就要考虑分页加载。比如一共要显示100条或者更多的时候,我们可以考虑先加载20条,等用户拉到列表底部的时候再去加载接下来的20条。
SimpleAdapter:
/*
**this --- context
**data --- List里面必须放 Map
**R.layout.simple --- 布局,就是设置item的布局
**new String[]{"name","tel"} --- String[],对应Map里面的Keys
**new int[]{R.id.name,R.id.tel} --- int[],对应上面布局的View的id ,
*/
SimpleAdapter spa=new SimpleAdapter(this,data,R.layout.simple,new String[]{"name","tel"},new int[]{R.id.name,R.id.tel});
//上面的最后一个参数 对应的View只能是TextView(因为系统内部实现针对的是它),否则:
adapter.setViewBinder(new ViewBinder(){//使ImageView的图片成功显示
@Override
public boolean setViewValue(View view, Object data,
String textRepresentation) {
if(view instanceof ImageView && data instanceof Bitmap){
ImageView imgV=(ImageView) view;
imgV.setImageBitmap((Bitmap)data);
return true;
}
return false;
}
});
将布局xml文件变成view对象(打气筒):
//创建打气筒
1. LayoutInflater inflater = getLayoutInflater(); //调用Activity的getLayoutInflater()
2. LayoutInflater localinflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);//
3. LayoutInflater inflater = LayoutInflater.from(context);
public View inflate (int resource, ViewGroup root)
注意:如果root被提供的话,在把新生成的View连接到root后,返回root.否者返回的是新生成的View
public View inflate (int resource, ViewGroup root, boolean attachToRoot)
注意:如果root被提供而且attachToRoot为TRUE的话,在把新生成的View连接到root,返回root。如果root被提供但attachToRoot为FALSE的话,root只是把它的LayoutParams参数给新生成的View用,不会把新生成的View连接到root,当然返回的是新生成的View。
4. View view = View.inflate(context, resource, root); //直接用View的方法
Activity的对话框(以id来识别):
onCreateDialog(id) //只为初始化(只调用一次),这时要重写
onPrepareDialog(dialog,id) //要show时,就会调用
showDialog(id) //show哪个
删除当前进程(也就是退出当前程序):
android.os.Process.killProcess(android.os.Process.myPid());
退出Activity:
Activity.finish();
System.exit(0);
onPrepareOptionsMenu(Menu menu)是在手机点击menu键时调用的
ContextMenu类似右键快捷键:
registerForContextMenu(mB); //参数为View,长按弹出菜单 (在onLongClick()方法中返回值为false时)
Activity.onCreateContextMenu() //跟上面搭配时,一般要重写
在状态栏发送通知:
NotificationManager nm=(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); //申请服务
Notification ntf=new Notification(R.drawable.ic_launcher, "来了一个通知...", System.currentTimeMillis());
Intent intent=new Intent(MainActivity.this,TurnActivity.class); //点击通知后往哪跳转
PendingIntent pi=PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
ntf.setLatestEventInfo(getApplicationContext(), "测试" , "这是一个通知,测试中...", pi); //定义通知的消息
nm.notify(1, ntf);
通知的其他特效:
1.使用默认声音
notification.defaults |= Notification.DEFAULT_SOUND;
2.指定一个文件,作为声音
notification.sound = Uri.parse("file:///mnt/sdcard/aa.mp3");
3.当点击notification window时,清除notification信息
notification.flags |= Notification.FLAG_AUTO_CANCEL;
4.不希望被从notification window清除
notification.flags 加上 Notification.FLAG_NO_CLEAR;
5.手机震动效果
需要声明一个权限:
1)使用系统默认的震动效果
notification.defaults |= Notification.DEFAULT_VIBRATE;
2)使用自定义的震动效果
long[] vibrate = {0,100,200,300};
notification.vibrate = vibrate; //添加震动,参数(毫秒)第一个是开始时间,后一个是结束时间,以此反复
查看联系人列表
Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse("content://com.android.contacts/contacts"));
//Intent intent = new Intent(Intent.ACTION_VIEW,ContactsContract.Contacts.CONTENT_URI);
startActivity(intent);
查看某一个联系人
Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse("content://com.android.contacts/contacts/190"));
//Intent intent = new Intent(Intent.ACTION_VIEW,ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, 190));
startActivity(intent);
Intent intent = new Intent(Intent.ACTION_EDIT,Uri.parse("content://com.android.contacts/contacts/190"));
//Intent intent = new Intent(Intent.ACTION_EDIT,ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, 190));
startActivity(intent);
查看并得到联系人信息(重写onActivityResult方法):
protected void onActivityResult(int requestCode, int resultCorede, Intent data) {
if(requestCode==FOR_CONTACT_ID){
if(resultCorede==RESULT_OK){
Uri uri=data.getData();
Cursor c1=getContentResolver().query(uri, null, null, null, null);
if(c1.moveToFirst()){
String id=c1.getString(c1.getColumnIndex(ContactsContract.Contacts._ID)); //得到返回的联系人ID
String name=c1.getString(c1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); //得到返回的联系人名字
nameEt.setText(name);
//这里需要注意的是,下面要得到的电话号码跟之前的不是一个表,而且要得到电话 需要添加权限:READ_CONTACTS
Cursor c2=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"="+id, null, null);
if(c2.moveToFirst()){
String phone=c2.getString(c2.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneEt.setText(phone);
}
}
}
}
}
Intent定义的内容
在Android参考文档中,对Intent的定义是执行某操作的一个抽象描述。
(1)Action,也就是要执行的动作
(2)Data,也就是执行动作要操作的数据
(3)type(数据类型)
(4)category(类别)
(5)component(组件)
(6)extras(附加信息)
Intent--type(数据类型),显式指定Intent的数据类型(MIME)。一般Intent的数据类型能够根据数据本身进行判定,
但是通过设置这个属性,可以强制采用显式指定的类型而不再进行推导。
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/a.pdf"),"application/pdf");
startActivity(intent);
Intent--component(组件),指定Intent的的目标组件的类名称。
如果 component这个属性有指定的话,将直接使用它指定的组件,而不再执行上述查找过程。
Intent intent = new Intent();
ComponentName component = new ComponentName(getApplicationContext(), SecondActivity.class);
intent.setComponent(component);
startActivity(intent);
直接Intent:指定了component属性的Intent;(调用setComponent(ComponentName)或者setClassName(Context, Class)来指定)。
隐式Intent(Explicit Intents)和Intent Filter(Implicit Intents)进行比较时的三要素是Intent的动作、数据以及类别;
(隐式Intent:指的是在Intent intent = new Intent()时的java代码,而Intent filter是在androidManifest.xml文件中定义的。)
隐式启动:
Intent intent = new Intent();
intent.setAction("com.anjoyo.myfirsttest");
startActivity(intent);
intent-filter配置:
android系统的四大组件:
Activity、Service、BroadcastReceiver、ContentProvider
intent-filter:
一条
元素指定了希望接受的Intent请求的数据URI和数据类型,URI被分成三部分来进行匹配:scheme,authority和path。
如:百度一下,你就知道//http就是schema
tel:1390023232 //tel就是schema
file:///mnt/sdcard/Picture/xx.jpg //file就是schema
如何获取 res 中的资源:
主要类:Resources(android.content.res包)
Resources r = this.getContext().getResources();
主要方法:
getXXXX()
例如:
int getColor(int id)
Drawable getDrawable(int id)
String getString(int id) 直接获取res中存放的资源
String[] getStringArray(int id)//获取一个String数组
InputStream openRawResource(int id) //获取资源的数据流,读取资源数据
void parseBundleExtras(XmlResourceParser parser, Bundle outBundle)从XML文件中获取数据
定义了TransitionDrawable的使用:
可以在layout布局中,设置ImageView的background属性:
android:background="@drawable/mydrawable"
在Activity代码中
Drawable d = getResources().getDrawable(R.drawable.mydrawable);
TransitionDrawable td = (TransitionDrawable)d;
td.startTransition(2000);//实现两张图片间切换
如何自定义一个View
step1.
写一个类,继承View,或者你要扩展那个控件类
step2.提供构造方法:
有三个:
public View(Context context) {}
//构造函数往往用在new xxxView()中后边两种构造方法,是由系统调用。它自动把xml属性赋值给AttributeSet
public View(Context context, AttributeSet attrs) {}
public View(Context context, AttributeSet attrs, int defStyle){}
step3.
方式A.在layout的xml文件中,要写全包名,例如:
方式B.在java代码中直接new,例如:CustomView cv = new CustomView(this);
在自定义View里,ShapeDrawable使用,如画一个椭圆
protected void onDraw(Canvas canvas) {//重写方法
ShapeDrawable sd = new ShapeDrawable(new OvalShape());
Paint paint = sd.getPaint();
paint.setColor();
sd.setBounds(10, 10, 300+10, 100+10);
sd.draw(canvas);
}
NinePatchDrawable:
NinePatchDrawable 绘画的是一个可以伸缩的位图图像,
Android会自动调整大小来容纳显示的内容。
NinePatchDrawable是一个标准的PNG图像,它包括额外的1个像素的边界,你必须保存它后缀为.9.png,并且保持到工程的res/drawable目录中。
Android提供绘制工具,在sdk/tools/draw9patch.bat
Bitmap和BitmapFactory:
要获取位图信息,比如位图大小、像素、density、透明度、颜色格式等,获取得到Bitmap就迎刃而解了。
方式1: 建立空的Bitmap
Bitmap vBitmap=Bitmap.createBitmap(vWidth,vHeight,
方式2: 取得Resource 的Bitmap
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
方式3: 取得图档的Bitmap
Bitmap vBitmap=BitmapFactory.decodeStream(vContentResolver.openInputStream(uri));
这里只是辅助说明以下2点:
1. 在Bitmap中对RGB颜色格式使用Bitmap.Config定义,仅包括ALPHA_8、ARGB_4444、ARGB_8888、RGB_565,缺少了一些其他的,比如说RGB_555,在开发中可能需要注意这个小问题;
2. Bitmap还提供了compress()接口来压缩图片,不过Android SDK只支持PNG、JPG格式的压缩;其他格式的需要Android开发人员自己补充了
在Android中,把Canvas当做画布,可以在画布上绘制我们想要的任何东西。
方法:
clipXXX 裁剪,通过Path, Rect ,Region 的不同组合,几乎可以支持任意形状的裁剪区域。如: ClipPath, ClipRect,ClipRegion
drawXXX 绘制,可绘制图片,图形等。如:drawBtimap、drawLine
save() 用来保存canvas状态的。可以得到一个返回值,是用来确定保存时间的。
使用restoreToCount()方法时可以把此值当参数传递,可以还原到指定的保存时间。
restore() 用来恢复canvas状态的,还原到上一次save()时的状态。
translate(float dx,float dy); 移动canvas和它的原点到不同的位置上。默认原点坐标为(0,0)
参数:dx,左右偏移量(正数是向右移动)
dy,上下偏移量(正数是向下移动)
rotate(float degrees); 以原点为中心对canvas旋转。默认原点坐标为(0,0)参数:degrees 旋转弧度
scale(float sx, float sy); 增减图形在canvas中的像素数目,对形状,位图进行缩小或者放大。
参数:sx,横轴缩放大小
sy,数轴缩放大小
scale(float sx, float sy, float px, float py); //px,设置原点的位置(与rotate中的px正好相反,正数是向左移动)
py,设置原点的位置(与rotate中的py正好相反,正数是向上移动)
Paint类包含样式和颜色有关如何绘制几何形状,文本和位图的信息。
Canvas是一块画布,具体的文本和位图如何显示,这就是在Paint类中定义了。
Paint的功能:
字体、大小(TextSize)、颜色 (TextColor)、对齐方式(TextAlign)、粗体(Bold)、斜体(Italic)、下划线(Underline)等
字体类型:Typeface类--(BOLD,BOLD_ITALIC,ITALIC,NORMAL)
使用Paint显示String
Paint p = new Paint();
String familyName = 宋体;
Typeface font = Typeface.create(familyName,Typeface.BOLD);
p.setColor();
p.setTypeface(font);
p.setTextSize(22);
canvas.drawText(mstrTitle,0,100,p);
对于Android游戏开发或者说2D绘图中来讲Path 路径可以用强大这个词来形容。在Photoshop中我们可能还记得使用钢笔工具绘制路径的方法。
Path路径类在位于 android.graphics.Path中,Path的构造方法比较简单,如下
Path cwj=new Path(); //构造方法
下面我们画一个封闭的原型路径,我们使用Path类的addCircle方法
cwj.addCircle(10,10,50,Direction.CW); //参数一为x轴水平位置,参数二为y轴垂直位置,第三个参数为圆形的半径,最后是绘制的方向,
//CW为顺时针方向,而CCW是逆时针方向 (Clock Wise)(Counter Close Wise)
特效-Matrix,都是针对在Canvas
Matrix的操作,总共分为translate(平移),rotate(旋转),scale(缩放)和skew(倾斜)四种
Matrix 提供set, post和pre三种操作方式,除了translate,其他三种操作都可以指定中心点。
set是直接设置Matrix的值,每次set一次,整个Matrix的数组都会变掉。
post是后乘,当前的矩阵乘以参数给出的矩阵。可以连续多次使用post,来完成所需的整个变换。
例如,要将一个图片旋转30度,然后平移到(100,100)的地方,那么可以这样做:
Matrix m = new Matrix();
m.postRotate(30);
m.postTranslate(100, 100);
pre是前乘,参数给出的矩阵乘以当前的矩阵。所以操作是在当前矩阵的最前面发生的。
例如上面的例子,如果用pre的话,就要这样:
Matrix m = new Matrix();
m.setTranslate(100, 100);
m.preRotate(30);
旋转、缩放和倾斜都可以围绕一个中心点来进行,如果不指定,默认情况下,是围绕(0,0)点来进行。
特效-Shader,都是针对在Canvas
Android中提供了Shader类专门用来渲染图像以及一些几何图形
Shader类的使用,都需要先构建Shader对象,然后通过Paint的setShader方法设置渲染对象,然后设置渲染对象,然后再绘制时使用这个Paint对象即可。
Shader shader = new BitmapShader(…..)
Shader shader = new LinearGradient(…..)
Paint paint = new Paint();
Paint.setShader(shader);
Shader下面包括几个直接子类,分别是:
BitmapShader 主要用来渲染图像,
LinearGradient 用来进行线性渲染,
RadialGradient 用来进行环形渲染,
SweepGradient 用来进行梯度渲染,
ComposeShader 则是一个 混合渲染,可以和其它几个子类组合起来使用。
Tween动画:
Android平台提供了两类动画,分别是Tween动画和Frame动画。
Tween通过场景里的对象不断的进行图片的变换,比如平移、渐变、缩放、旋转等来产生动画效果;
Frame动画叫做顺序播放实现做好的图像和电影类似。另外加上gif动画,因为如果直接使用Bitmap或其他方法直接调用gif图片资源的话,显示的是静态的,如果要做成动态的,就需要一些其他的方法来实现。
Tween动画分类:
Alpha:渐变透明度动画
Scale:渐变尺寸伸缩动画
Translate:画面转换位置移动动画
Rotate:画面转移旋转动画
有两种方式(java,xml):
java:
AlphaAnimation anim = new AlphaAnimation(0,1);
anim.setDuration(3000);
imageView.startAnimation(anim);
xml:
res/anim(必须在这里,文件夹名称必须这样)
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="2000"
>
Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.alpha);
imageView.startAnimation(animation);
ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, floatXValue, int pivotYType, float pivotYValue)
功能:创建一个渐变尺寸伸缩动画
参数:fromX,toX分别是起始和结束时x坐标上的伸缩尺寸。
fromY,toY分别是起始和结束时ye坐标上的伸缩尺寸。
pivotXValue,pivotYValue分别为伸缩动画相对于x,y坐标开始的位置,
pivotXType,pivotYType分别为x,y的伸缩模式。
Animation anim = new ScaleAnimation(0, 1, 0, 1); //相对于(0,0)位置
Animation anim = new ScaleAnimation(1.0f,0.0f,1.0f,0.0f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f); //相对与自身中心位置
anim.setFillAfter(true);是否保持动画后的状态,true表示保持
*****重点理解
Animation.RELATIVE_TO_SELF //表示相对自身 0.5f 表示中心
Animation.ABSOLUTE //表示一个固定的点 比如(300,300),表示在x轴为300px,y轴为300px的点为相对点
Animation.REALTIVE_TO_PARENT //表示相对父控件 0.5f表示父控件的一半
.xml
以指定位置(300,300)为中心点:
android:pivotX="300"
android:pivotY="300"
通过%来表示相对于自身什么位置:
android:pivotX="50%"
android:pivotY="50%"
通过p表示相对于父控件什么位置:
android:pivotX="50%p"
android:pivotY="100%p"
指定速度变化过程:
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
动画组合Set:
xml:
监听Animation状态的事件AnimationListener
启动Animation两种方式
1. imageView.startAnimation(anim);
2. imageView.setAnimation(anim);
anim.start();
Frame动画:
方式一,java的实现:
private int[] images = {R.drawable.pic1,R.drawable.pic2,R.drawable.pic3,R.drawable.pic4};
final AnimationDrawable animDrawable = new AnimationDrawable();
for(int i=0;i<4;i++){
animDrawable.addFrame(getResources().getDrawable(images[i]), 80);
//以下方式要求是文件命名要遵循一定规律,方便递归查找。
//int resId = getResources().getIdentifier("pic"+(i+1), "drawable", "com.anjoyo.animation2");
//animDrawable.addFrame(getResources().getDrawable(resId), 500);
}
image.setBackgroundDrawable(animDrawable);
animDrawable.setOneShot(false); //是否只动画一次
animDrawable.start();
方式二,xml的实现:
定义:(必须在res/drawable)
android:oneshot="false">
使用1:
AnimationDrawable d = (AnimationDrawable) getResources().getDrawable(R.anim.frame);
image.setBackgroundDrawable(d);
使用2,在xml中使用:
android:background="@drawable/frame"
/>
AnimationDrawable d = (AnimationDrawable) image.getBackground();
d.start();
GridView:网格,跟ListView差不多,也是用Adapter添加数据。
android:id="@+id/gv"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="60dp"
android:numColumns="3"
android:verticalSpacing="10dp"
android:horizontalSpacing="15dp"
android:stretchMode="columnWidth"
android:gravity="center"
/>
Service:Android系统的后台服务组件(需要在AnroidManifest.xml文件配置service),适用于开发无界面、长时间运行的应用功能。
没有用户界面,比Activity 的优先级高,不会轻易被Android系统终止;
即使Service被系统终止,在系统资源恢复后Service也将自动恢复运行状态;
用于进程间通信(Inter Process Communication,IPC),解决两个不同Android应用程序进程之间的调用和通讯问题
启动service://隐式启动service,类似Activity的隐式启动
Intent intent = new Intent(getApplicationContext(),MyFirstService.class);
startService(intent);
停止service
Intent intent = new Intent(getApplicationContext(),MyFirstService.class);
stopService(intent);
MediaRecorder:录音:
在recorder.stop()后,要释放资源recorder.release();
MediaRecorder recorder = new MediaRecorder();
//声音源为话筒
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置输出格式
recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
//音频编码
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
recorder.setOutputFile("/mnt/sdcard/record_"+(new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()))+".amr");
//开始录音
recorder.prepare();
recorder.start();
权限:
注意:
setAudioEncoder()必须在setOutputFormat()之后运行。
File sdcardFile = Environment.getExternalStorageDirectory();//得到sdcard根文件夹,因为有的手机sdcard路径就是/sdcard/
TelephonyManager监听电话状态:(要用到录音功能)
step1.获取TelephonyManager对象
TelephonyManager teleMan = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
teleMan.listen(new MyPhoneStateListener(this), PhoneStateListener.LISTEN_CALL_STATE);
step2.写那个类MyPhoneStateListner,实现PhoneStateListener接口
public class MyPhoneStateListener extends PhoneStateListener {
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
try {
recorder.prepare();
recorder.start();
} catch (Exception e) {
e.printStackTrace();
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if(isRecoder){
recorder.stop();
mr.release();
}
break;
}
}
}
step3.manifest.xml文件中声明权限
bind service:绑定服务:
通过服务链接(ServiceConnection)或直接获取Service中状态和数据信息服务链接能够获取Service的对象,因此绑定Service的组件可以调用Service中的实现的函数;
使用Service的组件通过Context.bindService()建立服务链接,通过Context.unbindService()停止服务链接;
同一个Service可以绑定多个ServiceConnection(服务链接),这样可以同时为多个不同的组件提供服务;
如何绑定:
Intent intent = new Intent(context,MyService.class);
ServiceConnection conn = new ServiceConnection(){
public void onServiceDisconnected(ComponentName name) {
Log.i("Service", "onServiceDisconnected===");
}
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("Service", "onServiceConnected===");
}
}
/*
**第3个参数Context.BIND_AUTO_CREATE表明只要绑定存在,就自动建立
**Service;同时也告知Android系统,这个Service的重要程度与调用者相同,
**除非考虑终止调用者,否则不要关闭这个Service
*/
context.bindService(intent,conn,Context.BIND_AUTO_CREATE);
解除绑定:
context.unBindService(conn);
注意:
1. unbindService(conn)//不可以多次调用
2. 如果onUnbind()函数的返回true,则表示在调用者绑定新服务时,onRebind()函数将被调用
3. 取消绑定仅需要使用unbindService()方法,并将ServiceConnnection传递给unbindService()方法
4. 关于ServiceConnection的两个方法:
当连接上service时,会调用onServiceConnected方法
当连接上后,service被后台停止,那么此时会调用onServiceDisconnected方法
5. unbindService()方法成功后,系统并不会调用onServiceDisconnected(),因为onServiceDisconnected()仅在意外断开绑定时才被调用
绑定Service的生命周期:
绑定:如果service没被创建,那么调用一次onCreate(),然后调用onBind(),多次绑定时,不会多次调用onBind()
解除绑定:调用onUnbind(),然后onDestory().不可以多次调用unbindService()方法解除绑定。
Service的启动方式和绑定方式的结合:
这两种使用方法并不是完全独立的,在某些情况下可以混合使用;
以MP3播放器为例:
在后台的工作的Service通过Context.startService()启动某个特定音乐播放,
但在播放过程中如果用户需要暂停音乐播放,则需要通过Context.bindService()获取服务链接和Service对象,
进而通过调用Service的对象中的函数,暂停音乐播放过程,并保存相关信息。
在这种情况下,如果调用Context.stopService()并不能够停止Service,需要在所有的服务链接关闭后,Service才能够真正的停止
生命周期:(绑定了就必须要先解绑后才能停止)
第一次点击:不管是startService还是bindService,如果service还未存在,那么会调用onCreate,之后如果是startService那么调用onStartCommand(),如果是bindService那么会调用onBind()
之后:如果再调startService(),那么会调用onStartCommand();如果再调用bindService那么如果第一次点击是bindService,那么就不会调用onBind(),否则什么方法都不会被调用。
当bindService后,不能stopService,需要通过unBindService()来解除绑定。
只是startService()后,不可以通过unBindService()来销毁service
注意:
service和Activity处于同一个线程。