實際上以前的示例使用的就是這種方法,今天介紹它的另一種寫法。還是以教師映射為例,修改映射文件TeacherMapper.xml如下(點擊此處進入嵌套resultMap形式的示例源碼下載頁面。注:本示例代碼是在修改本系列的上篇博文示例代碼的基礎上完成的,用到了MapperScannerConfigurer和注解等知識。對這些知識不熟悉的讀者,可參考上篇博文:http://legend2011.blog.51cto.com/3018495/980150):
<?xmlversion="1.0"encoding="utf8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--與以前一樣,namespace的值是對應的映射器接口的完整名稱-->
<mappernamespace="com.abc.mapper.TeacherMapper">
<!--TeacherMapper接口中getById方法對應的SQL語句。
查詢教師及其指導的學生的信息。由于教師、學生都有
id、name、gender等屬性,因此給教師的字段都起了別名-->
<selectid="getById"parameterType="int"resultMap="supervisorResultMap">
select t.id t_id, t.name t_name, t.gender t_gender,
t.research_area t_research_area, t.title t_title,
s.id,s.name, s.gender,s.major,s.grade
from teacher t,student s where t.id=#{id}
and s.supervisor_id = t.id
</select>
<!--教師實體映射-->
<resultMapid="supervisorResultMap"type="Teacher">
<idproperty="id"column="t_id"/>
<resultproperty="name"column="t_name"/>
<resultproperty="gender"column="t_gender"/>
<resultproperty="researchArea"column="t_research_area"/>
<resultproperty="title"column="t_title"/>
<!--需要注意的是,上面的select語句中學生的字段名/別名應與
下面的column屬性一致。ofType指collection包含的元素的類型,
此屬性不可少-->
<collectionproperty="supStudents"ofType="Student">
<idproperty="id"column="id"/>
<resultproperty="name"column="name"/>
<resultproperty="gender"column="gender"/>
<resultproperty="major"column="major"/>
<resultproperty="grade"column="grade"/>
<!--映射學生的指導教師屬性,用到了
supervisorResultMap本身-->
<associationproperty="supervisor"
resultMap="supervisorResultMap"/>
</collection>
</resultMap>
</mapper>
運行程序結果如下:
與以前的寫法相比,這種寫法的缺點是學生實體映射被嵌入到教師實體映射中,因此學生實體映射不能被重用。
二、嵌套的select語句
這種方式是使用一條單獨的select語句來加載關聯(lián)的實體(在本例中就是學生實體),然后在collection元素中引用此select語句(注:此方法會產生N+1問題,關于這個問題可參考本系列博客中的“MyBatis中的N+1問題”)。首先修改TeacherMapper.xml如下(點擊此處進入嵌套select語句形式示例源碼下載頁面):
<?xmlversion="1.0"encoding="utf8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--與以前一樣,namespace的值是對應的映射器接口的完整名稱-->
<mappernamespace="com.abc.mapper.TeacherMapper">
<!--TeacherMapper接口中getById方法對應的SQL語句。
查詢教師的信息。-->
<selectid="getById"parameterType="int"resultMap="supervisorResultMap">
select * from teacher where id=#{id}
</select>
<!--教師實體映射-->
<resultMapid="supervisorResultMap"type="Teacher">
<idproperty="id"column="id"/>
<resultproperty="name"column="name"/>
<resultproperty="gender"column="gender"/>
<resultproperty="researchArea"column="research_area"/>
<resultproperty="title"column="title"/>
<!--ofType指collection包含的元素的類型,此屬性不可少。
column屬性指把上述的getById的select語句中的教師id列的值作為參數(shù)
傳遞給將要引用到的下述的getStudents的select語句,此屬性不可少。
引用的形式為:命名空間.select語句id-->
<collectionproperty="supStudents"column="id"ofType="Student"
select="com.abc.mapper.StudentMapper.getStudents"/>
</resultMap>
</mapper>
在這里把根據(jù)指導教師id查詢學生信息的SQL語句寫在StudentMapper.xml中,并引用其中的學生實體映射studentResultMap。修改StudentMapper.xml如下:
<?xmlversion="1.0"encoding="utf8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="com.abc.mapper.StudentMapper">
<resultMapid="studentResultMap"type="Student">
<idproperty="id"column="id"/>
<resultproperty="name"column="name"/>
<resultproperty="gender"column="gender"/>
<resultproperty="major"column="major"/>
<resultproperty="grade"column="grade"/>
<!--在這里引用supervisorResultMap和getById,亦采用
命名空間名.相關元素id的形式。column="supervisor_id"
屬性不可少-->
<associationproperty="supervisor"
resultMap="com.abc.mapper.TeacherMapper.supervisorResultMap"
select="com.abc.mapper.TeacherMapper.getById"column="supervisor_id"/>
</resultMap>
<!--根據(jù)指導教師id查詢學生信息-->
<selectid="getStudents"parameterType="int"
resultMap="studentResultMap">
select * from student where supervisor_id = #{id}
</select>
</mapper>
執(zhí)行結果如下:
最近在工作中遇到了一個需求
在執(zhí)行數(shù)據(jù)庫操作時需要先判斷指定的數(shù)據(jù)是否存在,如果不存在則插入,存在則更新
最開始使用的是三條SQL語句:
后來leader提示還有新的方法,一條SQL語句就能搞定:
后來在網(wǎng)上看到的,執(zhí)行update語句的條件是insert語句的執(zhí)行會造成唯一鍵的重復。
所以,在創(chuàng)建表的時候還要加上唯一鍵的約束:
這樣就能達到目的。
大家都在為項目開發(fā)成功而喜悅,但可不知成功的路上是會經(jīng)常出錯的,下面是我碰到的一些錯誤集合!
【錯誤信息】
01-16 17:16:18.945: I/magh(979): org.apache.http.conn.HttpHostConnectException: Connection to http://127.0.0.1:8080 refused
在android模擬器連接本機訪問web時報這錯,把127.0.0.1改成localhost也是一樣的
原因:【錯誤信息】
java.lang.IllegalArgumentException: The key must be an application-specific resource id.
原因及解決辦法:
mRadioButton.setTag(1,sQuestionItem.get(i).getToNext());//設置監(jiān)聽 ToNext:下 一題目mRadioButton.setTag(2,sQuestionItem.get(i).getToEnd());//設置監(jiān)聽 ToEnd: 是否終止 拋出IllegalArgumentException的原因就在于key不唯一,正確代碼如下:
mRadioButton.setTag(R.id.tag_tonext,sQuestionItem.get(i).getToNext());// 設置監(jiān)聽 ToNext:下一題目 mRadioButton.setTag(R.id.tag_toend,sQuestionItem.get(i).getToEnd());//設置 監(jiān)聽 ToEnd:是否終止
【錯誤信息】
點擊Debug 運行 結果模擬器總是會彈出Waiting for Debugger 然后程序又可以正常運行
如果你想調試的時候去掉 Waiting for Debugger 提示
原因及解決辦法:
重啟啟動機器就OK
本文出自 “java之路” 博客,請務必保留此出處http://2402766.blog.51cto.com/2392766/1102373
管理提醒: 本帖被 kasim 執(zhí)行置頂操作(2010-04-11)
管理提醒: 本帖被 kasim 執(zhí)行加亮操作(2010-04-11)
首先說一下Json數(shù)據(jù)的最基本的特點,Json數(shù)據(jù)是一系列的鍵值對的集合,和XML數(shù)據(jù)來比,Json數(shù)據(jù)的體積更加小,傳輸效率高,易解析,不過可讀性不高;
因為這次要從服務器端得到Json數(shù)據(jù),并且通過解析之后把解析后的數(shù)據(jù)顯示在Android客戶端中,首先部署服務器端代碼(直接使用Jsp/Servlet):
構造的Json數(shù)據(jù)如下:
[{"name":"張三","address":"北京","age":20},{"name":"李四","address":"上海","age":30},{"name":"王五","address":"深圳","age":35}]
[一]服務器端(Person.java省略):
①:數(shù)據(jù)構造JsonService.java
main.xml文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:id="@+id/iv1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/longshuai" <!-- longshuai.png為圖片的名稱,記在資源文件里頭,不用文件名后綴-->
/>
</LinearLayout>
注意:強調一下,資源文件的圖片命名規(guī)則比較嚴格,由[a-z]和數(shù)字和“_”組成,而且不能數(shù)字開頭,我就常犯傻,命名老是數(shù)字或者大寫字母開頭,這種錯誤——囧。。
我們要把longshuai.png導入到res中,最簡單的方式就是直接找到這個文件夾,復制進去
之后右鍵更新,我們就可以在res中看到自己的圖片了
不用寫代碼。。直接用自動生成的代碼。。
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
效果如下:
2、加載本地圖片(其實主要是SdCard中圖片)
關于SdCard的使用,可以參見 http://longshuai2007.blog.163.com/blog/static/1420944142011611103950500/
xml文件同上面的是一樣的,并不需要修改
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView image1 = (ImageView) findViewById(R.id.iv1); //獲得ImageView對象
/*為什么圖片一定要轉化為 Bitmap格式的??! */
Bitmap bitmap = getLoacalBitmap("/sdcard/tubiao.jpg"); //從本地取圖片(在cdcard中獲取) //
image1 .setImageBitmap(bitmap); //設置Bitmap
}
/**
* 加載本地圖片
* @param url
* @return
*/
public static Bitmap getLoacalBitmap(String url) {
try {
FileInputStream fis = new FileInputStream(url);
return BitmapFactory.decodeStream(fis); ///把流轉化為Bitmap圖片
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
}
顯示效果如下:
android 完全退出應用程序
android android 退出應用程序, 單例模式管理Activity
引自:http://www.yoyong.com/archives/199
android 退出應用程序會調用android.os.Process.killProcess(android.os.Process.myPid())
或是System.exit(0),這只是針對第一個Activity(也就是入口的Activity)時生效。如果有A,B,C
三個Activity,而想在B 或C 中Activity 退出,調用上面的方法,往往會銷毀當前的Activity 返回上
一個Activity。當然也可以逐個返回上一個Activity,直到跳轉到入口的Activity,最后退出應用程
序。但這樣比較麻煩,而且逐個返回的體驗并不友好。
網(wǎng)上比較流行的方法是定義棧,寫一個ExitApplication 類,利用單例模式管理Activity,在每個在
Activity 的onCreate()方法中調用ExitApplication.getInstance().addActivity(this)方法,在退
出時調用ExitApplication.getInstance().exit()方法,就可以完全退出應用程序了。
ExitApplication 類
代碼如下:
view plaincopy to clipboardprint?
1 import java.util.LinkedList;
2 import java.util.List;
3
4 import android.app.Activity;
5 import android.app.Application;
6
7 public class ExitApplication extends Application {
9 private List<Activity> activityList=new LinkedList<Activity>();
10 private static ExitApplication instance;
11
12 private ExitApplication()
13 {
14 }
15 //單例模式中獲取唯一的ExitApplication 實例
16 public static ExitApplication getInstance()
17 {
18 if(null == instance)
19 {
20 instance = new ExitApplication();
21 }
22 return instance;
23
24 }
25 //添加Activity 到容器中
26 public void addActivity(Activity activity)
27 {
28 activityList.add(activity);
29 }
30 //遍歷所有Activity 并finish
31
32 public void exit()
33 {
34
35 for(Activity activity:activityList)
36 {
37 activity.finish();
38 }
39
40 System.exit(0);
41
42 }
43 }
下面的三個類IndexActivity, BActivity,CActivity 是簡單的例子, 分別是
IndexActivity–>BActivity–>CActivity 的跳轉順序。在每個Activity 類中onCreate()方法中調
用ExitApplication.getInstance().addActivity(Activity activity)方法。在任何一個Activity 界面退
出應用程序時,只要調用ExitApplication.getInstance().exit()方法,就可以在任何一個Activity
中完全退出應用程序。
IndexActivity 類源代碼:
view plaincopy to clipboardprint?
44 import android.app.Activity;
45 import android.content.Intent;
46 import android.os.Bundle;
47 import android.view.View;
48 import android.view.View.OnClickListener;
49 import android.widget.Button;
50
51 public class IndexActivity extends Activity {
52 /** Called when the activity is first created. */
53 @Override
54 public void onCreate(Bundle savedInstanceState) {
55 super.onCreate(savedInstanceState);
56 setContentView(R.layout.main);
57
58 Button next=(Button)findViewById(R.id.next_to_b);
59 next.setOnClickListener(nextClick);
60
61 Button exit=(Button)findViewById(R.id.exit_main);
62 exit.setOnClickListener(exitClick);
63 ExitApplication.getInstance().addActivity(this);
64
65 }
66
67 OnClickListener nextClick=new OnClickListener() {
68
69 @Override
70 public void onClick(View v) {
71 // TODO Auto-generated method stub
72
73 Intent intent=new Intent(IndexActivity.this,BActivity.class);
74 startActivity(intent);
75
76 }
77 };
78
79 OnClickListener exitClick=new OnClickListener() {
80
81 @Override
82 public void onClick(View v) {
83 // TODO Auto-generated method stub
84 ExitApplication.getInstance().exit();
85 }
86 };
87 }
BActivity 類源代碼:
view plaincopy to clipboardprint?
88 import android.app.Activity;
89 import android.content.Intent;
90 import android.os.Bundle;
91 import android.view.View;
92 import android.view.View.OnClickListener;
93 import android.widget.Button;
94
95 public class BActivity extends Activity {
96
97 @Override
98 protected void onCreate(Bundle savedInstanceState) {
99 // TODO Auto-generated method stub
100 super.onCreate(savedInstanceState);
101
102 setContentView(R.layout.b);
103 Button next_to_c=(Button)findViewById(R.id.next_to_c);
104 next_to_c.setOnClickListener(next_to_cClick);
105
106 Button exit_b=(Button)findViewById(R.id.exit_b);
107 exit_b.setOnClickListener(exitClick);
108 ExitApplication.getInstance().addActivity(this);
109
110 }
111
112 OnClickListener next_to_cClick=new OnClickListener() {
113
114 @Override
115 public void onClick(View v) {
116 // TODO Auto-generated method stub
117
118 Intent intent=new Intent(BActivity.this,CActivity.class);
119 startActivity(intent);
120
121 }
122 };
123
124 OnClickListener exitClick=new OnClickListener() {
125
126 @Override
127 public void onClick(View v) {
128 // TODO Auto-generated method stub
129 ExitApplication.getInstance().exit();
130 }
131 };
132 }
CActivity 類源代碼:
view plaincopy to clipboardprint?
133 import android.app.Activity;
134 import android.os.Bundle;
135 import android.view.View;
136 import android.view.View.OnClickListener;
137 import android.widget.Button;
138
139 public class CActivity extends Activity{
140
141 @Override
142 protected void onCreate(Bundle savedInstanceState) {
143 // TODO Auto-generated method stub
144 super.onCreate(savedInstanceState);
145
146 setContentView(R.layout.c);
147
148 Button exit_c=(Button)findViewById(R.id.exit_c);
149 exit_c.setOnClickListener(exitClick);
150 ExitApplication.getInstance().addActivity(this);
151
152 }
153
154 OnClickListener exitClick=new OnClickListener() {
155
156 @Override
157 public void onClick(View v) {
158 // TODO Auto-generated method stub
159 ExitApplication.getInstance().exit();
160 //如果只是調用以下其中的一個方法,并不會完全退出應用
161 //android.os.Process.killProcess(android.os.Process.myPid());
162 //System.exit(0);
163 }
164 };
165
166 }
1、Listview簡述
A view that shows items in a vertically scrolling list. The items come from theListAdapter
associated with this view.
簡單來說就是,創(chuàng)建Listview,然后給數(shù)值就行了。
而這些數(shù)值來源有三種方式:ArrayAdapter、SimpleAdapter、SimpleCursorAdapter
第一種是最簡單的一種Adapter,是字符串數(shù)值,只能在ListView顯示出文本信息。
第二種是一種自定義的數(shù)據(jù)來源,要自定義布局方式,可以放置圖片,按鈕,文本之類的。
第三種數(shù)據(jù)來源于數(shù)據(jù)庫。
本文為第一種方式,ArrayAdapter,其他兩項的方法都差不多,主要是adapter不同。
2、使用ListView步驟
首先創(chuàng)建Listview組件,然后調用Listview.ArrayAdapter()方法,設置Adapter。
通過調用setOnItemClickListener
()接口方法,設置“點擊”listview某一項的監(jiān)聽事件。
通過調用setOnItemLongClickListener
()接口方法,設置“長按”listview某一項的監(jiān)聽事件。
需要說明的是,當設置匿名內部類new OnItemClickListener()時,eclipse不會自動載入復寫函數(shù),要點擊左邊的錯誤提示,然后Add unimplemented methods,才能載入復寫函數(shù)onItemClick()。
Callback method to be invoked when an item in this AdapterView has been clicked.
Implementers can call getItemAtPosition(position) if they need to access the data associated with the selected item.
//當點擊listview某一項時,這個回調方法就會被調用。
parent | The AdapterView where the click happened. |
---|---|
view | The view within the AdapterView that was clicked (this will be a view provided by the adapter) |
position | The position of the view in the adapter. |
id | The row id of the item that was clicked. |
主要說說最后三個參數(shù),
view——————是你點擊的Listview的某一項的內容,來源于adapter。如用((TextView)arg1).getText(),可以取出點擊的這一項的內容,轉為string類型。
position————是adapter的某一項,如點擊了listview第2項,而第2項對應的是adapter的第2個數(shù)值,那此時position的值就為1了。
如對應adapter的第3個數(shù)值,那此時position的值就為2了。
id———————id的值為點擊了Listview的哪一項對應的數(shù)值,點擊了listview第2項,那id就等于1。
注:這些數(shù)值都是從0開始的。
s是遍歷后賦值的變量,v是要遍歷的list。
可以通過以下語句進行測試:
List<String> v=new ArrayList();
v.add("one");
v.add("two");
for(String s:v){
System.out.println(s);
}
注意s要跟前面的類型匹配。
1.response.setContentType("text/html;charset=gb2312");
在做servlet的時候,在doGet中已經(jīng)設定了response.setContentType("text/html;charset=gb2312");
pw.println("姓名");
pw.println("性別");
pw.println("郵箱");
pw.println("地址");
pw.println("權限");
這些漢字的可以正確顯示,但是從數(shù)據(jù)庫中查詢返回的漢字顯示為亂碼:
姓名 | 性別 | 郵箱 | 地址 | 權限 |
admin | 0 | admin@163.com | ???????? | 1 |
user1 | 0 | user1@163.com | ???????? | 5 |
user2 | 0 | user2@163.com | ???????? | 5 |
user3 | 0 | user3@163.com | ?????à?? | 3 |
user4 | 0 | user4@163.com | ???????¨ | 3 |
user5 | 0 | user5@163.com | ???????¨ | 5 |
user6 | 0 | user6@163.com | ???????¨ | 5 |
最近幾天一直都在學JSP,我用的數(shù)據(jù)庫是Mysql。在連接數(shù)據(jù)庫的過程中,剛開始我只是簡單的執(zhí)行了查詢命令,發(fā)現(xiàn)從數(shù)據(jù)庫取出的中文數(shù)據(jù)全部顯示成了亂碼,查了一些資料之后,我先用了下面的一個轉換函數(shù),值得高興的是,讀出的中文顯示正常:
將從Mysql數(shù)據(jù)庫中得到的中文數(shù)據(jù),通過以下轉換函數(shù) String trans(String chi)進行處理,即可正常顯示中文:
String trans(String chi) {
String result = null;
byte temp[];
try {
temp = chi.getBytes("iso-8859-1");
result = new String(temp);
} catch(UnsupportedEncodingException e) {
System.out.println(e.toString());
}
return result;
}
但很快,我意識到這種方法只是治標不治本,因為在插入中文數(shù)據(jù)時,又沒法在Mysql中正常顯示中文。而真正治本的方法是,將Mysql的編碼格式由默認的latin1改成gb2312.
改的步驟如下:
1. 設置Mysql的編碼格式(注意是在創(chuàng)建數(shù)據(jù)庫之前就要設置)
找到Mysql安裝目錄下的 myini文件,用記事本打開,找到以下兩句:
[mysql]
default-character-set=latin1
--------------------------------------------------------------------------------------------------
[mysqld]
# The TCP/IP Port the MySQL Server will listen on
port=3306
#Path to installation directory. All paths are usually resolved relative to this.
basedir="C:/Program Files/MySQL/MySQL Server 5.0/"
#Path to the database root
datadir="C:/Program Files/MySQL/MySQL Server 5.0/Data/"
# The default character set that will be used when a new schema or table is
# created and no character set is defined
default-character-set=latin1
我們需要做的是將這兩處的默認編碼格式由“latin1”改成“gb2312”。
改好之后,重啟Mysql 。
2. 在Mysql中開始創(chuàng)建數(shù)據(jù)庫
用相關命令創(chuàng)建數(shù)據(jù)庫,表等
注意: 在創(chuàng)建表時要加上一句 TYPE=MyISAM, default character set gb2312;
如以下示例:
create table student
-> (sno varchar(20),
-> sname varchar(10),
-> sex char(2),
-> age numeric(2),
-> dept varchar(20),
-> primary key(sno))
-> type=myisam,default character set gb2312;
3. 在Java文件或者JSP文件中連接數(shù)據(jù)庫
在Java代碼中:
str = "com.mysql.jdbc.Driver";
url="jdbc:mysql://localhost:3306/example?useUnicode=true&characterEncoding=gb2312";
user = "root";
password = "123456";
Class.forName(str).newInstance();
conn = DriverManager.getConnection(url,user,password);
在JSP中需要注意的有:
<%@page contentType="text/html"%>
<%@page pageEncoding="gb2312" %>
<%@ page import="java.sql.*,java.io.*" %>
gb2312">
OK,經(jīng)過上述一些設置之后,JAVA連Mysql將不會再出現(xiàn)中文顯示亂碼!
在android中,有很多功能是不能放在onCreate或者onStart方法里面,因為這些功能相對
來說費時比較長,比如說下載一個文件,下載的過程比較長,但是如果寫在Activity中,
那么這段時間Activity是完全沒有響應的,那么就可以將這種處理大量數(shù)據(jù)或者耗時比較
長的東西放在一個單獨的線程中來完成,即Activity是一個線程,而下載的是在另外一個
線程,那么這樣就可以使得下載跟Activity之間互不影響,從而得到了良好的用戶體驗
這里有兩種隊列,一種是線程隊列,就是用postXX方法或者removeCallbacks方法對線程對象的操作。另一種是消息隊列,用sendMessage和handleMessage方法來對消息對象進行處理
handler采用的是一個消息隊列的方式,每一個handler都有一個與之關聯(lián)的消息隊列,而且是先進先出的方式執(zhí)行,即:每次加入一個handler,然后拿出來,對其進行處理,然后再拿出另一個,再進行處理
例子一:這個例子僅僅是對線程對象進行操作的測試
運行結果如下:
程序解釋:首先創(chuàng)建一個Handler對象,然后創(chuàng)建一個繼承自Runnable接口的線程
程序首先點擊按鈕“開始”,于是會馬上執(zhí)行post方法,將執(zhí)行的線程對象添加到線程隊列中,這時會馬上執(zhí)行
然后,執(zhí)行postDelayed方法,由于里面設置的間隔時間,所以每3秒會調價一個handler對象到線程隊列中,并且一直執(zhí)行,直到點擊“結束”按鈕,調用removeCallbacks方法將其從線程隊列中移除
例子2:下面的例子將簡單的對線程對象和消息對象進行處理
main.xml
運行結果:
程序說明:
1、當點擊按鈕后,會執(zhí)行按鈕的onClick方法中的
將進度條顯示出來,并且將線程對象加入到線程隊列中
2、線程對象對先打印出一個“開始線程”,然后i的值增加10,然后從系統(tǒng)中獲取一個Message對象
3、將i賦給Message對象的參數(shù)arg1
4、當前線程休眠5秒,然后通過sendMessage方法發(fā)送一個Message對象發(fā)送到消息隊列中
5、然后再執(zhí)行,通過handleMessage方法設置進度條的值,并且將其加入到進程隊列中
6、循環(huán)執(zhí)行,直到i=100,進度條隱藏,并將線程對象從線程隊列中取出
對于Handler來說,它和與它調用它的Activity是出于同一線程的,上一篇并沒有調用線程
的start方法,而是直接執(zhí)行的run方法。而啟動一個線程是調用的start方法
上一篇博客里的對Handler的調用時通過Runnable接口來實現(xiàn)的,并且是通過run()方法來啟動那個線程的,而且是Activity和 Handler是兩個線程獨立運行的,互補干擾,但是實際情況確實,Activity所在的線程和Handler的線程是同一個線程,下面進行一下實驗
運行結果:
證明是同一個線程的兩個依據(jù):
①Activity的id或name和Handler的id或name是同樣的
②我設置了
handler.post(r);
setContentView(R.layout.main);
也就是,如果執(zhí)行后馬上顯示文本信息,那么可以證明它們不在同一個線程,但是實際情況是要先執(zhí)行了handler后5秒,才顯示文本信息,說明它們在同一線程
如果將代碼改為
再次執(zhí)行,運行結果如下,通過start啟動線程,它們不在同一個線程中
----------------------------------------------------------------------------------------------------------------
Looper即循環(huán)的從隊列當中取得消息的功能,如果在線程中使用Looper
那么,就會循環(huán)的從線程隊列當中取得消息并處理,如果隊列當中沒有消息的話
,線程就進入了休眠狀態(tài)
Looper很少自己創(chuàng)建,在Android中給出了HandlerThread類,并且具有循環(huán)取得并處理消息的功能
下面來實現(xiàn)這種Activity和Handler分別在兩個線程中執(zhí)行,實現(xiàn)真正的異步處理
運行結果:
可以看到,Activity和Handler是在兩個不同的線程中執(zhí)行的,這樣就是實現(xiàn)了真正的異步處理
1、首先創(chuàng)建一個HandlerThread對象,這個HandlerThread類實現(xiàn)了循環(huán)的取得消息并處理
2、用start方法啟動一個新線程
3、創(chuàng)建MyHandler類,里面?zhèn)鬟f的參數(shù)即Looper方法所獲得的可以循環(huán)在隊列中取得的消息
4、MyHandler類調用的是帶參數(shù)Looper的構造方法,并且實現(xiàn)了handlerMessage方法
5、獲取一個Message對象
6、將這個對象發(fā)送到生成該msg對象的handler對象,從而執(zhí)行了handleMessage方法
-----------------------------------------------------------------------------------------------------
最后,將說一下Message里傳送的數(shù)據(jù)的使用,這里的msg對象可以使用arg1,arg2或者obj
arg1 and arg2 are lower-cost alternatives to using setData()
if you only need to store a few integer values. 也就是相對于setData()方法,如果你僅僅保存一些簡單的整形數(shù)的話,arg1,arg2對資源的要求較低,而setData()方法一般用于傳遞 大量數(shù)據(jù)的時候會用到
如果是msg.obj,那么可以這樣用
msg.obj = "Welcome to china";
然后在handleMessage()方法中用
String str = (String)msg.obj;來獲得傳遞的值
如果使用getData()方法的話,需要用到Bundle對象來傳遞,下面用個例子來說明
上面的代碼用來設置要傳遞的數(shù)據(jù)
下面的代碼用來獲取Bundle傳遞過來的數(shù)據(jù)并且用Toast來顯示
package org.hualang.handlertest;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
public class HandlerTest4 extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("System.out","Activity所在線程的id:"+Thread.currentThread().getId());
/**
* 生成一個HandlerThread對象,實現(xiàn)了使用Looper來處理消息隊列的功能
* 這個類由Android應用程序框架提供
*/
HandlerThread handlerThread = new HandlerThread("handlerThread");
/**
* 使用HandlerThread的getLooper()方法之前,必須先調用該類的start()方法,否則是個null,會報錯
*/
handlerThread.start();
MyHandler handler = new MyHandler(handlerThread.getLooper());
Message msg = handler.obtainMessage();
/**
* 將Message對象發(fā)送到目標對象
* 所謂的目標對象,就是生成該msg對象的handler對象
*/
//msg.obj = "Hello world";
Bundle b = new Bundle();
b.putInt("age", 22);
b.putString("name", "loulijun");
msg.setData(b);
msg.sendToTarget();
}
class MyHandler extends Handler
{
public MyHandler()
{
}
public MyHandler(Looper looper)
{
super(looper);
}
public void handleMessage(Message msg)
{
//String str = (String)msg.obj
Bundle b = msg.getData();
int age = b.getInt("age");
String name = b.getString("name");
Toast toast = Toast.makeText(getApplicationContext(), "age="+age+"name="+name, Toast.LENGTH_LONG);
toast.show();
Log.d("System.out", "handler所在線程的id:"+Thread.currentThread().getId());
}
}
}
運行結果: