您的位置:首页 > 编程语言 > Java开发

【BSCL】Android与webservice开发技术总结(eclipse& visual studio 2008)

2014-12-15 13:11 435 查看

android模拟器演示(BSLC)

http://v.youku.com/v_show/id_XNDU1NjI2NjAw.html
http://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.onload=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]

这样的写法比较简洁,运行效率也高。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: