#Android 基础知识点总结
----------
##1.adb - android debug bridge
-adb start-server -----开启adb服务
-adb kill-server -----停止adb服务
-adb push 本地路径 手机路径 -----将文件导入手机
-adb pull 手机路径 本地路径 -----导出
-adb logcat -----查看Log
-adb install [-r] [-s] 全路径/xxx.apk
-r 重新安装该程序,保存数据
-s 安装在SD卡内,而不是设备内部存储
-adb uninstall [-k] 全路径/xxx.apk
-k 不删除程序运行所产生的数据和缓存目录
-adb remount -----重新挂载文件系统
-adb reboot -----重启手机
-adb reboot recovery -----重启到Recovery界面
-adb reboot bootloader -----重启到bootloader界面
-adb devices -----列出所有设备名称或IP
-adb -s IP install 全路径-apk
-adb shell -----挂载到Linux空间
-netstat -ano ---查看进程 (协议 本地地址 外部地址 状态 PID)
进入Linux空间后就好玩:
ls ---查看当前路径下的文件
ls -l ---查看文件的具体信息
ps ---查看当前运行进程
netstat -ano ---查看占用端口号的进程
monkey 1000;---猴子测试 测试整个系统;1000代表数量
monkey -p 包名 数量--- 测试某个应用程序运行数量后,会不会爆
cd .. ---返回上级目录
cat xxx.xml ---查看xml文件
sqlite3 xxx.db ---进入后
.help 查看帮助
.tables 查看所有表名
.quit 退出
**可以使用sql语句操作表
##2.UI(脸蛋)
1. 四种基本布局:
#LinearLayout#---线性布局
orientation:vertical竖直, horizontal 水平
gravity:指定子布局位置
layout_gravity:指定当前控件与父布局的相对位置
layout_weight:出去已经分配的具体屏幕大小,将剩余的屏幕大小按权重分配(自己的理解)
#RelativeLayout#---相对布局
初始位置:在屏幕左上角
容易忘记:layout_above="@id/xx" 在 xx控件上
layout_below="@id/xx" 在 xx控件下
layout_toRightOf="@id/xx" 在 xx控件右边
layout_alignParentRight="true" 在父窗体右边
layout_centerInParent="true" 在父窗体正中间
#FrameLayout#---帧布局、
特点:一层层覆盖
不好玩,用来被替换的布局,当使用碎片fragment来布局UI的时候,framelayout里面存放一个fragment
#TableLayout#---表格布局
基本不用
子控件 中无法指定宽度,使用 stretchColumns="1";
合并单元格: layout_span="2";
2. 常见控件:
#TextView#
textSize
textColor #ARGB a:透明度 r:red g:green b:blue
singleLine true 单行显示
maxLines 多行显示
#Button#
四种点击事件:
第一种:通过给控件添加onclick属性,然后进到 activity中 去添加方法
添加方法时,方法的签名也是固定的.(google不推荐使用)
andorid:onclick="xxx"
public void xxx(View v){
}`
第二种:给控件添加id , 然后 在activity中拿到 控件,然后 给控件添加onclick时间的监听器
使用匿名内部类的写法:
`android:id="@+id/xxx"
xxx = (Button) findViewById(R.id.xxx);
xxx.setOnClickListener(new OnClickListener(){
public void onClick(View v){
}
});
第三种:实际上与第二种一样, 只是换成了 内部类的写法.写个类去 实现 Onclick接口
第四种:让activity类去实现 onclicklistner接口最终通过 switch...case去判断到底点击的是哪个控件.
`android:id="@+id/xxx"
xxx = (Button) findViewById(R.id.xxx);
xxx.setOnClickListener(this);
public void onClick(View v){
int id = v.getId();
switch(id){
case R.id.xxx:
break;
default:
break;
}
}
#EditText#
hint
maxLines
inputType
et_content =(EditText) findViewById(R.id.et_content);
String et_content = et_content.getText().toString.trim();
if(TextUtils.isEmpty(et_content)){
Toast.makeText("","",Toast.Length_SHORT).show();
return;
}
#imageView#
src
ImageView.setImageResource(R.drawable.xxx);
好玩的:实现图片轮播
自己见一个xml文件:
/animation-list>`
'ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
rocketAnimation = (AnimationDrawable) rocketImage.getBackground()
;
rocketAnimation.start();
#RadioGroup#
eg:
android:id="@+id/rg"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="男"
android:id="@+id/rb_male"
/>
android:layout_width="0dip"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="女"
android:id="@+id/rb_female"
/>
获取属性值:
if(rg.getCheckedRadioButtonId() == R.id.rb_male){
sex = "male";
}else{
sex = "female";
}
'
#ProgressBar#
max
progress
重要设置样式:
style="?android:attr/progressBarStyleHorizontal"
#VideoView# 播放音频视频,底层是SurfaceView 和 mediaPlayer的结合。
vv = (VideoView) findViewById(R.id.vv);
// 设置要
vv.setVideoPath("/mnt/sdcard/lala.3gp");
//mediaController --- 媒体控制器
MediaController mc = new MediaController(this);
mc.setAnchorView(vv);
vv.setMediaController(mc); // 成功的将MediaController与vv关联起来
vv.start();
#SurfaceView#
sv = (SurfaceView) findViewById(R.id.sv);
try {
mPlayer = new MediaPlayer();
mPlayer.reset();
mPlayer.setDataSource("/mnt/sdcard/lala.3gp");
mPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
sp = getSharedPreferences("config", 0);
// surfaceHodler --- 界面的持有器,持有者
sv.getHolder().addCallback(new Callback() {
//surface销毁了
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("销毁了 ");
Editor editor = sp.edit();
editor.putInt("position", mPlayer.getCurrentPosition());
editor.commit();
mPlayer.stop();
}
//surface创建了
@Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("创建了 ");
int position = sp.getInt("position", 0);
mPlayer.setDisplay(sv.getHolder()); //显示画面,必须设置
mPlayer.start();
mPlayer.seekTo(position); // 直接跳到某个位置, 从这个位置开始播放
}
//surface变化了
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
System.out.println("修改了 ");
}
});
#ScollView# 只能有一个子节点
#WebView#
webview = new WebView(this);
//设置WebView属性,能够执行Javascript脚本
webview.getSettings().setJavaScriptEnabled(true);
//加载需要显示的网页
webview.setWebViewClient(new WebViewClient());
webview.loadUrl("http://www.xxxx.com/");
//设置Web视图
setContentView(webview);
#Fragment# 碎片 类似Activity
-1. 静态添加碎片
1.自己布局一个fragment:
android:id="@+id/fm_left" //id必须写,不然会报错
android:name="com.example.fragment.LeftFragment"// 添加name属性,包名必须写,此为加载LeftFragment 类
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"/>
2.定义一个LeftFragment 继承 Fragment
public class LeftFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//false 代表 不附着在parent布局中
return inflater.inflate(R.layout.left, container,false);
}
}
3.定义一个R.layout.left布局文件
-2. 动态添加碎片
核心代码
RightFragment rightFragment = new RightFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction beginTransaction = fragmentManager.beginTransaction();
beginTransaction.replace(R.id.fl, rightFragment);
beginTransaction.commit();
3. 四种对话框(不能用Application的上下文)
-1.取消对话框
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("please "); // 下面都对话框都可以设置标题
builder.setMessage("继续撸代码吗?"); // 同上
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "lu", 0).show();
}
}); //确定按钮的点击事件
builder.setNegativeButton("No", null); //取消按钮的点击事件
builder.show();
-2.单选对话框
Builder builder = new AlertDialog.Builder(this);
final String[] items = new String[]{"male","female"};
builder.setSingleChoiceItems(items, 0, new DialogInterface.OnClickListener() {
@Override
//which 是数组的 索引,下同
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity.this, "你选的是"+items[which], 0).show();
}
});
builder.show();
-3.多选对话框
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final String[] items = new String[]{"跳楼","上吊","撸代码","滚回家"};
final boolean[] checkedItems = new boolean[]{false,false,false,false};
// fasle 代表默认不被选中
builder.setMultiChoiceItems(items, checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
Toast.makeText(MainActivity.this, "你选的是"+items[which], 0).show();
checkedItems[which] = isChecked;
}
});
builder.show();
-4.进度条对话框
final ProgressDialog progressDialog = ProgressDialog.show(MainActivity.this, "please wait", "加载loading。。。。。");
new Thread(){
public void run(){
progressDialog.setCancelable(false);//Back键不能取消掉
SystemClock.sleep(2000);
progressDialog.dismiss(); //设置 dismiss 退出
}
}.start();
***所有的控件都有的属性:visibility{visible(默认,可见),invisible(不可见占空间),gone(不可见也不占空间)}
4. 自定义控件
开源框架:SmartImageView(看源码)---- SmartImageView.setImageUrl(Url url){}
1 . 继承原生控件
2 . 重写构造方法
3 . 根据业务需求定义方法
5. ListView
-1.作用和方法:用来将数据显示到屏幕上的技术
google按照mvc的三层架构思想设计
m:model--- 模型--- 需要显示的数据
v:view ---视图---- 呈现的界面
c:controller--- 控制器--- Adapter(适配器)
1. lv.setSelection(random1); //该方法可以 ListView 定位到让指定位置(random1),就是让指定位置的条目位于当前界面第一行。非常准确。
2. lv.smoothScrollToPosition(xxx); //该方法可以让 ListView 平滑的滚动到指定位置(xxx),但是非常不准确。
3. lv1.setOnScrollListener(OnScrollListener); //给ListView 设置监听器
4. //滑动时回调的方法
// scrollState 滚动状态有三种:0 静止,1 手指滑动,2惯性滚动
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) { }
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {}
-2.BaseAdapter ---是ListAdapter的一个默认实现类
主要需要重写的2个方法:
public int getCount(){ //总共需要显示数据条数
return list.size();
}
public public View getView(int position, View convertView, ViewGroup parent) {
//三种填充View的方法,本质是一样的
//第一种
View view = View.inflate(MainActivity.this,R,layout.item_main,null);
//第二种
View view = LayoutInflater.from(MainMainActivity.this).inflate(R,layout.item_main,null);
//第三种
LayoutInflater ll = (LayoutInflater)getSystemService("LAYOUT_INFLATER_SERVICE");
View view = ll.inflate(R,layout.item_main,null);
}
-3.ArrayAdapter
listView.setAdapter(new ArrayAdapter(MainActivity.this,R.layout.item,T[] Objects));
最后一个参数也可以是集合。
-4.SimpleAdapter
待完善
-5.优化
(1)//删除之前已经显示的数据 ,然后再次重新加载进来,这样避免重复显示
if(myadapter ==null){
myadapter = new MyAdapter();
lv.setAdapter(myadapter);
}else{
//要通知适配器去更新一下数据
myadapter.notifyDataSetChanged();
}
(2)防止OOM(Out Of Memory)异常
View view;
if(convertView==null){
view = View.inflate(MainActivity.this, R.layout.item, null);
}else{
view =convertView;
}
或
if(convertView==null){
convertView = View.inflate(MainActivity.this, R.layout.item, null);
}
(3)faster(用Holder)持有器
static class ViewHolder {
TextView tv;
ImageView iv;
}
View Holder holder;
if (convertView == null) {
convertView=View.inflate(MainActivity.this,R.layout.item,null);
holder = new ViewHolder();
holder.iv = (ImageView) convertView.findViewById(R.id.iv);
holder.tv_title = (TextView) convertView.findViewById(R.id.tv);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
##3.数据存储和解析
1. 文件存储
-1.基本输入输出流文件
-2.Context提供了两个方法来打开数据文件里的文件IO流,存储路径:/data/data//files
openFileInput("xxx.txt"); //读取
openFileOutput("xxx.txt",Context.MODE_PRIVATE); //保存
//MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容
//MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件;
//后面的两种模式在Android4.2被废弃,不安全
//MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;
//MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
deleteFile("xxx.txt"); //删除
File getFilesDir():获取该应用程序的数据文件夹得绝对路径
File getCacheDir():缓存区
String[] fileList():返回该应用数据文件夹的全部文件
-3.Sdcard 存储
1、调用Environment的getExternalStorageState()方法判断手机上是否插了sd卡,且应用程序具有读写SD卡的权限,如下代码将返回true
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
2、调用Environment.getExternalStorageDirectory()方法来获取外部存储器,也就是SD卡的目录,或者使用"/mnt/sdcard/"目录
File file = new File(Environment.getExternalStorageDirectory(),filename);
3、使用IO流操作SD卡上的文件
注意点:
手机应该已插入SD卡,对于模拟器而言,可通过mksdcard命令来创建虚拟存储卡
必须在AndroidManifest.xml上配置读写SD卡的权限
2. SharedPreferences存储 --- 单例,一般不会发生并发冲突
1.创建文件: SharedPreferences sp = context.getSharedPreferences("xxx",int mode);//创建的xxx一定是xml文件,存储在/data/data//shared_prefs,参数mode 和上面一样。
2.存储数据: Editor edit = sp.edit();
edit.putXxx(String key,Xxx value);
edit.commit(); || edit.apply();
区别: 1. apply没有返回值apply方法不会提示任何失败的提示。而commit返回boolean表明修改是否提交成功
2. apply异步提交数据,commit同步。
3.读取数据: sp.getXxx(String key,XxxDefault);// 如果没有读取到,就返回第二参数。
4.删除数据: sp.remove(String key);//删除key字段
sp.clear();//清空文件
3. SQLite数据库存储
-1.创建表
db.execSQL("create table tablename(_id integer primary key autoincrement,name varchar(30),age Integer)");
-2.Insert
第一种:存在sql注入问题
db.execSQL("insert into tablename(name,age) values('Myth',2)");
第二种:通过占位符? 解决sql注入
db.execSQL("insert into tablename(name,age) values(?,?)",new Object[]{"Myth",2});
第三种:底层还是通过拼接字符串得到sql语句
ContentValues values = new ContentValues();
values.put("name","Myth");
values.put("age",2);
db.insert("tablename",columnNull,values);//第二个参数:sql表不允许插入空,所以就会用null当作该值插入表。
-3.Delete
db.execSQL("delete from tablename where _id = 2");
db.execSQL("delete from tablename where _id = ?",new Object[]{2});
db.delete("tablename","_id = ?",new String[]{String.valueOf(id)});
-4.Update
db.execSQL("update tablename set name = 'Myth' where age = 2");
db.execSQL("update tablename set name=?,age =? where _id=?",new Objecet[]{"Myth",2,2});
ContentValues values = new ContentValues();
values.put("name","Myth");
values.put("age",2);
db.update("tablename",values,"_id=?",new String[]{String.valueOf(id)});
-5.Query
Cursor cursor = db.rawQuery("select * from tablename where _id=2");
Cursor cursor = db.rawQuery("select * from tablename where _id=?",new Object[]{2});
Cursor cursor = db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit);
if(cursor.moveToFirst){
while(cursor.moveToNext){
}
}
4. SQLite实践
-1.事务操作 --- 同时处理多条数据时,保证数据安全性
db.beginTransaction();
try {
db.setTransactionSuccessful();//执行提交
} finally {
db.endTransaction();
}
-2.数据库升级操作 --- 保证版本更新成功
switch (oldVersion) {
case 1: //代表每个版本的操作 该case 是1~2的升级操作
case 2: //case 一直到最新版本
default:
}
-3.注意:getWritableDatabase()和getReadableDatabase()方法的区别:
getWriteableDatabase()方法以读写方式打开数据库一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。
getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读的方式打开数据库.
5. XML生成器:XmlSerializer和 XML解析器:XmlPullParser
-1.XmlSerializer:(字符串拼接Xm文件存在语句注入问题,so用XmlSerializer)
XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(fos,"UTF-8");
serializer.startDocument("UTF-8",true);// "
serializer.startTag(null, "smses");
for (int i = 0; i < 50; i++) {
serializer.startTag(null, "sms"); //第一个参数为命名空间
serializer.startTag(null, "body");
serializer.text("我是内容<>" + i);
serializer.endTag(null, "body");
serializer.endTag(null, "sms");
}
serializer.endTag(null, "smses");
serializer.endDocument;
fos.close;
-2.XmlPullParser:
XmlPullParser pullparser = Xml.newPullParser();
pullparser.setInput(fis,"UTF-8");
int eventType = pullparser.next();
while(eventType != XmlPullParser.END_DOCUMENT){
switch(eventType){
case XmlPullParser.START_TAG:
if ("smses".equals(tagName)) {
list = new ArrayList();
}else if ("sms".equals(tagName)) {
sms = new Sms();
}else if ("body".equals(tagName)) {
sms.setBody(parser.nextText());
}
break;
case XmlPullParser.END_TAG:
if ("sms".equals(tagName)) {
list.add(sms);
}
break;
}
eventType = pullparser.next();
}
##4.Activity
-1.自定义的Activity
-1.创建一个MyActivtiy实现Activity
public class MyActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
-2.新建一个布局文件 xxx.xml
-3.在onCreate()方法里写 上 setContentView(R.layout.xxx);
-4.最重要的一步:在清单文件中注册一个自己的Activity
android:name="com.example.MyActivity" //可以缩写.MyActivity
android:label="@string/app_name" > //标题栏的内容
-5.非必须的一步:隐藏标题栏 ---在onCreate()方法内写
requestWindowFeature(Window.FEATURE_NO_TITLE);
-2.生命周期
OnCreate() 创建界面
OnStart() 不可见---->可见 时候会调用
OnResume() 获得焦点,此时活动在栈顶,处于运行状态
OnPause() 失去焦点,不在栈顶但可见,处于暂停状态
OnStop() 可见---->不可见 时候会调用,处于停止状态
OnDestroy() 销毁
**注意:要使得Activity不可见,可以再建一个项目同时运行,将其Application的theme属性改成透明状态:
android:theme="@android:style/Theme.Translucent">
-3.活动的四种启动模式(android:launchMode="")
-1.standard:每次启动acitvity组件时, 都会新创建activity 实例,是活动默认的启动模式
-2.singleTop:如果某个activity设置单一顶部模式, 那么当发现当前的activity就在当前任务栈的顶部, 那么就不再新创建当前的activity的实例.例如:系统的短信
-3.singleTask:如果当前任务栈中已经有当前activity 的实例, 那么就将当前activity 的实例直接拿过来用, 用的时候,如果当前activity 不在栈顶,那么将在当前activity 之上的其他的activity的实例 给干掉... 然后再处于栈顶了一般情况下, 当某个activity 启动的时候, 要占用的内存比较大, 而手机上的内存又是有限的, 那么这个时候, 就推荐将这个activity的启动模式设置为单一任务栈模式.例如:系统的浏览器
-4.singleInstance:如果某个activity 的启动模式设置为单一实例模式, 那么系统会为这个activity 单独的去开辟一个任务栈,这个任务栈中,只放这个 activity的实例.这样确保了整个操作系统中,只有一个这个activity的实例了.如果某个activity在整个系统中就只需要有一个实例, 并且永远不会更改, 那么就推荐使用这种模式.例如:系统的电话
-4.使用intent在活动之间传输数据
-1.显示意图:是明显的指定要激活哪个组件 ..一般建议用在应用程序内部 .
Intent intent = new Intent();
// intent.setClass(this, SecondActivity.class);
// intent.setClassName("com.itheima.exactintent", "com.itheima.exactintent.SecondActivity");
intent.setClassName(this, "com.itheima.exactintent.SecondActivity");
startActivity(intent);
-2.隐式意图:是指不明确到底哪个组件可以响应你的意图,你只需要将意图发出去就可以了.当存在满足你的意图的组件时,
这个时候,系统就会将组件给激活起来...一般用在不同应用程序之间 激活组件 ..
Intent intent = new Intent();
//必须和Activity下的intent-filter内容匹配
intent.setAction("com.itheima.nu");
// intent.addCategory("android.intent.category.DEFAULT");
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity(intent);
****1. 每个应用中的组件是可以配置多个Intent-filter,可以配置多个隐式意图去激活这个组件
2. 如果想要激活这个组件, 只需要发送对应的隐式意图就可以了.
-3.intent中setData:接收一个Uri对象,例如:intent.setData(Uri.parse("www.baidu.com"));
与其对应,可以在标签中配置一个子标签。
属性:scheme(http),host(www.baidu.com),port(8080),path(指定端口号后面的部分),mimeType(指定可以处理的数据类型,允许使用通配符)
-4.intent携带数据,实现短信分享:
Intent intent = new Intent();
//短信有很多intent-filter,只需要其中匹配上一个即可
intent.setAction("android.intent.action.SENDTO");
intent.addCategory("android.intent.category.DEFAULT");
intent.addCategory("android.intent.category.BROWSABLE");
intent.setData(Uri.parse("smsto://xxxxx"));
intent.putExtra("sms_body", "xxxxxxxxxx");
startActivity(intent);
//Activity接收数据
Intent intent = getIntent();
String data = intent.getExtraString("sms_body");
-5.带有返回结果的intent
主Activity:
Intent intent2 = new Intent();
intent2.setClass(this, xxx.class);
startActivityForResult(intent2, 2);
//接收其他Activity回传的结果数据
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
System.out.println("结果返回到这里了 ....");
if(requestCode==1){
}else if(requestCode==2){
}
super.onActivityResult(requestCode, resultCode, data);
}
xxxActivity:
Intent data = new Intent();
data.putExtra("contact", contact);
setResult(0, data);
finish(); // 关闭该xxxActivity
-6.其他
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);重新启动Activity
intent.addAction("android.media.action.IMAGE_CAPTURE");启动相机
##5.BroadcastReceiver(买收音机,装电池,调频道)
-1.动态注册广播接收者
(1)监听手机屏幕开关
receiver = new ScreenStateReceiver();//继承BroadcastReceiver
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.SCREEN_OFF");
filter.addAction("android.intent.action.SCREEN_ON");
registerReceiver(receiver, filter);//注册 广播接收者
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if("android.intent.action.SCREEN_OFF.equals(action)){
System.out.println("发现用户屏幕关了 ");
abortBroadcast();//拦截广播
}else if("android.intent.action.SCREEN_ON".equals(action)){
System.out.println("发现用户屏幕开启 ");
}
}
(2)监听网络变化
receiver = new NetworkChangeReceiver();//继承BroadcastReceiver
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.CONNECTIVITY_CHANGE");
registerReceiver(receiver, filter);//注册 广播接收者
(3)需要手动取消注册
在onDestroy()中调用 unregisterReceiver(receiver);
-2.静态注册一个广播接收者 --- 监听开机启动
//优先级-1000~10000,优先接收广播
-3.发送无序广播
// 定义 intent , intent 设置 必要的信息就可以 了
Intent intent = new Intent();
intent.setAction("com.example.xxx");
// 发送 广播
sendBroadcast(intent);
-4.发送有序广播
// 定义 intent , intent 设置 必要的信息就可以 了
Intent intent = new Intent();
intent.setAction("com.example.xxx");
// 发送 广播
sendOrderBroadcast(intent,null);//第二个参数是一个与权限有关的字符串
##6.Server
-1.Handler异步消息处理机制(IPC 线程通信,避免发生ANR 问题,在Activity中 耗时操作 5s 产生ANR。)
-1.Message:线程间传递消息,
//获得消息对象,两种方式本质一样
Message msg = handler.obtainMessage();
Message msg = Message.obtain();
msg.sendToTarget(); //该msg需要绑定handler,从handler.obtainMessage()获取
-2.Handler:用于发送和处理消息
handler.sendMessage();
handler.sendEmptyMessage();//发送无效消息
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case SUCCESS:
Xxx data = (Xxx)msg.obj;
Toast.makeText(MainActivity.this, "成功", 0).show();
break;
case FAILURE:
Toast.makeText(MainActivity.this, "失败", 0).show();
break;
}
}
};
-3.MessageQueue :消息队列,存放将要被处理的消息,每个线程只有一个MessageQueue
-4.Looper:调用loop(),进入一个无线循环中,不断取出MessageQueue中的消息传递到handleMessage()中,每个线程也只有一个Looper对象。
-5.发送消息代码
Message msg = Message.obtain();
msg.what = SUCCESS; // what 区分发送的消息类型
msg.obj = data; // obj 携带任意消息
handler.sendMessage(msg);
-2.AsyncTask ---Android已经封装好,方便在子线程中对UI进行操作。(待更新)
-3.进程优先级分类:
-1.前台进程: 就是正在与用户进程交互的引用程序
-2.可视进程: 用户看得见的,但是摸不着的
-3.服务进程: 在服务中运行, 在后台运行着
-4.后台进程: 在后台一直运行着,不是运行在service ,是运行在activity中
-5.空进程: 引用程序已经退出了,没有activity,没有service .
-6.总结:前台进程> 可视进程> 服务进程> 后台进程> 空进程 当系统内存不够用的时候, 就会去尝试回收进程,来重新分配内存. 会按照如上优先级分类杀掉进程.
-4.自定义服务
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
}
// 必须清单文件注册
-5.开启服务的生命周期
onCreate() //服务创建时调用
onStartComment() //每次服务启动时调用,废弃了onStart()
onDestroy() //服务销毁时调用
-1.开启服务
Intent intent = new Intent();
intent.setClass(MainActivity.this,MyService.class);
startService(intent);
-2.停止服务
Intent intent = new Intent();
intent.setClass(MainActivity.this,MyService.class);
stopService(intent);
-6.绑定服务的生命周期
onCreate() //创建服务
onBind() //绑定服务
onUnbind() //解除绑定服务
onDestroy() //销毁服务
(1)绑定服务时, onStartCommand并不会执行,
(2)绑定服务,服务何时销毁呢, 在应用程序退出的时候就销毁了
(3)绑定服务, 服务不会在后台运行 ---在apps中running 中是看不到的
(4)开启服务, 服务会在后台运行--- 可以在apps中 runnning 中看到
(5)绑定服务, 服务只会创建一次, 如果再次绑定服务, 那么服务是不会重新再次创建的.
(6)如果没有绑定服务, 就直接去解绑服务, 那么会抛异常.so 需要做如下判断,避免异常
if(conn != null){
unbindService(conn);
conn = null;
mybinder = null;
}
-7.绑定服务实现流程(活动和服务间通信,进程间通信使用 IBinder)
-1.绑定服务
Intent intent = new Intent();
intent.setClass(this, MyService.class);
if(conn == null){
conn = new MyConnection();
}
bindService(intent, new MyConnection(), BIND_AUTO_CREATE);
-2.编写MyBinder 继承 Binder 实现 IService // IService 接口中是将要调用的方法
private class MyBinder extends Binder implements IService{
@Override
// 服务中对外提供的方法封装在接口中,重写接口中的方法
public void call(String name, String service) {
calle(name, service);
}
//该方法为不对外提供的方法,只对内访问
public void callee(String name, String service) {
System.out.println("呼叫前台");
}
}
-3.向Activity传回MyBinder对象
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
-4.实现MyConnection 实现 ServiceConnection接口
private class MyConnection implements ServiceConnection{
@Override
//当与服务建立联系的时候被回调
public void onServiceConnected(ComponentName name, IBinder service) {
if(mybinder == null){
mybinder = (IService) service;
// mybinder = IService.Stub.asInterface(service);
}
}
@Override
//当与服务断开联系的时候被回调
public void onServiceDisconnected(ComponentName name) {
mybinder = null;
}
}
-5.调用服务中的方法
mybinder.call("xxxx", "xxxx");
-8.不同Activity之间通信
主要编写.aidl
(1)语法与接口很类似,直接修改接口文件后缀名即可。但是.aidl文件中不能写权限修饰符
(2).aidl文件接受参数和返回值类型是8种基本数据类型,如果是引用数据类型,必须实现Parceable接口
(3)不能修改.aidl文件生成的.java类
-1 Parceable 比 Serializable 性能高
-2 Serializable 使用时会产生大量临时变量,引起频繁的GC
-3 Parceable 不能保证数据的持续性,不能使用数据保存在磁盘上
-9.混合开发服务
(1)开启服务:只能在后台运行
(2)绑定服务:只能调用服务中的方法
想在后台运行,但是同时又想 调用服务中 方法, 那么 就需要混合开启服务了.
以后,如果需要在后台运行, 并且又需要调用服务中的方法时,请严格按照 如下的顺序去 实现程序的逻辑, 否则 就容易出现问题..
混合开启:
开启服务
绑定服务
调用服务中的方法
解除绑定
停止服务
例如:QQ 在退出的时候,选择退出后, 仍然可以接受消息, 就可以使用混合开启服务的方式...
-10.Android提供一个IntentService类:是一个异步的,会自动停止的服务,可以避免ANR问题(服务在主线程中耗时操作 10s 产生ANR 问题)
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
} //处理具体的逻辑
}
// 清单文件注册
##7.ContentProvider
-1.自定义内容提供者 ---ContentProvider
public class MyContentProvider extends ContentProvider {
private static final int SUCCESS = 0;
private static UriMatcher matcher;
//匹配器 -- UriMatcher
//是固定的写法
//这里的no_match是用来指定当匹配不成功时,返回的值
static {
matcher = new UriMatcher(UriMatcher.NO_MATCH);
// com.itheima.xxx 公开的名称, table就是暗号了, SUCCESS指匹配成功后返回的结果
matcher.addURI("com.example.xxx", "table", SUCCESS);
}
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
BankOpenHelper myOpenHelper = new MyOpenHelper(getContext());
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
if (matcher.match(uri) == SUCCESS) {
return db.query("table", projection, selection, selectionArgs, null,
null, sortOrder);
}
return null;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
BankOpenHelper myOpenHelper = new MyOpenHelper(getContext());
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
// TODO Auto-generated method stub
if (matcher.match(uri) == SUCCESS) {
db.insert("table", null, values);
} else {
try {
throw new Exception("暗号错误。");
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
BankOpenHelper myOpenHelper = new MyOpenHelper(getContext());
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
if (matcher.match(uri) == SUCCESS) {
return db.delete("account", selection, selectionArgs);
}
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
BankOpenHelper myOpenHelper = new MyOpenHelper(getContext());
SQLiteDatabase db = myOpenHelper.getWritableDatabase();
if (matcher.match(uri) == SUCCESS) {
return db.update("account", values, selection, selectionArgs);
}
return 0;
}
}
##清单文件注册:
-2. 内容解析者 ---- ContentResolver (类似SQLite操作)
1 insert
ContentResolver resolver = getContentResolver();
Uri url = Uri.parse("content://com.example.xxx/table");
ContentValues values = new ContentValues();
values.put("key", "value");
resolver.insert(url, values);
2.delete
ContentResolver resolver = getContentResolver();
Uri url = Uri.parse("content://com.example.xxx/table");
resolver.delete(url, "key=?", new String[]{"value"});
3.update
ContentResolver resolver = getContentResolver();
Uri url = Uri.parse("content://com.example.xxx/table");
ContentValues values = new ContentValues();
values.put("key1", "value1");
resolver.update(url, values, "key=?", new String[]{"value"});
4.query
ContentResolver resolver = getContentResolver();
Uri url = Uri.parse("content://com.example.xxx/table");
Cursor cursor = resolver.query(url, null, "key=?", new String[]{"value"}, null);
while(cursor.moveToNext()){
}
-3.内容观察者 --- ContentObserver
(1)ContentResolver resolver = getContentResolver();
//注册一个内容观察者
//如果notifyForDescendents参数设为true,假如Uri为content://abc,那么Uri为content://abc/xyz, content://abc/xyz/foo的数据改变时也会触发该监听器,如果参数为false,那么只有content://abc的数据改变时会触发该监听器
resolver.registerContentObserver(uri, boolean notifyForDescendents, new ContentObserver(null) {
// selfChange : 数据的变化是否是来自于自己
@Override
public void onChange(boolean selfChange) {
System.out.println("数据发生变化了 ....");
}
});
(2)在不需要时,需要手动的调用
unregisterContentObserver()去取消注册。
(3)ContentObserver类介绍
构造方法 public void ContentObserver(Handler handler) {}
说明:所有 ContentObserver的派生类都需要调用该构造方法
参数: handler Handler对象。可以是主线程Handler(这时候可以更新UI了),也可以是任何Handler对象。
##8.手机多媒体
-1.通知的使用(NotificationManager)
-1.第一种
//拿到通知管理器
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification nf = new Notification(R.drawable.ic_launcher,"This is ticker Text ",System.currentTimeMillis());
// 第四个参数为延期意图(能跳转干你想干的事)
nf.setLatestEventInfo(context, "This is content title", "This is content text", null);
//显示通知,第一个参数是每一个通知的id(保证不同)
nm.notify(1,nf);
-2.第二种
//基于Notification是builer模式构建,可以链式编程创建
Notification nf = new Notification.Builder(this)
.setContentTitle("你有消息") //标题
.setContentText("你mama 喊你回家吃饭") //文本
.setSmallIcon(R.drawable.ic_launcher) //小图标
.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher)) //大图标
.build();
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.notify(1,nf);
-3.通过pending(延期意图)拨打电话
Notification nf = new Notification(R.drawable.ic_launcher, "你好一有消息", System.currentTimeMillis());
Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+5556));
// pendingIntent 可以getActivity() getService() getBroadcast()
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
nf.setLatestEventInfo(this, "ai", "huijiachifan", pendingIntent);
//权限不能少,打电话权限
-2.短信的接收和发送(SmsManger)
-1.接收短信:监听 android.provider.Telephony.SMS_RECEIVED的广播
public class MessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
//通过密钥"pdus"获取SMS pdu 数组,每一个pdu是一条短信
Object[] objects = (Object[])bundle.get("pdus");
for (Object object : objects) {
//将每一个pdu字节数组转换SmsMessage对象
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[])object);
//获取短信的发送方号码
if(smsMessage.getOriginatingAddress().equals("55666")){
//获取短信
smsMessage.getMessageBody();
}
}
}
}
//接收短信权限
-2.发送短信
SmsManager smsManager = SmsManager.getDefault();
//发送很长很长的短信需要切割短信存到集合中,才能一条一次性发出去
ArrayList divideMessage = smsManager.divideMessage("");
smsManager.sendMultipartTextMessage("phone", null, divideMessage, null, null);
//接收短信权限
-3.监听手机状态(TelephonyManager):开启录音功能(MediaRecoder)
TelephonyManager manager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
manager.listen(new myPhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE);
private class myPhoneStateListener extends PhoneStateListener{
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// TODO Auto-generated method stub
super.onCallStateChanged(state, incomingNumber);
switch (state) {
if(mRecorder != null){
stopRecording();
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
startRecording();
break;
case TelephonyManager.CALL_STATE_RINGING:
break;
default:
break;
}
}
}
MediaRecorder mRecorder;
private void startRecording() {
//下面是模版,可以录音文件的格式有:3gp,mp3。。。
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setOutputFile("/mnt/sdcard/jianting.3gp");
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mRecorder.prepare();
} catch (IOException e) {
// Log.e(LOG_TAG, "prepare() failed");
}
mRecorder.start();
}
private void stopRecording() {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}
//录音权限,读手机状态权限
-4 播放音视频(MediaPlayer)
setDataSource() // 设置要播放
seekTo()// 从指定位置播放
isPlaying()//当前是否播放
getDuration// 获取音频时长
// 开始播放Button
public void start(View v){
//播放的地址
String dizhi = et_shu.getText().toString().trim();
if(TextUtils.isEmpty(dizhi)){
Toast.makeText(this, "不能为空", Toast.LENGTH_SHORT).show();
return;
}
player = new MediaPlayer();
player.reset();
try {
player.setDataSource(dizhi);
player.prepare();
//异步准备
/*player.prepareAsync();
player.setOnPreparedListener(new OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
player.start();
}
});*/
player.start();
} catch (Exception e) {
e.printStackTrace();
}
}
// 暂停Button
public void pause(View v){
if(player!= null && player.isPlaying()){
player.pause();
return;
}
if(player!= null){
player.start();
}
}
// 停止Button
public void stop(View v){
if(player!= null){
player.stop();
player.release();
player = null;
}
}
-5.传感器的使用(SensorManager)
SensorManager sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
// Sensor.TYPE_XXX 可以获取
Sensor lightSensor = sm.getDefaultSensor(Sensor.TYPE_XXX);
MySensorEventListener myListenser = new MySensorEventListener();
// 必须注册监听事件,第二个参数 是Senor实例,第三个参数是 传感器输出信息的更新速率
有4个值:SENSOR_DELAY_UI SENSOR_DELAY_NORMAL SENSOR_DELAY_GAME SENSOR_DELAY_FASTEST 越来越快,耗电
sm.registerListener(myListenser, XXXSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
// 不使用的时候取消监听,省电
@Override
protected void onDestroy() {
super.onDestroy();
if(myListenser!=null){
sm.unregisterListener(myListenser);
}
}
private class MySensorEventListener implements SensorEventListener{
// sensor获得周围环境数据发生变化时 ,会被调用
@Override
public void onSensorChanged(SensorEvent event) {
//编写逻辑事件
}
// sensor获得周围环境数据发生变化时,精确度发生变化时会被调用
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
// 获取Sensor.TYPE_ALL
List list = sm.getSensorList(Sensor.TYPE_ALL);
System.out.println("数量 : " + list.size());
for (Sensor sensor : list) {
System.out.println(sensor.getName() +" , 类型 值 : " + sensor.getType());
}
##9.网络编程
-1.HttpURLConnection
1.get请求(拼接URL。。)
//防止乱码 URL编码
String username = URLEncoder.encode(username, "UTF-8");
String password = URLEncoder.encode(password, "UTF-8");
URL url = new URL(path+"?username="+username+"&password="+password);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
//伪装设置成windows端查看网页
//conn.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586");
//设置连接超时时间
conn.setConnectTimeout(5000);
//获取响应码
int code = conn.getResponseCode();
2.post请求
URL url = new URL(path);
String params = "?username="+URLEncoder.encode(username, "UTF-8")+"&password="+URLEncoder.encode(password, "UTF-8");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
//设置连接超时时间
conn.setConnectTimeout(5000);
//获取响应码
conn.setDoOutput(true);
conn.getOutputStream().write(params.getBytes());
int code = conn.getResponseCode();
-2.HttpClient(Apache) ---android 6.0 废弃
1.get请求
username = URLEncoder.encode(username, "UTF-8");
String path = "http://169.254.26.249:8080/qqlogin/servlet/login?username="+username+"&password="+password;
DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(path);
//执行请求,拿到响应对象
HttpResponse response = client.execute(get);
int code = response.getStatusLine().getStatusCode();
if(code == 200){
//拿到服务端响应的输入流
InputStream is = response.getEntity().getContent();
String login = StreamTool.decodeStream(is);
2.post请求
String path = "http://169.254.26.249:8080/qqlogin/servlet/login";
DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(path);
//通过一个NameValuePair集合来存放待提交的数据
List list = new ArrayList();
list.add(new BasicNameValuePair("username", username));
list.add(new BasicNameValuePair("password", password));
//防止乱码
post.setEntity(new UrlEncodedFormEntity(list , "UTF-8"));
//执行请求,拿到响应对象
HttpResponse response = client.execute(post);
int code = response.getStatusLine().getStatusCode();
if(code == 200){
InputStream is = response.getEntity().getContent();
String login = StreamTool.decodeStream(is);
-3.AsyncHttpClient---post请求
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.add("username", username);
params.add("password", password);
client.post(path, params, new AsyncHttpResponseHandler() {
@Override
//statusCode 是 响应码 headers响应头 responseBody 响应体
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
Toast.makeText(MainActivity.this,"登录结果为"+new String(responseBody), 0).show();
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Toast.makeText(MainActivity.this,"登录结果为"+new String(responseBody), 0).show();
}