android 编程原则:
//必须遵守单线程模型的原则:
//1. 不要阻塞UI线程
// 当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,
// 如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。
// 2. 确保只在UI线程中访问Android UI工具包
只有主线程才能操纵界面上的组件。
当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。
比如说从网上获取一个网页,在一个TextView中将其源代码显示出来,这种涉及到网络操作的程序一般都是需要开一个线程完成网络访问,但是在获得页面源码后,是不能直接在网络操作线程中调用TextView.setText()的.因为其他线程中是不能直接访问主UI线程成员 。
android提供了几种在其他线程中访问UI线程的方法。
Activity.runOnUiThread( Runnable )
View.post( Runnable )
例如在按钮点击事件中,new Thread(new Runnable ()
{
public void run()
{
mimageview.post(new Runnable() //这里就是异步操作。
{
public void run()
{
mimageview.setImageDrawable();//这里更新UI上的组件。
}
})
}
})
View.postDelayed( Runnable, long )
Hanlder
在开发Android移动客户端的时候往往要使用多线程来进行操作,我们通常会将耗时的操作放在单独的线程执行,避免其占用主线程而给用户带来不好的用户体验。但是在子线程中无法去操作主线程(UI 线程),在子线程中操作UI线程会出现错误。因此android提供了一个类Handler来在子线程中来更新UI线程,用发消息的机制更新UI界面,呈现给用户。这样就解决了子线程更新UI的问题。但是费时的任务操作总会启动一些匿名的子线程,太多的子线程给系统带来巨大的负担,随之带来一些性能问题。因此android提供了一个工具类AsyncTask,顾名思义异步执行任务
android的类AsyncTask对线程间通讯进行了包装,提供了简易的编程方式来使后台线程和UI线程进行通讯:后台线程执行异步任务,并把操作结果通知UI线程
//适用于简单的异步处理,不需要借助线程和Handler即可实现 ,asynctask带了三个泛型参数:Params, Progress, Result
Params 启动任务执行的输入参数,比如HTTP请求的URL。
* Progress 后台任务执行的百分比。
* Result 后台执行任务最终返回的结果,比如String,Integer等。
class AsyncSetApprove extends AsyncTask<String, Integer, String> {
AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,开发者需要实现这些方法。
* 1) 继承AsyncTask
* 2) 实现AsyncTask中定义的下面一个或几个方法
* onPreExecute(), 该方法将在执行实际的后台操作前被UI 线程调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条,或者一些控件的实例化,这个方法可以不用实现。
* doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台处理工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。
* onProgressUpdate(Progress...),在publishProgress方法被调用后,UI 线程将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
* onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI 线程调用,后台的计算结果将通过该方法传递到UI 线程,并且在界面上展示给用户.
* onCancelled(),在用户取消线程操作的时候调用。在主线程中调用onCancelled()的时候调用。
为了正确的使用AsyncTask类,以下是几条必须遵守的准则:
1) Task的实例必须在UI 线程中创建
2) execute方法必须在UI 线程中调用
3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法,需要在UI线程中实例化这个task来调用。
4) 该task只能被执行一次,否则多次调用时将会出现异常
doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。
doInBackground 一般包含的操作有I/O,网络通讯等:一下是实例:
@Override
protected String doInBackground(String... params) {
try{
HttpClient client =new DefaultHttpClient();
// params[0]代表连接的url
HttpGet get =new HttpGet(params[0]);
HttpResponse response = client.execute(get);
HttpEntity entity = response.getEntity();
long length= entity.getContentLength();
InputStream is = entity.getContent();
String s =null;
if(is!= null) {
ByteArrayOutputStream baos =new ByteArrayOutputStream();
byte[] buf= newbyte[128];
int ch= -1;
int count= 0;
while((ch= is.read(buf))!= -1) {
baos.write(buf, 0, ch);
count += ch;
if(length> 0) {
// 如果知道响应的长度,调用publishProgress()更新进度
publishProgress((int) ((count/ (float) length)* 100));
}
// 让线程休眠100ms
Thread.sleep(100);
}
s =new String(baos.toByteArray()); }
// 返回结果
return s;
} catch(Exception e) {
e.printStackTrace();
}
returnnull;
}
I/O操作:
class AsyncSetApprove extends AsyncTask<String, Integer, String> {
@Override
protected String doInBackground(String... params) {//...可变参数
if (!isInit) {
File path = getFilesDir();
String[] strings = getResources().getStringArray(R.array.bookid);// 获取assets目录下的文件列表
for (int i = 0; i < strings.length; i++) {
try {
FileOutputStream out = new FileOutputStream(path + "/" + strings[i]);
BufferedInputStream bufferedIn = new BufferedInputStream(getResources().openRawResource(R.raw.book0 + i));
BufferedOutputStream bufferedOut = new BufferedOutputStream(out);
byte[] data = new byte[2048];
int length = 0;
while ((length = bufferedIn.read(data)) != -1) {
bufferedOut.write(data, 0, length);
}
// 将缓冲区中的数据全部写出
bufferedOut.flush();
// 关闭流
bufferedIn.close();
bufferedOut.close();
sp.edit().putBoolean("isInit", true).commit();
} catch (Exception e) {
e.printStackTrace();
}
}
ArrayList<HashMap<String, String>> insertList = new ArrayList<HashMap<String, String>>();
File[] f1 = path.listFiles();
int len = f1.length;
for (int i = 0; i < len; i++) {
if (f1[i].isFile()) {
if (f1[i].toString().contains(".txt")) {
HashMap<String, String> insertMap = new HashMap<String, String>();
insertMap.put("parent", f1[i].getParent());
insertMap.put("path", f1[i].toString());
insertList.add(insertMap);
}
}
}
SQLiteDatabase db = localbook.getWritableDatabase();
db.delete("localbook", "type='" + 2 + "'", null);
for (int i = 0; i < insertList.size(); i++) {
try {
if (insertList.get(i) != null) {
String s = insertList.get(i).get("parent");
String s1 = insertList.get(i).get("path");
String sql1 = "insert into " + "localbook" + " (parent,path" + ", type" + ",now,ready) values('" + s + "','" + s1 + "',2,0,null" + ");";
db.execSQL(sql1);
}
} catch (SQLException e) {
Log.e(TAG, "setApprove SQLException", e);
} catch (Exception e) {
Log.e(TAG, "setApprove Exception", e);
}
}
db.close();
}
isInit = true;
sp.edit().putBoolean("isInit", true).commit();
return null;
}