Android中用HttpClient实现Http请求通信

 更新时间:2016年9月20日 19:57  点击:2772
本文我们需要解决的问题是如何实现Http请求来实现通信,解决Android 2.3 版本以后无法使用Http请求问题,下面请看正文。

Android开发中使用HttpClient来开发Http程序来完成简单的网络通信,其实使用HttpUrlConnection也可以实现,不过HttpClient可以完成HttpUrlConnection的所有功能,并且还自己增加了其他的功能,那相比之下就直接使用HttpClient就得了...Http通信有两种方式,相比大家都清楚,一种是使用GET请求,另一种则是使用POST请求来完成...GET请求可以获取静态页面,也可以把参数放在URL参数后面进行传递...POST与GET不同的地方就在于这里,POST请求无法将数据放到字符串的后面...而是放在Http传递的数据当中...这些参数会通过cookie或者是session来进行传递...POST更加适合传递保密的数据信息...比如说用户的账户密码...这样使用GET方式就不是很合理了...因此把保密的数据信息放入到Http请求数据中更加的安全...

那么Android是如何通过Http请求来实现GET或者是POST请求呢?这里简单的介绍一下...先介绍一下GET方式...如何使用GET请求来获取数据信息....GET请求需要几个步骤...

首先:我们需要建立GET对象...通过创建对象来告诉服务器我们使用的GET请求来获取数据信息的...因为Http请求是以URL的形式进行来完成数据传递的...因此我们需要传递一个URL来实例化对象...我这个地址是服务器上的一个jsp文件...通过使用Http请求来获取JSP界面的数据信息...

String path="http://10.0.2.2:8080/JSP/text.jsp":
HttpGet get=new HttpGet(path);

  然后我们需要使用DefaultHttpClient类中的execute()方法来发送Http GET请求...并返回一个HttpResponse对象,HttpResponse对象的目的是当一个Http连接建立成功之后,我们就可以使用其类中的方法来获取到服务器的响应信息...

HttpClient client=new DefaultHttpClient();
HttpResponse response=client.execute(get);

  最后我们就可以通过HttpResponse对象来获取服务器的响应数据信息了...这里我使用了一个getEntity()方法来返回响应信息,然后获取GET提交的URL后面的数据信息...

if(response.getStatusLine().getStatusCode()==HttpStatuse.SC_OK){
     String result=EntityUtils.toString(resopnse.getEntity());
     tv.setText(result);   
}

   最后我们需要在AndroidManifest.xml文件中配置权限属性...只需要添加<user-permission android:name="android.permission.INTERNET"/>那么简单的举一个小例子来实现Http的GET请求...

  首先我们先写一个JSP页面.....这个页面要在Tomcat上进行发布...当没有参数值进行传递的时候,会显示Your message are wrong!这个信息...

<%
    String name=request.getParameter("name");
    String password=request.getParameter("password");
    if("DARKER".equals(name) && "4968188".equals(password)){
        out.println("Receive name is:"+name);
        out.println("Receive password is:"+password);%>
    Your message are right!
    <%}else{
        out.println("Receive name is:"+name);
        out.println("Receive password is:"+password); %>
        Your message are wrong!
    <%}%>

  然后有了这个东西,我们就可以通过Http传递数据信息来提交数据...然后通过这个界面返回的信息来告知我们服务器响应的信息数据...一个简单的布局文件...就一个文本框...目的就是为了返回服务器的响应信息...

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/msg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

  如何实现才是一个重要的过程...在实现的过程中会出现一个问题,就是在Android2.3版本以后就不允许在主线程中去使用Http请求了...相信大部分的学习资料上都没有这个提示问题,但是确实是存在着这样一个问题的...那么上有政策那么就下有对策...我们可以使用三种方法去解决这个问题...非常的简单,也很好理解...那么既然我们无法在主线程中去使用Http请求,那么我们可以新开启一个线程啊...或者是我们可以去使用异步线程类AsyncTask去实现不就完了吗...还有一种方法就是在主线程中加入某些东西...就是下面的在setContentView()这个函数下面加入的那两句话...但是这种方法在网上说并不是很推荐...因此本人也没怎么研究...其他两种方式先对就很好理解...这三种方式我都进行了列举...只要使用其中的任意一种方式就可以实现Http的GET请求....

package com.example.httpclient;
/* HttpCilent 通过Get与服务器进行通信...
 * HttpClient比HttpUrlConnection更加的有优势...前者能做后者所有能做的事情...
 * 那就干脆就使用这种方式吧....
 *
 *
 * */
import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.StrictMode;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

    /*
     * 由于在Android2.3版本以后就不允许在主线程使用Http请求...
     * 但是我们可以使用其他的方法来解决这个问题...
     * 第一种方法在主线程onCreate()方法中加入StrictMode方法..不过这种方法不被推荐...
     * 第二种使用异步线程AsyncTask<Param,Progress,Result>也可以实现...在异步线程中完成Http请求..
     * 第三种方法单开启一个线程Runnable()来实现,其实也是延续异步线程的思想...
     *
     * */
    private TextView tv;
//    private String path="http://10.0.2.2:8080/JSP/get.jsp?name=DARKER&password=49681888";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
//        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
        tv=(TextView) findViewById(R.id.msg);
        new Thread(runnable).start();
//        HttpGet httpRequest=new HttpGet(path);
//        HttpClient httpcilents=new DefaultHttpClient();
//        try {
//            HttpResponse response=httpcilents.execute(httpRequest);
//            if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
//                String result=EntityUtils.toString(response.getEntity());
//                tv.setText(result);
//            }else{
//                tv.setText("请求错误");
//            }
//        } catch (ClientProtocolException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        } catch (IOException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
    }
    @SuppressWarnings("unused")
    private class http extends AsyncTask<Integer, Integer, Integer>{

        @Override
        protected Integer doInBackground(Integer... params) {
            // TODO Auto-generated method stub
            String url="http://10.0.2.2:8080/JSP/get.jsp?name=DARKER&password=49681888";
            HttpGet hget=new HttpGet(url);
            HttpClient htclient=new DefaultHttpClient();
            try {
                HttpResponse hresonse=htclient.execute(hget);
                if(hresonse.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                    String resul=EntityUtils.toString(hresonse.getEntity());
                    tv.setText(resul);
                }else{
                    tv.setText("连接失败...");
                }
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }
        
    }

    Runnable runnable=new Runnable() {
        
        String path_1="http://10.0.2.2:8080/JSP/get.jsp?name=DARKER&password=49681888";
        @Override
        public void run() {
            // TODO Auto-generated method stub
            HttpGet get=new HttpGet(path_1);
            HttpClient cilent=new DefaultHttpClient();
            try {
                HttpResponse responses=cilent.execute(get);
                if(responses.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                    String result_1=EntityUtils.toString(responses.getEntity());
                    tv.setText(result_1);
                }else{
                    tv.setText("无法获取信息...");
                }
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

   其实上面代码使用异步线程类是没问题的,不过上面的代码会报错,由于我的代码写错了位置...这个错误其实是在doInBackground()方法中出现的...因为在这个方法中是不能够更新控件的数据信息的...这个问题我将在下面进行解决....下面是实现Http的POST请求...然后解决刚才说的问题....下面使用了Handler类...简答的说一下这个类...其实这个类并不是用在这个异步线程类里面的...这个异步线程类内部还有三个没有实现的方法...就是onPreExecute(),publishProgress(),onProgressUpdate()...这三个方法内部都可以完成控件数据信息的更新,唯独这个doInBackground()是无法实现的...使用一个AsyncTask类,再使用Handler是完全没有必要的...其实Handler和AsyncTask是为了实现子线程无法去更新主线程中控件的数据信息而存在的...因为控件对于线程来说是不安全的,因此在子线程中也就无法完成主线程中控件数据信息的更新操作...但是在Android中往往是需要这样做的...因此出现了这两个类去解决这个问题...

  首先说一句主要的事,就是使用到了Runnable并不代表一定使用到了多线程...就拿上面那个Runnable类来说,这个runnable虽然重写了run()方法,并且还在主函数中使用了start进行调用,但是这个线程仍然是属于主线程Activity的,并不属于我们单独开启了一个新的线程,然后去执行任务...这是必然的,否则一定会报错...因为在一个新的线程内部是无法去更新主线程中控件的数据信息的...然后在说一下Handler是如何能够完成在子线程中能够对主线程中的控件完成对数据的更新...首先Handler通过传递Message或者是Runnable对象...一般来说都是Message对数据进行封装...Handler主要用来与Looper进行沟通..把信息加入到特定的Looper消息队列中,或者是获取Looper的信息,然后调用handlemessage方法来对获取的信息进行操作...然后将Message发送到MessageQueue中,MessageQueue是一个线性队列,用来保存获取到的消息数据...当Looper发现MessageQueue中有未处理的信息就将这个信息广播出去...Looper就是对MessageQueue队列中然后主线程Handler接收到信息,然后做相应的处理...最后完成更新操作...这就是实现的一个过程...

package com.example.httpclientpost;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

    TextView tv;
    String result;
    @SuppressLint("HandlerLeak")
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg){
            if(msg.what==1){
                tv.setText(result);
            }else{
                tv.setText("无法连接服务器...");
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv=(TextView) findViewById(R.id.show);
        http h=new http();
        h.execute();
    }
    
    class http extends AsyncTask<Integer, Integer, Integer>{

        String url="http://10.0.2.2:8080/JSP/get.jsp";
        @Override
        protected Integer doInBackground(Integer... params) {
            // TODO Auto-generated method stub
            HttpPost post=new HttpPost(url);
            List<NameValuePair> param=new ArrayList<NameValuePair>();
            param.add(new BasicNameValuePair("name", "DARKER"));
            param.add(new BasicNameValuePair("password", "49681888"));
            try {
                HttpEntity entity=new UrlEncodedFormEntity(param,"gb2312");
                post.setEntity(entity);
                HttpClient client=new DefaultHttpClient();
                HttpResponse response=client.execute(post);
                if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                     result=EntityUtils.toString(response.getEntity());
                     Message msg=new Message();
                     msg.what=1;
                     handler.sendMessage(msg);
                }else{
                    Message msg=new Message();
                    msg.what=0;
                    handler.sendMessage(msg);
                }
            }catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
          
            return null;
        }
        
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

  其实我觉得使用Android中使用AsyncTask这个异步线程类其实就行,因为这个异步线程类是结合了handler+Thread才得以实现的,当然我们也可以使用handler去进行处理,个人推荐还是使用这个异步线程类更好...好了有点说跑题了...返回Http的POST请求,Http的POST请求比GET能多了一点东西,它使用NameValuePair以键值对的形式对数据进行保存...并且POST请求需要制定字符集...否则数据会出现乱码现象...剩下的东西基本就类似了...这样就实现了Http的POST请求

有时我们的Android APP需要内嵌现成的wap手机网站,本文我们来介绍两个Android内嵌wap站的实例方法,而且嵌入的网页后界面效果和app差不多。

我们的内嵌Android APP手机站点m.baidu.com,不能显示标题栏,点击网页的超链接,不会弹出系统自带浏览器。


布局web.xml 在layouts目录下新建布局文件web.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">
<webview android:id="@+id/webView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1.0">
</webview></linearlayout>

布局文件写好了,那么我们开始写代码了,我把整个代码都拷贝到下面

package cn.afcu.sdk;
 
import android.os.Bundle;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
 
public class Web extends MainActivity {
 
private WebView  webView;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.web);
webView  = (WebView)  findViewById(R.id.webView);
openBrowser();
 
webView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url)
{ //  重写此方法表明点击网页里面的链接还是在当前的webview里跳转,不跳到浏览器那边
view.loadUrl(url);
return true;
}
});
}
 
//利用webView的loadUrl方法
public void openBrowser() {
webView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);//滚动条在WebView内侧显示
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);//滚动条在WebView外侧显示
webView.setVerticalScrollBarEnabled(false); //垂直不显示
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.loadUrl("http://www.baidu.com");
}
}



Andriod使用webview控件往APP里内嵌网页

1.布局文件片段:res-layout

<WebView android:id="@+id/Toweb"  
     android:layout_width="fill_parent"  
     android:layout_height="fill_parent" />

2.Java片段:src

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //WebView
        WebView browser=(WebView)findViewById(R.id.Toweb);  
        browser.loadUrl("http://www.baidu.com");  
          
        //设置可自由缩放网页  
        browser.getSettings().setSupportZoom(true);  
        browser.getSettings().setBuiltInZoomControls(true);  
          
        // 如果页面中链接,如果希望点击链接继续在当前browser中响应,  
        // 而不是新开Android的系统browser中响应该链接,必须覆盖webview的WebViewClient对象  
        browser.setWebViewClient(new WebViewClient() {  
            public boolean shouldOverrideUrlLoading(WebView view, String url)  
            {   
                //  重写此方法表明点击网页里面的链接还是在当前的webview里跳转,不跳到浏览器那边  
                view.loadUrl(url);  
                        return true;  
            }         
             });
    }  
    
    //go back
    @Override  
    public boolean onKeyDown(int keyCode, KeyEvent event) {  
        WebView browser=(WebView)findViewById(R.id.Toweb);  
        // Check if the key event was the Back button and if there's history  
        if ((keyCode == KeyEvent.KEYCODE_BACK) && browser.canGoBack()) {  
            browser.goBack();  
            return true;  
        }  
      //  return true;  
        // If it wasn't the Back key or there's no web page history, bubble up to the default  
        // system behavior (probably exit the activity)  
        return super.onKeyDown(keyCode, event);  
    }

3. AndroidManifest.xml 设置权限,否则无法访问

<!--添加该权限,webview可以访问网页-->
<uses-permission android:name="android.permission.INTERNET"></uses-permission> 

本文我们研究一下关于Android获取短信验证码的工作原理,由于短信验证码用来保护个人信息的安全性,在手机app应用非常广范,我们可以认真的学习一下。

短信验证需要服务器端生成一个验证码,然后发送到用户输入的手机上,这个过程需要服务器主动向客户发送验证短信,所以这是就需要一个移动或联通的发送短息接口,由于本人目前尚处于学生阶段,没有获得这个接口的权限,所以我就选择了借助网上的移动开发服务平台,来完成这个功能的实现,这里我借用的平台是:http://dashboard.mob.com/,大家可以关注一下,这个平台为我们开发移动应用提供了很好的技术指导,可以大大缩短我们的开发周期。废话不多说,下面开始我们今天的重点。

官方为我们提供了两种设计方式:第一种调用内部GUI实现;另一种通过自定义GUI实现,对于第一种方式,我就不再多讲,因为官方文档提供了很详细的实行步骤,大家只需要按照上面的步骤去实现即可,没有难度。本篇我将带领大家通过自定义GUI实现短信验证功能。首先开发之前你可以先查阅一下官方提供的无GUI  API,然后下载一下官方提供的dome,做好这些工作之后,我们就可以开始我们的设计了。

  1、将demo中的libs下的SMSSDK-1.1.5.jar和armeabi文件夹拷贝到我们项目的libs目录下,这是官方提供的类库jar包。

  2、在AndroidManifest.xml文件添加权限和声明Action:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android_sms"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
    
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.android_sms.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <activity
            android:name="cn.smssdk.SMSSDKUIShell"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:theme="@android:style/Theme.Translucent.NoTitleBar"
            android:windowSoftInputMode="stateHidden|adjustResize" />
        
    </application>

</manifest>

  3、设计我们的布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20dp"
        android:text="短信验证"
        android:textColor="#00ffaa"
        android:textSize="20dp" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/textView2"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:text="手机号:" />

    <EditText
        android:id="@+id/phone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/textView1"
        android:layout_alignBottom="@+id/textView1"
        android:layout_toRightOf="@+id/textView1"
        android:maxLength="11"
        android:ems="11"
        android:inputType="phone" >
        <requestFocus />
        </EditText>

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_marginTop="40dp"
        android:layout_below="@+id/phone"
        android:text="验证码:"/>

    <EditText
        android:id="@+id/cord"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_alignBaseline="@+id/textView3"
        android:layout_alignBottom="@+id/textView3"
        android:layout_alignLeft="@+id/phone"
        android:ems="4"
        android:maxLength="4"
        android:inputType="phone" />

    <Button
        android:id="@+id/getcord"
        style="?android:attr/buttonStyleSmall"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/cord"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="10dp"
        android:layout_toRightOf="@+id/cord"
        android:visibility="visible"
        android:text="获取验证码" />

    <Button
        android:id="@+id/savecord"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/cord"
        android:layout_margin="20dp"
        android:text="验证" />

    <TextView
        android:id="@+id/now"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_above="@+id/savecord"
        android:layout_toRightOf="@+id/cord"
        android:gravity="center_horizontal"
        android:visibility="gone"
        android:text="提示信息"
        android:textColor="#aaaaaa" />
    
</RelativeLayout>

  4、我们的MainActivity:

/**
 * 自定义GUI短信验证
 * @time: 2015年7月4日
 */
public class MainActivity extends Activity implements OnClickListener{
    
    private EditText phone;
    private EditText cord;
    private TextView now;
    private Button getCord;
    private Button saveCord;
    
    private String iPhone;
    private String iCord;
    private int time = 60;
    private boolean flag = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        init();
        
     SMSSDK.initSDK(this, "<您的appkey>", "<您的appsecret>");
        EventHandler eh=new EventHandler(){

            @Override
            public void afterEvent(int event, int result, Object data) {
                
                Message msg = new Message();
                msg.arg1 = event;
                msg.arg2 = result;
                msg.obj = data;
                handler.sendMessage(msg);
            }
            
        };
        SMSSDK.registerEventHandler(eh);
        
    }

    private void init() {
        phone = (EditText) findViewById(R.id.phone);
        cord = (EditText) findViewById(R.id.cord);
        now = (TextView) findViewById(R.id.now);
        getCord = (Button) findViewById(R.id.getcord);
        saveCord = (Button) findViewById(R.id.savecord);
        getCord.setOnClickListener(this);
        saveCord.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.getcord:
            if(!TextUtils.isEmpty(phone.getText().toString().trim())){
                if(phone.getText().toString().trim().length()==11){
                    iPhone = phone.getText().toString().trim();
                    SMSSDK.getVerificationCode("86",iPhone);
                    cord.requestFocus();
                    getCord.setVisibility(View.GONE);
                }else{
                    Toast.makeText(MainActivity.this, "请输入完整电话号码", Toast.LENGTH_LONG).show();
                    phone.requestFocus();
                }
            }else{
                Toast.makeText(MainActivity.this, "请输入您的电话号码", Toast.LENGTH_LONG).show();
                phone.requestFocus();
            }
            break;

        case R.id.savecord:
            if(!TextUtils.isEmpty(cord.getText().toString().trim())){
                if(cord.getText().toString().trim().length()==4){
                    iCord = cord.getText().toString().trim();
                    SMSSDK.submitVerificationCode("86", iPhone, iCord);
                    flag = false;
                }else{
                    Toast.makeText(MainActivity.this, "请输入完整验证码", Toast.LENGTH_LONG).show();
                    cord.requestFocus();
                }
            }else{
                Toast.makeText(MainActivity.this, "请输入验证码", Toast.LENGTH_LONG).show();
                cord.requestFocus();
            }
            break;
            
        default:
            break;
        }
    }
    
    //验证码送成功后提示文字
    private void reminderText() {
        now.setVisibility(View.VISIBLE);
        handlerText.sendEmptyMessageDelayed(1, 1000);
    }

    Handler handlerText =new Handler(){
        public void handleMessage(Message msg) {
            if(msg.what==1){
                if(time>0){
                    now.setText("验证码已发送"+time+"秒");
                    time--;
                    handlerText.sendEmptyMessageDelayed(1, 1000);
                }else{
                    now.setText("提示信息");
                    time = 60;
                    now.setVisibility(View.GONE);
                    getCord.setVisibility(View.VISIBLE);
                }
            }else{
                cord.setText("");
                now.setText("提示信息");
                time = 60;
                now.setVisibility(View.GONE);
                getCord.setVisibility(View.VISIBLE);
            }
        };
    };
    
    Handler handler=new Handler(){

        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            int event = msg.arg1;
            int result = msg.arg2;
            Object data = msg.obj;
            Log.e("event", "event="+event);
            if (result == SMSSDK.RESULT_COMPLETE) {
                //短信注册成功后,返回MainActivity,然后提示新好友
                if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE) {//提交验证码成功,验证通过
                    Toast.makeText(getApplicationContext(), "验证码校验成功", Toast.LENGTH_SHORT).show();
                    handlerText.sendEmptyMessage(2);
                } else if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE){//服务器验证码发送成功
                    reminderText();
                    Toast.makeText(getApplicationContext(), "验证码已经发送", Toast.LENGTH_SHORT).show();
                }else if (event ==SMSSDK.EVENT_GET_SUPPORTED_COUNTRIES){//返回支持发送验证码的国家列表
                    Toast.makeText(getApplicationContext(), "获取国家列表成功", Toast.LENGTH_SHORT).show();
                }
            } else {
                if(flag){
                    getCord.setVisibility(View.VISIBLE);
                    Toast.makeText(MainActivity.this, "验证码获取失败,请重新获取", Toast.LENGTH_SHORT).show();
                    phone.requestFocus();
                }else{
                    ((Throwable) data).printStackTrace();
                    int resId = getStringRes(MainActivity.this, "smssdk_network_error");
                    Toast.makeText(MainActivity.this, "验证码错误", Toast.LENGTH_SHORT).show();
                    cord.selectAll();
                    if (resId > 0) {
                        Toast.makeText(MainActivity.this, resId, Toast.LENGTH_SHORT).show();
                    }
                }
                
            }
            
        }
        
    };
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        SMSSDK.unregisterAllEventHandler();
    }

}

  注:appkey和appsecret:在http://dashboard.mob.com/注册一个账号后,创建一个发送短信的应用,系统会自动为生成appkey和appsecret

    handlerText是我自定义设计的Handker对象,用于当服务器发送验证码后,提醒用户注意。

  最后附图两张,供大家参考:





android获取短信验证码并自动填写的实现

现在的应用在注册登录或者修改密码中都用到了短信验证码,那在android中是如何实现获取短信验证码并自动填写的呢?

首先,需要要在manifest中注册接收和读取短信的权限:

    <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
    <uses-permission android:name="android.permission.READ_SMS"/>


实现一个广播SMSBroadcastReceiver来监听短信:

package com.example.receive;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsMessage;


/**
 * 短信监听
 * @author
 *
 */
public class SMSBroadcastReceiver extends BroadcastReceiver {
    
    private static MessageListener mMessageListener;
    public static final String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";
    
    public SMSBroadcastReceiver() {
        super();
    }

    @Override
    public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(SMS_RECEIVED_ACTION)) {
                Object[] pdus = (Object[]) intent.getExtras().get("pdus");
                for(Object pdu:pdus) {
                    SmsMessage smsMessage = SmsMessage.createFromPdu((byte [])pdu);
                    String sender = smsMessage.getDisplayOriginatingAddress();
                    //短信内容
                    String content = smsMessage.getDisplayMessageBody();
                    long date = smsMessage.getTimestampMillis();
                    Date tiemDate = new Date(date);
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String time = simpleDateFormat.format(tiemDate);

                    //过滤不需要读取的短信的发送号码
                    if ("+8613450214963".equals(sender)) {
                        mMessageListener.onReceived(content);
                        abortBroadcast();
                    }
                }
            }
        
    }
    
    //回调接口
    public interface MessageListener {
        public void onReceived(String message);
    }
    
    public void setOnReceivedMessageListener(MessageListener messageListener) {
        this.mMessageListener = messageListener;
    }
}


在需要填写验证码的Activity中,生产SMSBroadcastReceiver的实例,实现onReceived的回调接口。为了节约系统资源,我们使用动态注册注销广播的方法。

package com.example.smstest;

import com.example.receive.SMSBroadcastReceiver;

import android.os.Bundle;
import android.app.Activity;
import android.content.IntentFilter;
import android.view.Menu;
import android.widget.EditText;

public class MainActivity extends Activity {
    
    private EditText edtPassword;
    private SMSBroadcastReceiver mSMSBroadcastReceiver;
    
    private static final String ACTION = "android.provider.Telephony.SMS_RECEIVED";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        edtPassword = (EditText) findViewById(R.id.password);
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        //生成广播处理
        mSMSBroadcastReceiver = new SMSBroadcastReceiver();

        //实例化过滤器并设置要过滤的广播
        IntentFilter intentFilter = new IntentFilter(ACTION);
        intentFilter.setPriority(Integer.MAX_VALUE);
        //注册广播
        this.registerReceiver(mSMSBroadcastReceiver, intentFilter);

        mSMSBroadcastReceiver.setOnReceivedMessageListener(new SMSBroadcastReceiver.MessageListener() {
            @Override
            public void onReceived(String message) {

                edtPassword.setText(message);

            }
        });
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
         //注销短信监听广播
        this.unregisterReceiver(mSMSBroadcastReceiver);
    }


}

PopupWindow在android.widget包下,弹出窗口的形式展示。PopupWindow弹出的菜单随内容的宽度自适应,重写ListView的onMeasure()方法是个不错的解决办法。

PopupWindow用法

使用PopupWindow可实现弹出窗口效果,,其实和AlertDialog一样,也是一种对话框,两者也经常混用,但是也各有特点。下面就看看使用方法。
首先初始化一个PopupWindow,指定窗口大小参数。

PopupWindow mPop = new PopupWindow(getLayoutInflater().inflate(R.layout.window, null),
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
也可以分开写:
LayoutInflater mLayoutInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
//自定义布局
ViewGroup menuView = (ViewGroup) mLayoutInflater.inflate(
                    R.layout.window, null, true);
PopupWindow mPop = new PopupWindow(menuView, LayoutParams.WRAP_CONTENT,
                    LayoutParams.WRAP_CONTENT, true);
当然也可以手动设置PopupWindow大小。
mPop.setContentView(menuView );//设置包含视图
mPop.setWidth(int )
mPop.setHeight(int )//设置弹出框大小

设置进场动画:
mPop.setAnimationStyle(R.style.AnimationPreview);//设置动画样式


mPop.setOutsideTouchable(true);//这里设置显示PopuWindow之后在外面点击是否有效。如果为false的话,那么点击PopuWindow外面并不会关闭PopuWindow。当然这里很明显只能在Touchable下才能使用。

当有mPop.setFocusable(false);的时候,说明PopuWindow不能获得焦点,即使设置设置了背景不为空也不能点击外面消失,只能由dismiss()消失,但是外面的View的事件还是可以触发,back键也可以顺利dismiss掉。当设置为popuWindow.setFocusable(true);的时候,加上下面两行设置背景代码,点击外面和Back键才会消失。
mPop.setFocusable(true);
需要顺利让PopUpWindow dimiss(即点击PopuWindow之外的地方此或者back键PopuWindow会消失);PopUpWindow的背景不能为空。必须在popuWindow.showAsDropDown(v);或者其它的显示PopuWindow方法之前设置它的背景不为空:

mPop.setBackgroundDrawable(new ColorDrawable(0));



mPop.showAsDropDown(anchor, 0, 0);//设置显示PopupWindow的位置位于View的左下方,x,y表示坐标偏移量

mPop.showAtLocation(findViewById(R.id.parent), Gravity.LEFT, 0, -90);(以某个View为参考),表示弹出窗口以parent组件为参考,位于左侧,偏移-90。
mPop.setOnDismissListenerd(new PopupWindow.OnDismissListener(){})//设置窗口消失事件

注:window.xml为布局文件

总结:

1、为PopupWindow的view布局,通过LayoutInflator获取布局的view.如:

LayoutInflater inflater =(LayoutInflater)            

this.anchor.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

View textEntryView =  inflater.inflate(R.layout.paopao_alert_dialog, null);

       

2、显示位置,可以有很多方式设置显示方式

pop.showAtLocation(findViewById(R.id.ll2), Gravity.LEFT, 0, -90);

或者

pop.showAsDropDown(View anchor, int xoff, int yoff)

 

3、进出场动画

pop.setAnimationStyle(R.style.PopupAnimation);

 

4、点击PopupWindow区域外部,PopupWindow消失

   this.window = new PopupWindow(anchor.getContext());

 

this.window.setTouchInterceptor(new OnTouchListener() {

@Override

public boolean onTouch(View v, MotionEvent event) {

if(event.getAction() ==MotionEvent.ACTION_OUTSIDE) {              

BetterPopupWindow.this.window.dismiss();

return true;

}

return false;

}

});



PopupWindow 自适应宽度实例


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        
     int maxWidth = meathureWidthByChilds() + getPaddingLeft() + getPaddingRight(); super.onMeasure(MeasureSpec.makeMeasureSpec(maxWidth,MeasureSpec.EXACTLY),heightMeasureSpec);   
}   
   public int meathureWidthByChilds() {     
      int maxWidth = 0;    
      View view = null;
      for (int i = 0; i < getAdapter().getCount(); i++) {
           view = getAdapter().getView(i, view, this);     
           view.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);     
      if (view.getMeasuredWidth() > maxWidth){        
         maxWidth = view.getMeasuredWidth();    
      }       
  }       
   return maxWidth;  
}



PopupWindow自适应布局

Android自带的Menu菜单,常常无法满足我们的需求,所以就只有自己写menu菜单,通常的选择是用PopupWindow来实现自定义的menu菜单,先看代码,再来说明要注意的几点:

    View menuView = inflater.inflate(R.layout.menu_popwindow, null);  
    final PopupWindow p = new PopupWindow(mContext);  
    p.setContentView(menuView);  
    p.setWidth(ViewGroup.LayoutParams.FILL_PARENT);  
    p.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);  
    p.setAnimationStyle(R.style.MenuWindow);  
    p.setOnDismissListener(this);  
    p.setOutsideTouchable(false);  
    p.setBackgroundDrawable(new ColorDrawable(android.R.color.transparent));  
    p.setFocusable(true); // 如果把焦点设置为false,则其他部份是可以点击的,也就是说传递事件时,不会先走PopupWindow  
      
    mPopwindow = p;  

来说明其中的几点:

  1. 为了让PopupWindow自适应屏幕的宽度,设置宽度时用ViewGroup.LayoutParams.FILL_PARENT,为了自适应子布局的高度,设置高度时用ViewGroup.LayoutParams.WRAP_CONTENT

  2. 由于PopupWindow类没有继承ViewGroup类,所以inflater.inflate(int resource, ViewGroup root)方法的第二个参数只能传为null,传null会使最外层布局的android:layout_xxx都不起作用。所以高度是以第二层布局为主

  3. 为了设置背景和边距,其背景只能设置在第二层布局里,因第一层布局的android:layout_marginXxx不起作用,而设置android:padding_Xxx不会影响背景。

  4. menu有一个特点,就是点外部,menu菜单要消失,要实现这个,有几个属性要一起设置:p.setOutsideTouchable(false);p.setBackgroundDrawable();p.setFocusable(true);

Genymotion是一套完整的工具,它提供了Android虚拟环境。它简直就是开发者、测试人员、推销者甚至是游戏玩家的福音。而且Genymotion支持Windows、Linux和Mac OS等操作系统,容易安装和使用,本文就来看看 Genymotion 安装使用图解教程.

Genymotion模拟器提供了Android虚拟环境,为安卓开发测试人员带来了极大的便利。Genymotion的启动速度比Eclipse自带的模拟器要快得多,运行起来非常的流畅,堪称Eclipse拥趸的调试神器!

Genymotion兼容的操作系统有:Microsoft Windows 32/64 bits、Mac OSX 10.5+ 、 Linux 32/64 bits

Genymotion官网:https://www.genymotion.com 


Android Studio本身的模拟器已经很强大,所以Genymotion还是配合Eclipse使用比较多一点,下面也是基于Eclipse编辑器进行讲解。

1、翻墙

Genymotion的使用需要注册账户并登录,但如果没有翻墙的话,注册和登录都是很难操作成功的。

在这里介绍个VPN,可以免费使用一段时间,足够安装完环境了。

Green VPN官网:https://www.igreenjsq.co

在官网注册一个账户,打开注册时填写的邮箱激活一下账户。下载PC客户端,登录账号,直接点击“链接”按钮:


VPN连接成功了,但对于一个程序员来说,上个技术类的网站都要翻墙,简直是一种耻辱!

2、注册账号并下载安装Genymotion

Genymotion基于VirtualBox虚拟机才能运行,在下载Genymotion时应选择相应的版本(软件下载不需要翻墙):


“Get Genymotion (without VirtualBox) (24.03MB)”版本适合于已经安装了VirtualBox的电脑,“Get Genymotion (126.02MB)”版本适合于尚未安装VirtualBox的电脑,安装该版本完成的时候会提示是否安装VirtualBox环境,点击“是”按钮,就顺带的把VirtualBox也安装了:


3、添加虚拟机

运行Genymotion,软件会提示是否添加一个虚拟设备:


点击“Yes”,弹出登录界面:


动不动就要登录,这也是我非常想吐槽的一个地方!

如果安装了翻墙软件,登录是没问题的;没有安装翻墙软件的话,也可以在网上找一个代理IP,设置一下:


登录成功后会出现一个设备列表:


选择需要用到的虚拟设备进行安装,120MB左右一个,下载过程可以不开VPN。

4、Eclipse安装Genymotion插件


Name:Genymobile Location:http://plugins.genymotion.com/eclipse/ ,点击“OK”


选择并下载(记得开VPN):


安装完成,重新启动Eclipse,可以看到重启后软件界面多了一个小图标:


点击图标,提示需要配置Genymotion安装的目录:


点击“OK”,进入配置界面:


点击“OK”进入虚拟设备选择界面,选择相应的虚拟设备,并启动:


Genymotion启动成功:


运行一个测试程序:


程序已经成功的在Genymotion模拟器中运行了:


PS:关闭Genymotion运行程序的话,默认启动的是Eclipse自带的模拟器。

现在,我们的Genymotion模拟器安装就告一段落了。


[!--infotagslink--]

相关文章

  • php语言实现redis的客户端

    php语言实现redis的客户端与服务端有一些区别了因为前面介绍过服务端了这里我们来介绍客户端吧,希望文章对各位有帮助。 为了更好的了解redis协议,我们用php来实现...2016-11-25
  • Spring Cloud 中@FeignClient注解中的contextId属性详解

    这篇文章主要介绍了Spring Cloud 中@FeignClient注解中的contextId属性详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-25
  • jQuery+jRange实现滑动选取数值范围特效

    有时我们在页面上需要选择数值范围,如购物时选取价格区间,购买主机时自主选取CPU,内存大小配置等,使用直观的滑块条直接选取想要的数值大小即可,无需手动输入数值,操作简单又方便。HTML首先载入jQuery库文件以及jRange相关...2015-03-15
  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • 解决Feign切换client到okhttp无法生效的坑(出现原因说明)

    这篇文章主要介绍了解决Feign切换client到okhttp无法生效的坑(出现原因说明),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-25
  • JS实现的简洁纵向滑动菜单(滑动门)效果

    本文实例讲述了JS实现的简洁纵向滑动菜单(滑动门)效果。分享给大家供大家参考,具体如下:这是一款纵向布局的CSS+JavaScript滑动门代码,相当简洁的手法来实现,如果对颜色不满意,你可以试着自己修改CSS代码,这个滑动门将每一...2015-10-21
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • jQuery+slidereveal实现的面板滑动侧边展出效果

    我们借助一款jQuery插件:slidereveal.js,可以使用它控制面板左右侧滑出与隐藏等效果,项目地址:https://github.com/nnattawat/slideReveal。如何使用首先在页面中加载jquery库文件和slidereveal.js插件。复制代码 代码如...2015-03-15
  • Android WebView加载html5页面实例教程

    如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
  • PHP+jQuery翻板抽奖功能实现

    翻板抽奖的实现流程:前端页面提供6个方块,用数字1-6依次表示6个不同的方块,当抽奖者点击6个方块中的某一块时,方块翻转到背面,显示抽奖中奖信息。看似简单的一个操作过程,却包含着WEB技术的很多知识面,所以本文的读者应该熟...2015-10-21
  • 深入理解Android中View和ViewGroup

    深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • Android用MemoryFile文件类读写进行性能优化

    java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
  • SQLMAP结合Meterpreter实现注入渗透返回shell

    sqlmap 是一个自动SQL 射入工具。它是可胜任执行一个广泛的数据库管理系统后端指印, 检索遥远的DBMS 数据库等,下面我们来看一个学习例子。 自己搭建一个PHP+MYSQ...2016-11-25
  • 自定义feignClient的常见坑及解决

    这篇文章主要介绍了自定义feignClient的常见坑及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-10-20
  • Android设置TextView竖着显示实例

    TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
  • android.os.BinderProxy cannot be cast to com解决办法

    本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20