首页 > 代码库 > Android基础3

Android基础3

 

 

一、内容观察者的运行原理

运行过程通常为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);