一、内容观察者的运行原理
运行过程通常为A应用对内容提供者暴露的数据进行修改,而B应用负则专门责监听内容提供者数据的变化。
1、简单的小演示
首先在内容提供者写一个MyContentProvider类继承ContentProvider如下
public class MyContentProvider extends ContentProvider
继承后会自动重写6个方法(增删改查onCreat和getBytes)在B应用对应修改的方法(增删改)中发出通知,getContext().getContentResolver().notifyChange(uri, null);
通知A应用(观察者内容发生变化),A应用的
Uri uri=Uri.parse("content://qjq");
getContentResolver().query(uri, null, null, null, null);
Log.i(TAG, "查询已完成");
//监听数据的改变。参数二notifyForDescendents boolean 是否级联
getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
Log.i(TAG, "已经设置了监听");}
private class MyContentObserver extends ContentObserver{}//重写构造函数和onChange方法
二、使用内容观察者监听短信数据的改变(掌握)
短信的数据存放的位置,
源码的清单文件里面
短信的存放的位置
核心的URI
代码:
二、短信监听器
getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, new MyContentObserver(new Handler()));MyContentObserver为自己new的一个类继承ContentObserver重写onChange方法代码如下
public void onChange(boolean selfChange) {
// TODO Auto-generated method stub
super.onChange(selfChange);
//如果短信内容改变 方法会被系统自动调用
//获取最新的那条短信 (查询短信数据 需要权限 读短信的权限)
//address 号码 ,body 内容
Cursor c = getContentResolver().query(Uri.parse("content://sms"), new String[]{"address","body"}, null, null, "_id desc");
c.moveToFirst();
String address=c.getString(0);
String body=c.getString(1);
Log.i(TAG, "address:"+address+",body:"+body);
c.close(); }
三、ANR异常(即用户点击按钮5秒没响应的时候西永就会弹出窗口)了解
写一个anr按钮
在mainactivity里面写代码如下
注意以后不能再activity里面不能执行耗时的操作,如果出现耗时的操作,应该开线程
Android的程序默认是单线程即为主线程或者是UI线程。
如何开启线程
开线程有两种方式
第一种方式
new Thread(){
public void run() {
};
}.start();
第二方式
new Thread(new Runnable() {
@Override
public void run() {
}
}).start();
四、【案例】实现点击开始按钮TextView框里面显示1+...+100的结果的变化过程
1.界面一个编辑框一个按钮
2.Mainactivity代码如下如果不使用消息处理器会报错误
07-13 02:38:25.215: E/AndroidRuntime(21713): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.只有主线程才可以操作显示
Mainactivity代码如下:
public class MainActivity extends Activity {
protected static final int UPDATE_SUM = 0;//只是一种标示
private TextView tv_number;
//消息处理器
public Handler mHandler = new Handler() {
//处理消息的方法,输入handle按提示alt+/就可出来
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case UPDATE_SUM:
int sum = (Integer) msg.obj;
tv_number.setText(sum + "");
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_number = (TextView) findViewById(R.id.tv_number);
}
public void add(View v) {
new Thread() {
public void run() {
int i = 0;
int sum = 0;
while (i <= 100) {
i++;
sum += i;
//tv_number.setText(sum+""); 子线程不能操作显示发消息给主线程
/**
* 思路:
* 1 创建消息
* 2 把数据设置给消息对象
* 3 发送消息
*/
Message msg = Message.obtain();//obtain获得,即获取消息
msg.what = UPDATE_SUM;//给消息设置唯一标示
msg.obj = sum;
mHandler.sendMessage(msg);//消息发送后就会交给mHanlder里面的handleMessage()方法
SystemClock.sleep(200);
}
}
}.start();
}
五、Android下消息机制的实现。
1、网络协议
Get请求,数据写在URL的后面,1kb
Post请求数据在实体里面
六、【案例五】网络图片查看器
在Android2.3以下可以直接使用以下代码读取网络图片,2.3以上必须使用消息处理器来处理
try {//多学一招alt+shift+z(x,y是大小写互换)包裹块来try ...catch
String path = et_path.getText().toString();
// 1 包装网络路径 URL注意不是Uri
URL url=new URL(path);
// 2 打开连接 url.openConnection()
HttpURLConnection conn=(HttpURLConnection) url.openConnection();
//3 设置连接的参数 (超时时长、请求的方式)
conn.setConnectTimeout(10000);
conn.setRequestMethod("get");//小写是错的注意了改成GET
//4 判断响应码:200成功
if (conn.getResponseCode()==200){
//5 获取服务器回送的流数据
InputStream is= conn.getInputStream();
//把流处理成一张图片 再显示
Bitmap bitmap=BitmapFactory.decodeStream(is);
//设置图片显示
iv.setImageBitmap(bitmap);
}
使用消息处理器以及缓存图片全部代码如下
public class MainActivity extends Activity {
private final static String TAG = "MainActivity";
protected static final int SUCCESS_GET_IMAGE = 0;
protected static final int ERROR_GET_IMAGE = 1;
private ImageView iv;
private EditText et_path;
private Handler mHandler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case SUCCESS_GET_IMAGE:
File file = (File) msg.obj;
//设置图片的显示
iv.setImageURI(Uri.fromFile(file));
break;
case ERROR_GET_IMAGE:
Toast.makeText(getApplicationContext(), "获取图片失败", 0).show();
break;
default:
break;
}
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_path = (EditText) findViewById(R.id.et_path);
iv = (ImageView) findViewById(R.id.iv);
}
public void get(View v){
new Thread(){
public void run() {
try {
String path = et_path.getText().toString();
File file = new File(Environment.getExternalStorageDirectory(),getFileName(path));
//判断图片是否存在
if(file.exists()){
//直接使用
Log.i(TAG, "使用了缓存的图片");
Message msg = Message.obtain();
msg.what = SUCCESS_GET_IMAGE;
msg.obj = file;
mHandler.sendMessage(msg);
}else{
//1 包装网络路径 URL
URL url = new URL(path);
//2 打开连接 url.openConnection()
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//超时时长
conn.setConnectTimeout(5000);
//请求的方式
conn.setRequestMethod("GET");
//4 判断响应码:200成功
if(conn.getResponseCode() == 200){
//5 获取服务器回送的流数据
InputStream is = conn.getInputStream();
//把流处理成一张图片 再显示
Bitmap bitmap = BitmapFactory.decodeStream(is);//使用位图工厂处理为图片
//缓存在sdcard
FileOutputStream stream = new FileOutputStream(file);
//format 图片的格式
//quality 图片的质量
//stream 输出流
bitmap.compress(CompressFormat.JPEG, 100, stream);
Log.i(TAG, "下载了图片,并且缓存到了sdcard");
//发消息给主线程
Message msg = Message.obtain();
msg.what = SUCCESS_GET_IMAGE;
msg.obj = file;
mHandler.sendMessage(msg);
}else{
Message msg = Message.obtain();
msg.what = ERROR_GET_IMAGE;
mHandler.sendMessage(msg);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Message msg = Message.obtain();
msg.what = ERROR_GET_IMAGE;
mHandler.sendMessage(msg);
}
};
}.start();
}
//获取文件的名字
public String getFileName(String path){
return path.substring(path.lastIndexOf("/")+1);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
3.使用SmartImageView 开源空间获取网页图片,将loopj.android.image包复制到src目录下另外布局里面的标签要改成loopj.android.image.SmartImageView即包名加上SmartImageView
iv.setImageUrl("http://10.0.2.2:8080/tomcat.png");
七、从服务器上获取json数据
InputStream is = conn.getInputStream();//其实是一个json格式的字符串
//如何把json格式的字符串 转化为对象集合
//1 把流变为字符串
//2 把字符串变为JSONArray
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while((len = is.read(buffer)) != -1){
bos.write(buffer, 0, len);
}
String json = bos.toString();
bos.close();
is.close();
//2 把字符串变为JSONArray
JSONArray array = new JSONArray(json);
for(int i = 0;i<array.length();i++){
JSONObject jsonObject = array.getJSONObject(i);
int id = jsonObject.getInt("id");
String name = jsonObject.getString("name");
int age = jsonObject.getInt("age");
Log.i(TAG, "id:"+id+",name:"+name+",age:"+age);
Android基础3