整理几个android后台发送邮件的方法

 更新时间:2016年9月20日 19:58  点击:2552
本文我们整理了三个android后台发送邮件的方法及示例,第一个是不借助Intent在android后台发送Email,第二个是用在收集应用的异常信息,第三个是分享一个android后台发送邮件的类。

android后台发送Email(不借助Intent)

Android的SDK使得它很容易从一个应用程序发送电子邮件,但只能通过Intent的方法,就是通过内置的邮件应用程序。这能满足大多数的需求,但如果你想在后台发送,就不行了。
在这篇文章中,我将告诉你怎样在没有用户干预的情况下,在后台发送一封电子邮件。

开始之前需要先下载一个特殊版本的JavaMail API,这是专门为Android编写的。

http://code.google.com/p/javamail-android/downloads/list


如果你被墙屏蔽了,也可以去这里下载,里面的附件里有全部需要的东西,包括如何在Android应用的Activity中使用:


我们开始吧,下面是对邮件发送功能的封装,使用这些方法可以很容易地发送电子邮件,甚至可以添加附件。

import java.util.Date;
import java.util.Properties;
import javax.activation.CommandMap;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.activation.MailcapCommandMap;
import javax.mail.BodyPart;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
 
 
public class Mail extends javax.mail.Authenticator {
  private String _user;
  private String _pass;
 
  private String[] _to;
  private String _from;
 
  private String _port;
  private String _sport;
 
  private String _host;
 
  private String _subject;
  private String _body;
 
  private boolean _auth;
   
  private boolean _debuggable;
 
  private Multipart _multipart;
 
 
  public Mail() {
    _host = "smtp.gmail.com"; // default smtp server
    _port = "465"; // default smtp port
    _sport = "465"; // default socketfactory port
 
    _user = ""; // username
    _pass = ""; // password
    _from = ""; // email sent from
    _subject = ""; // email subject
    _body = ""; // email body
 
    _debuggable = false; // debug mode on or off - default off
    _auth = true; // smtp authentication - default on
 
    _multipart = new MimeMultipart();
 
    // There is something wrong with MailCap, javamail can not find a handler for the multipart/mixed part, so this bit needs to be added.
    MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
    mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
    mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
    mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
    mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
    mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
    CommandMap.setDefaultCommandMap(mc);
  }
 
  public Mail(String user, String pass) {
    this();
 
    _user = user;
    _pass = pass;
  }
 
  public boolean send() throws Exception {
    Properties props = _setProperties();
 
    if(!_user.equals("") && !_pass.equals("") && _to.length > 0 && !_from.equals("") && !_subject.equals("") && !_body.equals("")) {
      Session session = Session.getInstance(props, this);
 
      MimeMessage msg = new MimeMessage(session);
 
      msg.setFrom(new InternetAddress(_from));
       
      InternetAddress[] addressTo = new InternetAddress[_to.length];
      for (int i = 0; i < _to.length; i++) {
        addressTo[i] = new InternetAddress(_to[i]);
      }
        msg.setRecipients(MimeMessage.RecipientType.TO, addressTo);
 
      msg.setSubject(_subject);
      msg.setSentDate(new Date());
 
      // setup message body
      BodyPart messageBodyPart = new MimeBodyPart();
      messageBodyPart.setText(_body);
      _multipart.addBodyPart(messageBodyPart);
 
      // Put parts in message
      msg.setContent(_multipart);
 
      // send email
      Transport.send(msg);
 
      return true;
    } else {
      return false;
    }
  }
 
  public void addAttachment(String filename) throws Exception {
    BodyPart messageBodyPart = new MimeBodyPart();
    DataSource source = new FileDataSource(filename);
    messageBodyPart.setDataHandler(new DataHandler(source));
    messageBodyPart.setFileName(filename);
 
    _multipart.addBodyPart(messageBodyPart);
  }
 
  @Override
  public PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(_user, _pass);
  }
 
  private Properties _setProperties() {
    Properties props = new Properties();
 
    props.put("mail.smtp.host", _host);
 
    if(_debuggable) {
      props.put("mail.debug", "true");
    }
 
    if(_auth) {
      props.put("mail.smtp.auth", "true");
    }
 
    props.put("mail.smtp.port", _port);
    props.put("mail.smtp.socketFactory.port", _sport);
    props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.socketFactory.fallback", "false");
 
    return props;
  }
 
  // the getters and setters
  public String getBody() {
    return _body;
  }
 
  public void setBody(String _body) {
    this._body = _body;
  }
 
  // more of the getters and setters …..
}

And now I'm going to go through each bit of code

 
public Mail() {
  _host = "smtp.gmail.com"; // default smtp server
  _port = "465"; // default smtp port
  _sport = "465"; // default socketfactory port
 
  _user = ""; // username
  _pass = ""; // password
  _from = ""; // email sent from
  _subject = ""; // email subject
  _body = ""; // email body
 
  _debuggable = false; // debug mode on or off - default off
  _auth = true; // smtp authentication - default on
 
  _multipart = new MimeMultipart();
 
  // There is something wrong with MailCap, javamail can not find a handler for the multipart/mixed part, so this bit needs to be added.
  MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
  mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
  mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
  mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
  mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
  mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
  CommandMap.setDefaultCommandMap(mc);
}
 
public Mail(String user, String pass) {
  this();
 
  _user = user;
  _pass = pass;
}

在这段代码中,我们初始化了类mail属性,并设置为默认值。
另外,里面的JavaMail MIME类型需要注意看。里面有一个注释说明。
里面的两个2个构造函数也要仔细看,你可以通过其中一个传递用户名跟密码进去。

public boolean send() throws Exception {
  Properties props = _setProperties();
 
  if(!_user.equals("") && !_pass.equals("") && _to.length > 0 && !_from.equals("") && !_subject.equals("") && !_body.equals("")) {
    Session session = Session.getInstance(props, this);
 
    MimeMessage msg = new MimeMessage(session);
 
    msg.setFrom(new InternetAddress(_from));
       
    InternetAddress[] addressTo = new InternetAddress[_to.length];
    for (int i = 0; i < _to.length; i++) {
      addressTo[i] = new InternetAddress(_to[i]);
    }
    msg.setRecipients(MimeMessage.RecipientType.TO, addressTo);
 
    msg.setSubject(_subject);
    msg.setSentDate(new Date());
 
    // setup message body
    BodyPart messageBodyPart = new MimeBodyPart();
    messageBodyPart.setText(_body);
    _multipart.addBodyPart(messageBodyPart);
 
    // Put parts in message
    msg.setContent(_multipart);
 
    // send email
    Transport.send(msg);
 
    return true;
  } else {
    return false;
  }
}

这是发送的方法,里面有设置了数据属性,然后执行了发送操作。


public void addAttachment(String filename) throws Exception {
  BodyPart messageBodyPart = new MimeBodyPart();
  DataSource source = new FileDataSource(filename);
  messageBodyPart.setDataHandler(new DataHandler(source));
  messageBodyPart.setFileName(filename);
 
  _multipart.addBodyPart(messageBodyPart);
}

这是添加附件的函数,不过需要在发送之前调用。


private Properties _setProperties() {
  Properties props = new Properties();
 
  props.put("mail.smtp.host", _host);
 
  if(_debuggable) {
    props.put("mail.debug", "true");
  }
 
  if(_auth) {
    props.put("mail.smtp.auth", "true");
  }
 
  props.put("mail.smtp.port", _port);
  props.put("mail.smtp.socketFactory.port", _sport);
  props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
  props.put("mail.smtp.socketFactory.fallback", "false");
 
  return props;
}

在这里,我们设置了邮件认证的属性 - 默认是SMTP认证。
这是所有Gmail(谷歌)SMTP服务器连接。


Android 后台发送邮件 收集应用异常信息


这篇文章是实用性文章,不会涉及太多理论分析。主要是让大家看了以后知道怎么在自己的应用里面添加这个功能。下面附件Demo和关键代码是CSDN上面一个例子代码,我只把包链接和界面改了一下,方便阅读。因此不知道这Demo的原始作者是谁,如果您看到这是您的Demo代码,请跟我联系加入您的信息。

 (PS:新建的QQ群,有兴趣可以加入一起讨论:Android群:322599434)

1、第三方库

这次发送后台邮件需要用到三个第三方的库,这几个库在java里面应该是比较有名的了。以前做个java 邮件开发的朋友,应该多多少少都会用过。Android默认发送邮件的方法,需要通过Intent调用系统邮件程序,这个对于我们这种后台操作不实用。

    activation.jar
    additionnal.jar
    mail.jar

下面我Demo例子里面会附上这三个包,这几个包网上也很多资源,可以自行下载。

 

2、邮件信息

因为我们是后台发送邮件,因此需要收集一些必要信息,因为不需要用户输入这些信息。

//Edited by mythou
//http://www.cnblogs.com/mythou/

public class MailSenderInfo
{
    // 发送邮件的服务器的IP和端口    
    private String mailServerHost;    
    private String mailServerPort = "25";   
    
    // 邮件发送者的地址    
    private String fromAddress;    
    // 邮件接收者的地址    
    private String toAddress;    
    // 登陆邮件发送服务器的用户名和密码    
    private String userName;    
    private String password;    
    // 是否需要身份验证    
    private boolean validate = true;    
    // 邮件主题    
    private String subject;    
    // 邮件的文本内容    
    private String content;    
    // 邮件附件的文件名    
    private String[] attachFileNames;      
}

上面这些都是我们发送邮件的时候需要用到的信息。这里需要注意的是,我们发送后台邮件需要给出账号密码等敏感信息。这些邮件信息,我们可以在程序里面编写好,这样我们发送邮件的时候,就不需要用户输入任何信息。

 

3、邮件发送

//Edited by mythou
//http://www.cnblogs.com/mythou/

   public boolean sendTextMail(MailSenderInfo mailInfo)
    {
        // 判断是否需要身份认证    
        MyAuthenticator authenticator = null;    
        Properties pro = mailInfo.getProperties();   
        if (mailInfo.isValidate())
        {    
            // 如果需要身份认证,则创建一个密码验证器    
            authenticator = new MyAuthenticator(mailInfo.getUserName(), mailInfo.getPassword());    
        }   
        // 根据邮件会话属性和密码验证器构造一个发送邮件的session    
        Session sendMailSession = Session.getDefaultInstance(pro,authenticator);    
        try
        {    
            // 根据session创建一个邮件消息    
            Message mailMessage = new MimeMessage(sendMailSession);    
            // 创建邮件发送者地址    
            Address from = new InternetAddress(mailInfo.getFromAddress());    
            // 设置邮件消息的发送者    
            mailMessage.setFrom(from);    
            // 创建邮件的接收者地址,并设置到邮件消息中    
            Address to = new InternetAddress(mailInfo.getToAddress());    
            mailMessage.setRecipient(Message.RecipientType.TO,to);    
            // 设置邮件消息的主题    
            mailMessage.setSubject(mailInfo.getSubject());    
            // 设置邮件消息发送的时间    
            mailMessage.setSentDate(new Date());    
            // 设置邮件消息的主要内容    
            String mailContent = mailInfo.getContent();    
            mailMessage.setText(mailContent);    
            // 发送邮件    
            Transport.send(mailMessage);   
            return true;    
        }
        catch (MessagingException ex)
        {    
            ex.printStackTrace();    
        }    
        return false;    
    }   

发送邮件主要是使用了mail.jar包里面的方法,首先会使用MyAuthenticator类判断一些用户验证信息,然后就是设置我们上面收集的邮件信息,最后会调用Transport.send()方法发送我们设置好的邮件。

跟我我个人测试效果,我是用QQ邮箱测试,发送的速度很快,调用发送接口,基本马上就能收到邮件了。下面提供的Demo例子里面也是基于QQ邮箱的,你可以根据需要修改一些邮箱参数(smtp、端口等信息)发送到其他邮箱服务器。利用这种方法,结合我前面一篇收集程序异常信息的文章,就可以把收集的异常信息发送到我们指定邮箱。

最后需要说明一点是,如果你是直接在后台发送邮件,最好给用户一个提示,或者让用户选择是否发送。否则容易背上流氓软件或者后台偷跑流量的骂名,O(∩_∩)O哈!另外也需要注意发送邮件的频率,避免发送太频繁,邮件服务商把你邮件屏蔽了。

android后台发送邮件类分享

public class SendEmail {
    private static final String TAG = "SendEmail";
    //要发送Email地址
    private String mailTo = null;
    //邮件发送来源地址
    private String mailFrom = null;
    //SMTP主机地址
    private String smtpHost = null;
    //是否启用调试
    private boolean debug = false;

    private String messageBasePath = null;
    //Email主题
    private String subject;

    public void setMailTo(String mailTo) {
        this.mailTo = mailTo;
    }

    public void setMailFrom(String mailFrom) {
        this.mailFrom = mailFrom;
    }

    public void setSmtpHost(String smtpHost) {
        this.smtpHost = smtpHost;
    }

    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    public void setMessageBasePath(String messageBasePath) {
        this.messageBasePath = messageBasePath;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public void setMsgContent(String msgContent) {
        this.msgContent = msgContent;
    }

    public void setAttachedFileList(Vector attachedFileList) {
        this.attachedFileList = attachedFileList;
    }

    public void setEmailAccount(String emailAccount) {
        this.emailAccount = emailAccount;
    }

    public void setEmailPwd(String emailPwd) {
        this.emailPwd = emailPwd;
    }

    public void setMessageContentType(String messageContentType) {
        this.messageContentType = messageContentType;
    }

    public void setEmailbccTo(String emailbccTo) {
        this.emailbccTo = emailbccTo;
    }

    public void setEmailccTo(String emailccTo) {
        this.emailccTo = emailccTo;
    }

    //Email内容
    private String msgContent;

    private Vector attachedFileList;
    private String emailAccount = null;
    private String emailPwd = null;
    private String messageContentType = "text/html;charset=utf-8";

    private String emailbccTo = null;
    private String emailccTo = null;

    /*
    默认构造函数
     */
    public SendEmail() {
        super();
    }

    private void writeEmail(Session session, Message message) throws MessagingException {
        String fileName;
        Multipart multipart = new MimeMultipart();
        //设定发件人地址
        if (mailFrom != null) {
            message.setFrom(new InternetAddress(mailFrom));
            Log.i(TAG, "发件人邮件地址:" + mailFrom);
        } else {
            Log.i(TAG, "没有指定发件人邮件地址");
            return;
        }
        //设定收件人地址
        if (mailTo != null) {
            message.setRecipient(Message.RecipientType.TO, new InternetAddress(mailTo));
            Log.i(TAG, "收件人邮件地址:" + mailTo);
        } else {
            Log.i(TAG, "没有指定收件人邮件地址");
            return;
        }
        //设定抄送地址
        if (emailccTo != null) {
            message.setRecipient(Message.RecipientType.CC, new InternetAddress(emailccTo));
            Log.i(TAG, "抄送邮件地址:" + emailccTo);
        } else {
            Log.i(TAG, "没有指定抄送邮件地址");
            return;
        }
        //设定密送地址
        if (emailbccTo != null) {
            message.setRecipient(Message.RecipientType.BCC, new InternetAddress(emailbccTo));
            Log.i(TAG, "密送邮件地址:" + emailbccTo);
        } else {
            Log.i(TAG, "没有指定密送邮件地址");
            return;
        }
        //设置邮件主题
        message.setSubject(subject);
        Log.i(TAG, "邮件主题:" + subject);
        //设置回复地址
        message.setReplyTo(new InternetAddress[]{new InternetAddress(mailFrom)});
        //创建并设置第一部分
        MimeBodyPart bodyPart = new MimeBodyPart();
        if (msgContent != null) {
            Log.i(TAG, "邮件内容:" + msgContent);
            bodyPart.setContent(msgContent, messageContentType);
        } else {
            bodyPart.setContent("", messageContentType);
        }
        multipart.addBodyPart(bodyPart);
        //附件文件到邮件中
        if (attachedFileList != null) {
            for (Enumeration fileList = attachedFileList.elements(); fileList.hasMoreElements(); ) {
                fileName = (String) fileList.nextElement();
                MimeBodyPart mBodyPart = new MimeBodyPart();

                FileDataSource fds = new FileDataSource(messageBasePath + fileName);
                Log.i(TAG, "Email发送的附件为:" + messageBasePath + fileName);
                mBodyPart.setDataHandler(new DataHandler(fds));
                mBodyPart.setFileName(fileName);
                multipart.addBodyPart(mBodyPart);
            }
        }
        Log.i(TAG, "设置邮件部分");
        message.setContent(multipart);
        message.setSentDate(new Date());
    }

    /**
     * 发送邮件方法
     *
     * @return true 表示发送成功,false表示不成功
     */
    public boolean sendEmail() {
        int loopCount;
        Properties properties = System.getProperties();
        properties.setProperty("mail.smtp.host", smtpHost);
        properties.setProperty("mail.smtp.auth", "true");
        properties.put("mail.smtp.port", "25");
        MailAuthenticator authenticator = new MailAuthenticator();
        Session session = Session.getInstance(properties, authenticator);
        session.setDebug(debug);
        MimeMessage mimeMessage = new MimeMessage(session);

//这里如果用Transport的话会出现错误
        SMTPTransport transport = new SMTPTransport(session, new URLName("smtp", "smtp.qq.com", 25, null, MailAuthenticator.TENCENT_EMAIL_USER, MailAuthenticator.TENCENT_EMAIL_PWD));
        try {
            writeEmail(session, mimeMessage);
            //transport = session.getTransport("smtp");
            try {
                Log.i(TAG, "开始连接服务器");
                transport.connect(smtpHost, 25, MailAuthenticator.TENCENT_EMAIL_USER, MailAuthenticator.TENCENT_EMAIL_PWD);
            } catch (AuthenticationFailedException e) {
                e.printStackTrace();
                Log.i(TAG, "连接服务器失败");
                return false;
            } catch (MessagingException e) {
                e.printStackTrace();
                Log.i(TAG, "发送邮件过程中出现错误");
                return false;
            }
            Log.i(TAG, "开始发送邮件");
            transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
            transport.close();
            Log.i(TAG, "关闭连接");
        } catch (MessagingException e) {
            e.printStackTrace();
            Log.i(TAG, "发送邮件失败");
            return false;
        } finally {
            try {
                if (transport != null && transport.isConnected()) {
                    transport.close();
                    Log.i(TAG, "在finally中关闭连接");
                }
            } catch (MessagingException e) {
                e.printStackTrace();
            }
        }
        Log.i(TAG, "邮件发送成功");
        return true;
    }
}

tips---其中的MyAuthenticator类继承自Authenticator,重写这个方法即可

@Override
protected PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(邮箱用户名,密码);
}



密码字符串在开发过程中很常见,本文我们来分享在android开发时如何用MD5和SHA1加密,文章后面提示加密实例。


首先,我们来分享MD5和SHA1加密的函数。

public class MD5 {

private static String key = "a6U&1$Ip[Jr/sed]Rfvn=O>Mz+}lXN*%-gLcGD|0";

//MD5加密实例
public static String getMD5(String str) throws NoSuchAlgorithmException {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
e.printStackTrace();
return "";
}
char[] charArray = str.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++) {
byteArray[i] = (byte) charArray[i];
}
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}



public static String byte2hex(byte[] b) {
String hs = "";
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1) {
hs = hs + "0" + stmp;
} else {
hs = hs + stmp;
}
}
return hs;
}

//SHA1 加密实例
public static  String encryptToSHA(String info) {
byte[] digesta = null;
try {
// 得到一个SHA-1的消息摘要
MessageDigest alga = MessageDigest.getInstance("SHA-1");
// 添加要进行计算摘要的信息
alga.update(info.getBytes());
// 得到该摘要
digesta = alga.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 将摘要转为字符串
String rs = byte2hex(digesta);
return rs + key;
}
}

android手机安装包频繁提示解析错误怎么解决呢?解析错误一下是包有问题或不是安卓系统所支持的安装包了,下面我们一起来看问题的一个解决办法。

 Android操作系统作为目前唯一可以与苹果iOS系统平分秋色的一款新生系统,它之所以成长的如此之快,除了其很强的开源性,Android系统一个很大的优势就在于其海量增长的应用程序。一款好玩的应用程序是充实闲暇时光的一柄利器,当我们新入手一款Android手机,慢慢熟悉后或多或少都会想到丰富其内置的应用程序,看到好玩的游戏或软件都会想要下载安装。而如果大家的Android手机在安装apk程序途中弹出“解析包时出现问题”这样的提示,会不会觉得很揪心呢?那么Android解析包出现问题有没有好的解决办法呢?

安卓android手机安装包频繁提示解析错误解决方法1

    安卓android手机安装包频繁提示解析错误解决方法介绍:

一、应用程序本身问题

  Android apk程序解析包出现问题的话,可能是由于你下载的apk程序本身就有问题,程序的压缩包可能在下载过程中被损坏了,建议请重新下载一次。

二、系统版本不支持

  如果重新下载也解决不了Android解析包出现问题的话,很大一个可能就是在于你的手机的配置参数不支持这款软件,举个例子吧,如果一款apk程序的系统版本要求在Android 4.0以上,而你的手机则是Android 2.3系统,就会出现“解析包时出现问题”这样的解析错误。

安卓android手机安装包频繁提示解析错误解决方法2

三、RE管理器设置问题

  进入RE管理器——设置——常规设置——主文件夹选项,有的网友反映如果将其设置成“sdcard\ ”就会出现“解析包出现问题”的错误提示,而如果将其设置“\ ”就可以成功安装,大家也可以试试!

安卓android手机安装包频繁提示解析错误解决方法3

以上就是安卓android手机安装包频繁提示解析错误解决方法的全部内容,遇到这种情况的朋友可以照着以上方法进行尝试!

Andriod开发AsyncHttpClient类是异步的,我们可以通过AsyncHttpClient实例请求网络,比如get、post等。

AsyncHttpClient client = newAsyncHttpClient();
 client.get("http://www.google.com", newAsyncHttpResponseHandler() {
 @Override
 public void onSuccess(String response) {
   System.out.println(response);
 }

});



通过AsyncHttpClient类的实例就可以执行网络请求,包括get、put、post、head、delete。并指定一个ResponseHandlerInterface的实例接收请求结果。(onSuccess参数不对,此处只说明基本用法,详细参数看源码)


主要类介绍

    AsyncHttpRequest

继承自Runnabler,被submit至线程池执行网络请求并发送start,success等消息

    AsyncHttpResponseHandler

接收请求结果,一般重写onSuccess及onFailure接收请求成功或失败的消息,还有onStart,onFinish等消息

    TextHttpResponseHandler

继承自AsyncHttpResponseHandler,只是重写了AsyncHttpResponseHandler的onSuccess和onFailure方法,将请求结果由byte数组转换为String

    JsonHttpResponseHandler

继承自TextHttpResponseHandler,同样是重写onSuccess和onFailure方法,将请求结果由String转换为JSONObject或JSONArray

    BaseJsonHttpResponseHandler

继承自TextHttpResponseHandler,是一个泛型类,提供了parseResponse方法,子类需要提供实现,将请求结果解析成需要的类型,子类可以灵活地使用解析方法,可以直接原始解析,使用gson等。

    RequestParams

请求参数,可以添加普通的字符串参数,并可添加File,InputStream上传文件

    AsyncHttpClient

核心类,使用HttpClient执行网络请求,提供了get,put,post,delete,head等请求方法,使用起来很简单,只需以url及RequestParams调用相应的方法即可,还可以选择性地传入Context,用于取消Content相关的请求,同时必须提供ResponseHandlerInterface(AsyncHttpResponseHandler继承自ResponseHandlerInterface)的实现类,一般为AsyncHttpResponseHandler的子类,AsyncHttpClient内部有一个线程池,当使用AsyncHttpClient执行网络请求时,最终都会调用sendRequest方法,在这个方法内部将请求参数封装成AsyncHttpRequest(继承自Runnable)交由内部的线程池执行。

    SyncHttpClient

继承自AsyncHttpClient,同步执行网络请求,AsyncHttpClient把请求封装成AsyncHttpRequest后提交至线程池,SyncHttpClient把请求封装成AsyncHttpRequest后直接调用它的run方法。


请求流程

    调用AsyncHttpClient的get或post等方法发起网络请求

    所有的请求都走了sendRequest,在sendRequest中把请求封装为了AsyncHttpRequest,并添加到线程池执行

    当请求被执行时(即AsyncHttpRequest的run方法),执行AsyncHttpRequest的makeRequestWithRetries方法执行实际的请求,当请求失败时可以重试。并在请求开始,结束,成功或失败时向请求时传的ResponseHandlerInterface实例发送消息

    基本上使用的都是AsyncHttpResponseHandler的子类,调用其onStart,onSuccess等方法返回请求结果

详细使用方法

官方建议使用一个静态的AsyncHttpClient,像下面的这样:

public class TwitterRestClient {
 private static final String BASE_URL = "http://api.twitter.com/1/";
 private static AsyncHttpClient client = newAsyncHttpClient();

 public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
 client.get(getAbsoluteUrl(url), params, responseHandler);
}
public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
 client.post(getAbsoluteUrl(url), params, responseHandler);
}
private static String getAbsoluteUrl(String relativeUrl) {
 return BASE_URL + relativeUrl;
}
}

封装的方法建议都加上Context参数,以在Activity pause或stop时取消掉没用的请求。

详细使用方法就不说了,直接看官方文档


其他说明及总结

Android-Async-Http的使用非常简单,通过AsyncHttpClient发起请求就可以了,如果需要添加参数,直接传一个RequestParams过去,而且参数可以是String、File和InputStream,可以很方便地上传文件。

每个请求都需要传一个ResponseHandlerInterface的实例用以接收请求结果或请求失败,请求结束等通知,一般是AsyncHttpResponseHandler的子类。

通过BinaryHttpResponseHandler可以发起二进制请求,如请求图片。

通过TextHttpResponseHandler可以发起返回结果为字符串的请求,一般这个使用较多。

也可以使用它的子类JsonHttpResponseHandler,返回结果是一个JSONObject或JSONArray。不过感觉这个类作用不大,一是有另一个类BaseJsonHttpResponseHandler,可以直接解析返回的JSON数据,二是JsonHttpResponseHandler的方法太复杂了,有太多的onSuccess和onFailure方法,都不知道重写哪个了。


如上图所示,每个子类有太多的onSuccess和onFailure了,尤其是JsonHttpResponseHandler,这应该算是这个类库的不足吧。所以平时使用时基本不使用JsonHttpResponseHandler,而是直接使用TextHttpResponseHandler,当然也可以使用BaseJsonHttpResponseHandler。

这个类库还有一点不足,就是onSuccess等方法一般会在主线程执行,其实这么说不严谨,看代码吧:

public AsyncHttpResponseHandler() {

   boolean missingLooper = null == Looper.myLooper();

   // Try to create handler

   if (!missingLooper)

       handler = new ResponderHandler(this);

   else {

       // There is no Looper on this thread so synchronous mode should be used.

       handler = null;

       setUseSynchronousMode(true);

       Log.i(LOG_TAG, "Current thread has not called Looper.prepare(). Forcing synchronous mode.");

   }

   // Init Looper by calling postRunnable without an argument.

   postRunnable(null);

}

可以看到,内部使用了Handler,当新建AsyncHttpResponseHandler的实例的时候会获取当前线程的Looper,如果为空就启用同步模式,即所有的回调都会在执行请求的线程中执行,当在一个普通的后台线程时这样执行是正常的,而我们一般都会在主线程发请请求,结果就是所有的回调都会在主线程中执行,这就限制了我们在onSuccess中执行耗时操作,比如请求成功后将数据持久化到数据库。

不过可以看到创建Handler的时候使用了Looper对象,所以我们就可以改进一下其构造函数,添加一个Looper参数(同步修改子类),这样所有的回调就都会在Looper所在线程执行,这样我们只需要开启一个HandlerThread就行了。但这样和Looper为空时一样有一个弊端,如果要更新UI操作的话,还需要向一个主线程的Handler发送消息让UI更新。还有第二个弊端,所有回调都在同一个HandlerThread中执行,如果一个处理耗时太久会阻塞后面的请求结果处理,如果只是简单地写个数据库影响应该不大,如果真耗时太久,为这个耗时处理再开个线程

为了优化Android应用的启动速度,我们在首次初始化时导入静态数据库到Android应用中。本文就来讲讲如何实现这个功能。

一个Android除了要有好的创意和美观的界面,性能也是很关键的部分,本文讨论的就是第一次启动的速度问题。 Android应用的启动过程不能让用户等待太长时间,个人觉得最好控制在3秒之内。一般来说,内容的初始化是影响Android应用第一次启动速度的主要因素之一,尤其是创建数据库并插入一定数量的初始记录,对于这种问题,最好的办法莫过于在首次初始化时导入静态数据库。

 在Android中导入静态数据库很简单,首先将准备好的静态数据库文件放到Android工程的res目录中的raw子目录下面,如果没有这个子目录的话就手动创建该目录,然后在应用的初始化阶段通过类似下面的代码将数据库文件拷贝到特定的目录下面,假设Android应用的包名是com.test,那么大部分情况下该应用默认的数据库文件位于/data/data/com.test/databases目录下面。


 String dbDirPath = "/data/data/com.test/databases";  

File dbDir = new File(dbDirPath);if(!dbDir.exists())

// 如果不存在该目录则创建    

dbDir.mkdir();

// 打开静态数据库文件的输入流  

InputStream is = context.getResources().openRawResource(R.raw.data);

// 打开目标数据库文件的输出流

FileOutputStream os = new FileOutputStream(dbDirPath+"/data.db");

byte[] buffer = newbyte[1024];

int count = 0;

// 将静态数据库文件拷贝到目的地

while ((count = is.read(buffer)) > 0) {  

os.write(buffer, 0, count);  

}

is.close();  

os.close();


以最近完成的一个应用来看,采用导入静态数据库的方式后,第一次启动时间从将近4秒变成了1秒,效果还是很明显的。  


不过,这种方式是假定所有Android设备的应用安装目录是相同的,而且数据库文件的目录都是/data/data/包名/databases,但是Android的文档中并没有明确规定所有设备具有此种目录结构,所以将静态数据库文件拷贝到一个事先定死的目录的做法还是有一定危险性的。更好的做法是使用Android系统提供的API去解决这个问题,总之,我们要避免的就是使用固定目录,下面是更好的拷贝过程:
复制代码

// 打开静态数据库文件的输入流  

InputStream is = context.getResources().openRawResource(R.raw.data);

// 通过Context类来打开目标数据库文件的输出流,这样可以避免将路径写死。  

FileOutputStream os = context.openFileInput("data.db");

byte[] buffer = newbyte[1024];

int count = 0;

// 将静态数据库文件拷贝到目的地

while ((count = is.read(buffer)) > 0) {  

 os.write(buffer, 0, count);

}

is.close();

os.close();




最终的数据库文件将位于/data/data/com.data/files目录下,需要注意的是,使用Context类的openOrCreateDatabase方法或者SQLiteOpenHelper工具类时,不能再传递数据库的名称作为参数,而是要把数据库文件的全路经传递给它们。

[!--infotagslink--]

相关文章

  • php 中file_get_contents超时问题的解决方法

    file_get_contents超时我知道最多的原因就是你机器访问远程机器过慢,导致php脚本超时了,但也有其它很多原因,下面我来总结file_get_contents超时问题的解决方法总结。...2016-11-25
  • HTTP 408错误是什么 HTTP 408错误解决方法

    相信很多站长都遇到过这样一个问题,访问页面时出现408错误,下面一聚教程网将为大家介绍408错误出现的原因以及408错误的解决办法。 HTTP 408错误出现原因: HTT...2017-01-22
  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • php抓取网站图片并保存的实现方法

    php如何实现抓取网页图片,相较于手动的粘贴复制,使用小程序要方便快捷多了,喜欢编程的人总会喜欢制作一些简单有用的小软件,最近就参考了网上一个php抓取图片代码,封装了一个php远程抓取图片的类,测试了一下,效果还不错分享...2015-10-30
  • ps把文字背景变透明的操作方法

    ps软件是现在非常受大家喜欢的一款软件,有着非常不错的使用功能。这次文章就给大家介绍下ps把文字背景变透明的操作方法,喜欢的一起来看看。 1、使用Photoshop软件...2017-07-06
  • intellij idea快速查看当前类中的所有方法(推荐)

    这篇文章主要介绍了intellij idea快速查看当前类中的所有方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-09-02
  • Mysql select语句设置默认值的方法

    1.在没有设置默认值的情况下: 复制代码 代码如下:SELECT userinfo.id, user_name, role, adm_regionid, region_name , create_timeFROM userinfoLEFT JOIN region ON userinfo.adm_regionid = region.id 结果:...2014-05-31
  • js导出table数据到excel即导出为EXCEL文档的方法

    复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta ht...2013-10-13
  • js基础知识(公有方法、私有方法、特权方法)

    本文涉及的主题虽然很基础,在许多人看来属于小伎俩,但在JavaScript基础知识中属于一个综合性的话题。这里会涉及到对象属性的封装、原型、构造函数、闭包以及立即执行表达式等知识。公有方法 公有方法就是能被外部访问...2015-11-08
  • mysql 批量更新与批量更新多条记录的不同值实现方法

    批量更新mysql更新语句很简单,更新一条数据的某个字段,一般这样写:复制代码 代码如下:UPDATE mytable SET myfield = 'value' WHERE other_field = 'other_value';如果更新同一字段为同一个值,mysql也很简单,修改下where即...2013-10-04
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • c#中分割字符串的几种方法

    单个字符分割 string s="abcdeabcdeabcde"; string[] sArray=s.Split('c'); foreach(string i in sArray) Console.WriteLine(i.ToString()); 输出下面的结果: ab de...2020-06-25
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • ps怎么制作倒影 ps设计倒影的方法

    ps软件是一款非常不错的图片处理软件,有着非常不错的使用效果。这次文章要给大家介绍的是ps怎么制作倒影,一起来看看设计倒影的方法。 用ps怎么做倒影最终效果&#819...2017-07-06
  • PHP 验证码不显示只有一个小红叉的解决方法

    最近想自学PHP ,做了个验证码,但不知道怎么搞的,总出现一个如下图的小红叉,但验证码就是显示不出来,原因如下 未修改之前,出现如下错误; (1)修改步骤如下,原因如下,原因是apache权限没开, (2)点击打开php.int., 搜索extension=ph...2013-10-04
  • 安卓手机wifi打不开修复教程,安卓手机wifi打不开解决方法

    手机wifi打不开?让小编来告诉你如何解决。还不知道的朋友快来看看。 手机wifi是现在生活中最常用的手机功能,但是遇到手机wifi打不开的情况该怎么办呢?如果手机wifi...2016-12-21
  • 连接MySql速度慢的解决方法(skip-name-resolve)

    最近在Linux服务器上安装MySql5后,本地使用客户端连MySql速度超慢,本地程序连接也超慢。 解决方法:在配置文件my.cnf的[mysqld]下加入skip-name-resolve。原因是默认安装的MySql开启了DNS的反向解析。如果禁用的话就不能...2015-10-21
  • js控制页面控件隐藏显示的两种方法介绍

    javascript控制页面控件隐藏显示的两种方法,方法的不同之处在于控件隐藏后是否还在页面上占位 方法一: 复制代码 代码如下: document.all["panelsms"].style.visibility="hidden"; document.all["panelsms"].style.visi...2013-10-13
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • C#方法的总结详解

    本篇文章是对C#方法进行了详细的总结与介绍,需要的朋友参考下...2020-06-25