android模拟器演示(BSLC)
http://v.youku.com/v_show/id_XNDU1NjI2NjAw.htmlhttp://v.youku.com/v_show/id_XNDU1NjU2NDQ4.html
这篇是回顾帖。
虽然开始得有点晚,但总也好过一直不开始。
整理自己在android webservice开发过程中遇到的各种问题,以及解决的过程。
关于图片上传下载的问题:
从最初的不知所措,到现在的略有了解,个人理解的原理是,通过把图片转换成base64编码,存放在字节流中,通过对字节流的读取、存放,来实现最终对图片的操作。难点是,如何在android下和C#的webservice中分别实现,以及数据的交互。
最初找了很多资料来看,开始选择的是ksoap2 + base64
遇到的细节问题:
图片路径:/sdcard/###.png android app 只能读取模拟器上的文件(图片),而且不能在系统文件里读取图片(root权限问题),所以,最后还是把测试的图片放到了/sdcard下。
最初想先用.net 发布web服务的调试功能,手动传图片。可是后来在学长的提醒下,明白其实不是直接传路径,(而且转换后的字节流),所以,基本上没法手动调试。
Ksoap2 不支持传递byte[]类型的参数,后来试着传base64编码后的string类型,在web服务端再解码,但是不知道哪里出错,还是产生异常。
唉,难道要换别的方法????
已解决,问题还是出在了服务端。是文件最后的存储路径不对,不能写绝对路径(估计是我的格式不对),改成(~/XXX/)相对路径就OK了!
只是这是一个简单的demo,只能上传单个的固定的文件。不过,可以比较容易改进,难点是最终我们的项目要求是一次返回多组图片数据,有待完善。
8月17日
图片上传整合到BSLC中:
进展比较缓慢。
第一个对调用系统相册的解决过程。查了很多资料,最后还是找到一个比较详细的,通过Intent.createChooser,可以选择调用多个Activity。难点是,需要在这多个被调用的Activity在AndroidManifest注册的时候加上intent -filter ,貌似这里是用来区分那些是属于Intent.ACTION_GET_CONTENT类型里的。这样的话,也就不再是调用系统默认的INTENT了吧。。。
<activity
android:name="com.photos.doTakePhoto"
android:label="照相">
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
Intent.createChooser的相关代码:
public class ImageButtonClicklistener implements OnClickListener
{
int resultCode;//区分照相还是从本地获取图片
public void onClick(View v)
{
Intent getAlbum = new Intent(Intent.ACTION_GET_CONTENT);
Intent selectIntent = new Intent(Intent.createChooser(getAlbum,"选择图片"));
Add01.this.startActivity(selectIntent);
}
}
今天的第二个坑爹的问题是:不知道什么原因,在往sdcard里添加图片的时候报错权限问题:read-only system(后缀的permission变成了d------),实际应该是d---rwxr 。各种google各种研究各种方法试都没有效果,重启了两次,删了又建了好几次模拟器。(还试过edit过 sdcard路径为file 镜像文件sdcard.img)
最后一怒之下,把系统在User/pss(我的主机名)目录下的.Android文件夹全部删除。
然后关机,去吃饭了。
等再回来,新建了一个AVD(模拟器),惊喜地发现,sdcard权限问题解决了。。。。
最后再列出一个之前遇到过的各种问题,可能有些记不清了,等有机会再补充解决过程吧。
@ksoap2的Action不能被webservice(vs2008 .netC#)识别。这个有过痛苦的回忆,所以做过记录。
//在Java平台上调用.NET WebService的服务时,出现"服务器未能识别HTTP 标头 SOAPAction 的值"
//SOAPAction HTTP request header被用来标识SOAPHTTP请求的目的地,其值是个URI地址
//SOAP发送并不限制格式、URI特征或其必须可解析,那么在这种情况下,发送一个HTTP SOAP请求时,其HTTP客户端必须使用/指明SOAPAction HTTP request header
//SOAPAction header的内容可以被用在服务端,诸如:防火墙适当的过滤基于HTTP的SOAP请求消息等场景。
//SOAPAction header的值为空串("")表示SOAP消息的目的地由HTTP请求的URI标识;无值则表示没有指定这条消息的目的地
[SoapDocumentService(RoutingStyle = SoapServiceRoutingStyle.RequestElement)]
@类似的还有:SoapObject类型不能正确接受webservice返回的值,改用Object类型,再转化回SoapObject。(或者直接用object类型)异常解决。
result = (Object)envelope.getResponse();
@webservice返回值为Dataset时,对数据的解析,也是一个痛苦的过程:最后还是找到了一个比较有自主研究精神以及分享精神的博主,才完满解决(这里有嵌套之意):
edt2.setText( ((SoapObject) ((SoapObject)result).getProperty(0) ).getProperty("name") .toString() );
ps:man.setChecked(true);是使radiobutton(单选按钮)获取焦点的方法,也花费了很多时间,最后还是高帅学长一句话,世界安静了。。。。。
@还有一些小问题,比如数据库的外键依赖啊,sql语句的组装啊,等等,看似小问题却也花费了不少时间精力。
最后总结一句吧:只要会耐心调试,总能找到问题的所在,然后研究解决问题。(怕就怕在不知道异常在哪,那才是真正的坑爹了~~~~~)
2012年8月18号
今天受困于一个上传图片遗留下来的坑爹问题,本来是想半天或者一会功夫就能解决的,结果却浪费了大量的精力和好心情。不牢骚了。
昨天做好了从本地的相册里读取图片,以期实现上传,还差的最后一步就是把读取图片的路径找到,发给文件流、字符流等等。就是这坑爹的路径问题:在Android里,文件的路径有两种,一种是绝对路径:/sdcard/XX.png之类。一种是相对路径,也就是Android系统数据库中的路径:例如图片的uri(content://media/external/images/media/4)。
这里我要做的就是要把uri转换为sdcard里的绝对路径!!!!
即使明白了原理和目标,也比较顺利地找到了部分相关的源代码,事实证明,源代码给的还是不全,让我们这些初学者苦不堪言啊。
捣鼓了半天,研究了半天,还是一个劲地报错:java.lang.NullPointerException
atandroid.content.ContextWrapper.getContentResolver(ContextWrapper.java:90)
也知道出错的位置::Cursor actualimagecursor =this.ctx.managedQuery(uri,proj,null,null,null);
我写的是this.managedQuery(uri,proj,null,null,null);
开始就不是很明白怎么个转换具体过程的我,在学长也没研究过的阴影下,坚持各种搜索资料,慢慢得开始有了一点感性的认识,知道问题可能出在context上(因为涉及了不少Activity)。(上下文)最后还是用了session(自己写的一个用于静态存储数据的类),
package com.flogin;
import android.content.Context;
import android.net.Uri;
public class Session
{
public static String id;//记录登录用户名
public static String password;//记录登录密码
public static Uri imageUri;
//记录最近一次上传的图片的Uri(格式:content://media/external/images/media/6)
public static Context doSelectImageContext;
}
相关代码:
public class ImageButtonClicklistener implements OnClickListener
{//上传图片按钮的监听器,在add.java里
public void onClick(View v)
{
imageButton.setVisibility(View.INVISIBLE);//隐藏button按钮
Intent getAlbum= new Intent(Intent.ACTION_GET_CONTENT);
Intent selectIntent = new Intent(Intent.createChooser(getAlbum,"选择图片"));
Add01.this.startActivity(selectIntent);
}
}
public boolean upload(Uri uri,String fileName){
//上传图片的函数 service.java
try
{
Log.i("log.i", "start----------------Uri:"+uri);
Log.i("log.i", "fileName:" + fileName);
String[] proj = { MediaStore.Images.Media.DATA };
String img_path=getFilePathFromUri(Session.doSelectImageContext,uri,proj,null,null,null);//碉堡了,我成功了
File file = new File(img_path);
Log.i("log.i", "file(stringpath):" + img_path);
FileInputStream fis = new FileInputStream(file);// 打开的图片地址
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int count = 0;
while ((count = fis.read(buffer)) >= 0)
{
baos.write(buffer, 0, count);
}
String uploadBuffer = new String(Base64.encode(baos.toByteArray()));
Log.i("uploadbuffer", "uploadbuffer:" + uploadBuffer);
// byte[] image=baos.toByteArray();
boolean flag = connectWebService(uploadBuffer, fileName);
if (flag)
{
return true;
} else
{
return false;
}
} catch (Exception e)
{
e.printStackTrace();
return false;
}
}
public static String getFilePathFromUri(Context context, Uri uri,String[] projection, String selection, String[] selectionArgs, StringsortOrder)
{
Cursor cursor = context.getContentResolver().query(uri,projection, selection, selectionArgs, sortOrder);
int index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String path = cursor.getString(index);
cursor.close();
cursor = null;
return path;
}
private boolean connectWebService(String image,String fileName) throws IOException,XmlPullParserException
{
String Url = "http://211.87.147.81:8082/Service.asmx";
String namespace = "http://tempuri.org/";
String methodname = "UploadImage";
String SOAP_ACTION = "http://211.87.147.81:8082/Service.asmx?op=UploadImage";
SoapObject rpc = new SoapObject(namespace, methodname);
rpc.addProperty("id", Session.id);
rpc.addProperty("image", image);
rpc.addProperty("fileName", fileName);
Log.i("send:", image + " " + fileName);
HttpTransportSE ht = new HttpTransportSE(Url);
ht.debug = false;
SoapSerializationEnvelope envelope = newSoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut = rpc;
System.out.println("post:" + rpc);
envelope.dotNet = true;
envelope.setOutputSoapObject(rpc);
ht.call(SOAP_ACTION, envelope);
Object result = (Object) envelope.getResponse();
System.out.println("result:" + result);
if (result.toString().equals("true"))
{
return true;
} else
{
return false;
}
}
//这是出现从本地选择图片的Activity
package com.photos;
import java.io.FileNotFoundException;
import com.setting01.Add01;
import com.flogin.Session;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class doSelectImageFromLoacal extendsActivity
{
/*用来标识请求照相功能的activity*/
privatestatic final int CAMERA_WITH_DATA = 1001;
/*用来标识请求gallery的activity*/
privatestatic final int PHOTO_PICKED_WITH_DATA = 1002;
privateBitmap bitMap; //用来保存图片
privateboolean hasImage; //是否已经选择了图片
publicstatic Uri selectedImageUri=null;
publicvoid onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Intent localIntent = new Intent();
localIntent.setType("image/*");
localIntent.setAction("android.intent.action.GET_CONTENT");
startActivityForResult(localIntent,PHOTO_PICKED_WITH_DATA);
}
protected void onActivityResult(int requestCode, int resultCode, Intentdata) {
Log.i("doSelectImageFromLoacal:","doSelectImageFromLoacal:start!!!!!!!!!!!!!!!!!!!!!!!!!!");
if(resultCode != RESULT_OK)
return;
switch (requestCode) {
case PHOTO_PICKED_WITH_DATA: //从本地选择图片
if (bitMap != null &&!bitMap.isRecycled()) {
bitMap.recycle();
}
selectedImageUri = data.getData();
Session.doSelectImageContext=this;
Session.imageUri=selectedImageUri;//把对应图片的在数据库中的Uri读取给Session
Log.i("log.i","selectedImageUri:"+selectedImageUri.toString());
if(selectedImageUri != null){
try {
bitMap = BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImageUri));
} catch (FileNotFoundException e){
e.printStackTrace();
}
//下面这两句是对图片按照一定的比例缩放,这样就可以完美地显示出来。有关图片的处理将重新写文章来介绍。
//int scale =ImageThumbnail.reckonThumbnail(bitMap.getWidth(), bitMap.getHeight(), 500,600);
//bitMap =ImageThumbnail.PicZoom(bitMap, (int) (bitMap.getWidth() / scale), (int)(bitMap.getHeight() / scale));
Add01.imageView.setImageBitmap(bitMap);
Add01.imageView.setVisibility(View.VISIBLE);
doSelectImageFromLoacal.this.finish();//结束当前Activity
hasImage = true;
}
break;
case CAMERA_WITH_DATA: //拍照
Bundle bundle = data.getExtras();
bitMap =(Bitmap)bundle.get("data");
if (bitMap != null)
bitMap.recycle();
bitMap = (Bitmap)data.getExtras().get("data");
Add01.imageView.setImageBitmap(bitMap);
Add01.imageView.setVisibility(View.VISIBLE);
hasImage = true;
break;
}
}
}
如何动态显示listview中绑定的数据?
尝试失败
现在尝试静态显示,事先把listview显示出来
成功了!!!虽然还是有些小bug需要改进,不过都不是大问题。
原来问题是xml文件没写好,要使用线性布局,使用关联布局会只在
listview里显示一个item。
BSLC依然存在的问题:收信箱里的收到的信件
重复读取的问题,需要有个已读和未读的区别属性。
java.net.SocketException: Connection reset bypeer
没有解决,在模拟器上测试时不再出现此问题,但是还是需要用到
异步加载图片,不然几乎没有适合的用户体验
下一步工作:
之前的code都没有调试(本身有点发烧,状态不好,先到这里把)
由物品的详细信息界面 跳转到交换引导界面
还需要扩增webservice:
比如 删除我的宝贝和交换篮里的物品信息
技术方面,还没想好怎么动态刷新搜索物品界面;
还有异步加载(试着写了,但是没调试。)
感觉要完善还有很长的路要走。
唉,今天基本上都干这个了。
已阅和未阅的标记
刷新搜索物品
我离个差 好混乱啊 逻辑上的混乱
调试 bug一大堆 唉唉
下一步工作:
信件的阅读标记;搜索物品功能的局部刷新的实现
bug:交换 -》选择我的宝贝(改变时报错
java.lang.NullPointerException)这里有待改进;;;;
加入交换蓝,功能没实现;;;;(webservice返回false)
从错误中恢复时(没有重新运行apk),session里的id会置空,(
如果能加一个判断,读取之前保存的用户和密码就好了)
下一步工作:
设置信件阅读标志
继续完善,修复bug。
如果服务器返回值的类型是byte[] 的时候,使用Object object =
envelope.getResponse();和SoapObjectresult =
(SoapObject)
envelope.bodyIn;都不会发生错误现象,但是在使用Object
object = envelope.getResponse();取回来的值在使用base64进
行解码和编码的时候会报出错误。
如果使用SoapObjectresult = (SoapObject)envelope.bodyIn;
就可以完整的将byte[]进行解码和编码
Android系统默认给TextView插入图片提供了三种方式:
1、ImageSpan
2、Html.ImageGetter
3、TextView.setCompoundDrawables(left, top, right,
bottom)
1、TextView使用ImageSpan显示图片
ImageSpan span = new ImageSpan(this,
R.drawable.ic_launcher);
SpannableString spanStr = new SpannableString
("http://orgcent.com");
spanStr.setSpan(span, spanStr.length()-1,
spanStr.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
mTVText.setText(spanStr);
3、在TextView四周显示图片
mTVText.setText("setCompoundDrawables");
Drawable d = getResources().getDrawable
(R.drawable.ic_launcher);
d.setBounds(0, 0, 50, 50); //必须设置图片大小,否则不显示
mTVText.setCompoundDrawables(d , null, null,null);
有时我们的软件界面中有退出的功能,不能用Activity中的finish
()了事,因为有时你的应用中有多个Activity,我在网上搜了如何
完全退出应用,不外乎三种方法:
1 使用ActivityManager的killBackgroundProcesses方法,这种
方法还要加应用权限,且不是所有版本SDK中通用,相关代码如下:
ActivityManager manager = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
manager.killBackgroundProcesses("package");
2 杀进程:
使用android.os.Process.killProcess
(android.os.Process.myPid());或者System.exit(0);
3 还是使用ActivityManager的restartPackage方法:
manager.restartPackage("package");
不知道为何,我都是不成功,后来使用广播机制终于可以了,如果
有朋友也和我一样,以上方法都不灵,试试广播机制,也不需要什
么权限。做法奉上:
1、先写一个父类继承Activity,其他的Activity都继承此父类,
重要的两个方法如下:
?
private BroadcastReceiver broadcastReceiver = new
BroadcastReceiver()
{
@Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
finish();
}
};
@Override
protected void onResume() {
//TODO Auto-generated method stub
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("ExitApp");
this.registerReceiver(broadcastReceiver,filter);
}
当然你也可以每个Activity都写以上的代码。
1、然后在需要退出的Activity中添加如下方法:
?
//发送广播通知所有窗体关闭
public void close()
{
Intent intent = new Intent();
intent.setAction("ExitApp");
this.sendBroadcast(intent);
super.finish();
}
需要退出时调用一下。
Web应用中防止用户重复登录的简单实现方法
主要使用application,listener, 把用户id和用户对象放到
ConcurrentHashMap中,再存入application中
1、登录时把id和对象放到application中
2、登出时把remove掉
3、listener sessionDestroyed的时候,把对象session的key从
application中去掉
一、登录时
// 2009.10.29 防止多处登录
Object onlineUsersObject =session.getServletContext
().getAttribute(Constants.ONLINE_USERS_KEY);
logger.info("on line user object isnull: {}", null ==
onlineUsersObject);
if (null != onlineUsersObject) { // 不为空,说明有用户在
线。
Map<Long, UserInfo> onlineUsersMap =(Map<Long,
UserInfo>) onlineUsersObject;
logger.info("----------001、打印在线用户 id 列表(检查用户
是否已经在列表中)---");
for (Long id : onlineUsersMap.keySet()) {
logger.info(String.valueOf(id));
}
logger.info
("------------------------------------------------------
------------------");
for (Long id : onlineUsersMap.keySet()) {
if (id.equals(userInfo.getId())) {
logger.info("{} == {}", id,userInfo.getId());
msg = super.getMessage(request,
"login.failed.username.hadLogined");
super.renderJavaScript(response,
"window.οnlοad=function(){alert('"+ msg
+ "');location.href='login.do" +queryString + "'}");
return null;
}
}
}
// 2009.10.29 防止多处登录
// Object onlineUsersObject =session.getServletContext
().getAttribute(Constants.ONLINE_USERS_KEY);
if (null != onlineUsersObject) {
Map<Long, UserInfo> onlineUsersMap =(Map<Long,
UserInfo>) onlineUsersObject;
onlineUsersMap.put(ui.getId(), ui);
} else {
Map<Long, UserInfo> onlineUsersMap =new
ConcurrentHashMap<Long, UserInfo>();
onlineUsersMap.put(ui.getId(), ui);
session.getServletContext().setAttribute
(Constants.ONLINE_USERS_KEY, onlineUsersMap);
}
logger.info("----------002、登录后打印在线用户列
表-------------");
for (Long id : ((Map<Long, UserInfo>)
session.getServletContext().getAttribute
(Constants.ONLINE_USERS_KEY)).keySet()) {
logger.info(String.valueOf(id));
}
logger.info
("------------------------------------------------------
------------------");
二、登出时
HttpSession session =request.getSession(false);
UserInfo ui = (UserInfo) session.getAttribute
(Constants.USER_INFO);
// 在 application 中删除已经注销的用户
Object onlineUsersObject =session.getServletContext
().getAttribute(Constants.ONLINE_USERS_KEY);
if (null != onlineUsersObject) {
Map<Long, UserInfo> onlineUsersMap =(Map<Long,
UserInfo>) onlineUsersObject;
logger.info("user is null ? {}",ui);
if (null != ui) {
onlineUsersMap.remove(ui.getId());
}
logger.info("------003、手动注销前打印在线用户列
表-------------");
for (Long id : onlineUsersMap.keySet()) {
logger.info(String.valueOf(id));
}
logger.info
("------------------------------------------------------
------");
}
if (null != session) {
session.removeAttribute(Constants.USER_INFO);
session.invalidate();
}
if (null != onlineUsersObject) {
Map<Long, UserInfo> onlineUsersMap =(Map<Long,
UserInfo>) onlineUsersObject;
onlineUsersMap.remove(ui);
logger.info("------004、手动注销后打印在线用户列
表-------------");
for (Long id : onlineUsersMap.keySet()) {
logger.info(String.valueOf(id));
}
logger.info
("------------------------------------------------------
------");
}
三、OnlineSessionListener
public void sessionDestroyed(HttpSessionEvent
httpSessionEvent) {
HttpSession session =httpSessionEvent.getSession();
logger.info("sessionDestroyed:{};sessionid is {}",
session, session.getId());
Object onlineUsersObject =session.getServletContext
().getAttribute(Constants.ONLINE_USERS_KEY);
UserInfo userInfo = (UserInfo)session.getAttribute
(Constants.USER_INFO);
logger.info("userInfo is null:{}",null == userInfo);
if (null != onlineUsersObject && null!= userInfo) {
Map<Long, UserInfo> onlineUsersMap =(Map<Long,
UserInfo>) onlineUsersObject;
logger.info("---------------从在线列表中移除超时用户id前打
印在线用户列表-------------");
for (Long id : onlineUsersMap.keySet()) {
logger.info(String.valueOf(id));
}
logger.info
("------------------------------------------------------
------");
for (Long id : onlineUsersMap.keySet()) {
if (id.equals(userInfo.getId())) {
logger.info(String.valueOf(id));
onlineUsersMap.remove(id);
}
}
logger.info("---------------从在线列表中移除超时用户id后打
印在线用户列表-------------");
for (Long id : onlineUsersMap.keySet()) {
logger.info(String.valueOf(id));
}
logger.info
("------------------------------------------------------
------");
}
进程的异常:
java.lang.RuntimeException: Can't createhandler inside
thread that has not called Looper.prepare()
已解决:在thread的run()里加入一个语句Looper.prepare();
根据Android SDKapi文档说明
invalidate 方法是用来更新视图(View)的方法,不过这东西的用
法比较古怪
invalidate 方法如果你直接在主线程中调用,是看不到任何更新的
。
如果跟线程结合使用的话
比如在下面的代码中就会抛出异常
UIThread implements Runnable{
public void run(){
invalidate();
}
}
上面的代码会抛出Only the original thread that created
a view hierarchy can touch its views。
怎么样解决上面的问题呢,如果你有两个View,你需要一个
View用来显示当前的状态,一个Thread去下载网络数据
或者是读取文件等,这些数据读取完毕后你要更新View到当前
屏幕上怎么办呢。看看下面的代码,也许可以帮助你
第一种解决方案是:
class UIUpdateThread implements Runnable{
public void run() {
try {
Thread.sleep(1000*5);
mHandler.post(mUpdateResults);
} catch (InterruptedExceptione) {
e.printStackTrace();
}
}
final Handler mHandler = new Handler();
final Runnable mUpdateResults =new
Runnable() {
public void run() {
invalidate(); //更新视图
}
};
}
你必须实现一个Handler.然后再你下载数据的线程中放上一个
mHandler.post(mUpdateResults);这样就可以了。
第2中方案比较简单
LoadDataThread implements Runnable{
public void run(){
doLoadData();
mHandler.sendMessage(mHandler.obtainMessage());//这里
系统会自动调用handleMessage;这样就可以更新视图了
}
}
Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 这里处理视图需要更新的代码。
}
};
有时我们的程序需要运行一些耗费时间的操作,当进行这些操作时
,我们不能让界面假死,不然用户会以为是死机或者卡住了。这时
候,我们就需要通过运行一个ProgressDialog来告诉用户:“你看
,我没死,我还活着,我还能转!”。 当然,还要有Thread的配合
,才能完成这个任务。
下面是一开始我自己写的代码,虽然思路对了,但是有些繁琐:
[java]//声明变量
private ProgressDialog pDialog = null;
Boolean startView = false;
private Handler handler;
private Thread mThread;
public void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//显示Dialog
pDialog = new ProgressDialog(this);
pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pDialog.setMessage("Loading….");
pDialog.show();
//定义Handler对象
handler = new Handler() {
public void handleMessage(Message msg) {
startView = msg.getData().getBoolean("start");
if(startView) {
//关闭Dialog
pDialog.dismiss();
}
}
};
//启动线程
mThread=new Thread(this);
mThread.start();
}
//在下面的线程中运行耗时方法
public void run() {
//耗时方法
longTimeMethod();
//handler传回“准备好”的信息
Message msg = handler.obtainMessage();
Bundle data = new Bundle();
data.putBoolean("start", true);
msg.setData(data);
handler.sendMessage(msg);
}[/java]
这样写的好处是Message可以传回不同类型的值,可以应对不同需要
。后来在网上看见了一种简便方法,顿时觉得自己这只菜鸟还要好
好学习啊。
代码是这样的:
[java]//声明变量
private Button b1;
private ProgressDialog pd;
//定义Handler对象
private Handler handler =new Handler(){
@Override
//当有消息发送出来的时候就执行Handler的这个方法
public void handleMessage(Message msg){
super.handleMessage(msg);
//只要执行到这里就关闭对话框
pd.dismiss();
}
};
public void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
private void processThread(){
//构建一个下载进度条
pd= ProgressDialog.show(MainHandler.this,"Load",
"Loading…");
new Thread(){
public void run(){
//在新线程里执行长耗时方法
longTimeMethod();
//执行完毕后给handler发送一个空消息
handler.sendEmptyMessage(0);
}
}.start();
}[/java]
这样的写法比较简洁,运行效率也高。