魔乐科技安卓开发教程----李兴华----20 网络通信之与web服务器交换数据

1.通过地址重写访问动态Web

这里使用Tomcat服务器,本地网站地址为:
http://localhost:8080/fengray/
但实际访问不能使用本地主机地址,不能是127.0.0.1或localhost,而应当是ipv4地址诸如本例的192.168.221.124

1、在服务器端创建一个android.jsp页面。

<%//接受发送过来的请求
	String id=request.getParameter("id");
	String password=request.getParameter("password");
%>

<%
	if("ncepu".equals(id) && "ncepup".equals(password)){
%>
	true	
<%	
	}else{
%>
	false	
<%    	
		}
%>

地址栏输入:
http://localhost:8080/fengray/android.jsp?id=ncepu&password=ncepup

返回:true

需要做的是,在手机中将以上地址提交到android.jsp页面

2、添加网络访问授权及解决android9以后关于网络连接失败的bug

解决两个android9以后关于网络连接失败的bug


1、android9不可以明文访问网络的解决思路

  • 在res目录下创建xml目录并创建network_security_config.xml(名字可自定义)
  • 文件内容为:
  <?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:android="http://schemas.android.com/apk/res/android">
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>
  • 在Manifest文件中申明名字空间
    xmlns:tools=“http://schemas.android.com/tools”
    同时在application标签中添加以下两项属性
    ndroid:networkSecurityConfig="@xml/network_security_config"
    tools:replace=“android:networkSecurityConfig”

2、还需要解决一个主线程不能访问网络连接的问题
如下介绍,选择第二种方法:
在做一个博客App遇到一个错误,刚开始怎么都解决不了,因为代码没有问题但总是报错。最后查阅资料了解到,在Android 4.0以上,网络连接不能放在主线程上,不然就会报错android.os.NetworkOnMainThreadException。

解决此问题有两种解决的方法:
1.可以再Activity的onCreate()方法中加入这样一段代码,适用于网络请求数据量很小的话,如下

if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
2.启动一条子线程进行你的网络请求,推荐使用这种

// Android 4.0 之后不能在主线程中请求HTTP请求
new Thread(new Runnable(){
@Override
public void run() {
cachedImage = asyncImageLoader.loadDrawable(imageUrl, position);
imageView.setImageDrawable(cachedImage);
}
}).start();


完整的Manifest文件为:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.fengray.myex034test">
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:networkSecurityConfig="@xml/network_security_config"
        tools:replace="android:networkSecurityConfig">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

2、布局页面中设置一个TextView接受返回的信息

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

</LinearLayout>

3、主activity

public class MainActivity extends AppCompatActivity {
    private TextView info=null;
    private String permission[]=new String[]{Manifest.permission.INTERNET};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        info=findViewById(R.id.info);
        ActivityCompat.requestPermissions(MainActivity.this,permission, 0);


        new Thread(new Runnable() {
            @Override
            public void run() {
                boolean flag=false;

                try {
                    //创建一个连接地址,必须使用ipv4的外网地址,不能使用127.0.0.1或localhost
                    URL url=new URL("http","192.168.221.124",8080,"/fengray/android.jsp?id=ncepu&password=ncepup");
                    info.setText(url.toString());
                    //通过地址拿到网络连接
                    HttpURLConnection connection= (HttpURLConnection) url.openConnection();

                    //创建一个新的byte数组,用来存放从连接中读取到的信息
                    byte data[]=new byte[512];
                    //从连接中获取输入流,并写入到data数组中
                    Log.d("jian", "onCreate: before"+connection);

                    int length=connection.getInputStream().read(data);
                    Log.d("jian", "onCreate: after");

                    if (length>0){//如果读入了内容
                        //从data中获取完整内容,并转化成字符串
                        connection.setRequestMethod("GET");

                        //String temp=new String(data,0,length, Charset.forName("utf-8")).trim();
                        String temp=new String(data,0,length).trim();

                        //把flag设置为true
                        flag=Boolean.parseBoolean(temp);
                    }
                    connection.getInputStream().close();
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                    info.setText("服务器连接失败");
                }

                if (flag) {
                    info.setText("用户登录成功");
                }else{
                    info.setText("用户登录失败");
                }
            }
        }).start();

    }
}

结果为:
在这里插入图片描述

2.通过post方式提交数据

在这里插入图片描述
首先要解决的两个bug

  1. AndroidStudio中默认不导入org.apache.http等包的解决方法
    在model的build.gradle中的android添加,如下所示,然后同步一下就可以了.

android {
useLibrary’org.apache.http.legacy’
}

  1. Manifest中对于Apache HTTP 客户端的支持

在 Android 6.0 中,我们取消了对 Apache HTTP 客户端的支持。 从 Android 9 开始,默认情况下该内容库已从 bootclasspath 中移除且不可用于应用。

要继续使用 Apache HTTP 客户端,以 Android 9 及更高版本为目标的应用可以向其 AndroidManifest.xml 添加以下内容:
注意:这个要放在application的节点下面
《uses-library android:name=“org.apache.http.legacy” android:required=“false”/》(这里书名号应替换为尖括号)
作为使用运行时 Apache 库的替代,应用可以在其 APK 中绑定自己的 org.apache.http 库版本。 如果进行此操作,您必须将该库重新打包(使用一个类似 Jar Jar 的实用程序)以避免运行时中提供的类存在类兼容性问题。
一个完整的Manifest文件为:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.fengray.myex034test">
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:networkSecurityConfig="@xml/network_security_config"
        tools:replace="android:networkSecurityConfig">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <uses-library android:name="org.apache.http.legacy" android:required="false"
            tools:ignore="WrongManifestParent" />
    </application>

</manifest>

1、同上例的布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

</LinearLayout>

2、Manifest添加网络访问权限和补bug(网络访问bug和apache包bug)

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.fengray.myex034test">
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:networkSecurityConfig="@xml/network_security_config"
        tools:replace="android:networkSecurityConfig">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <uses-library android:name="org.apache.http.legacy" android:required="false"
            tools:ignore="WrongManifestParent" />
    </application>

</manifest>

3、主activity文件

public class MainActivity extends AppCompatActivity {
    private TextView info=null;
    private static  final String URL="http://192.168.xxx.xxx:8080/fengray/android.jsp";//请求地址
    private String permission[]=new String[]{Manifest.permission.INTERNET};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        info=findViewById(R.id.info);
        ActivityCompat.requestPermissions(MainActivity.this,permission, 0);


        new Thread(new Runnable() {
            @Override
            public void run() {
                boolean flag=false;
                //创建一个HttpPost请求对象
                HttpPost request=new HttpPost(URL);
                List<NameValuePair> params =new ArrayList<>();
                //将个参数添加到list集合中
                params.add(new BasicNameValuePair("id","ncepu"));
                params.add(new BasicNameValuePair("password","ncepup"));
                try {
                    //设置请求的参数
                    request.setEntity(new UrlEncodedFormEntity(params,HTTP.UTF_8));
                    //创建一个接收对象取执行request请求
                    HttpResponse response=new DefaultHttpClient().execute(request);
                    if (response.getStatusLine().getStatusCode()!=404){//请求返回的页面代码部不为404,即已经发现数据了
                       flag=Boolean.parseBoolean(EntityUtils.toString(response.getEntity()).trim());
                    }
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    info.setText("服务器连接失败");

                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (flag) {
                    info.setText("用户登录成功");

                }else{
                    info.setText("用户登录失败");
                }
            }
        }).start();

    }
}

4、Gradle Scripts下的build.gradle(Modle:app)文件添加 useLibrary’org.apache.http.legacy’

android {
    compileSdkVersion 29
    useLibrary'org.apache.http.legacy'

    defaultConfig {
        applicationId "com.fengray.myex034test"
        minSdkVersion 23
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

    }

结果:
在这里插入图片描述

3.读取网络中图片的信息

读取一张网络上的图片到android屏幕上显示,就需要使用ImageView完成显示,同时使用Bitmap来接收读取进来的二进制数据
1、布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

2、Manifest文件

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.fengray.myex034test">
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:networkSecurityConfig="@xml/network_security_config"
        tools:replace="android:networkSecurityConfig">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <uses-library android:name="org.apache.http.legacy" android:required="false"
            tools:ignore="WrongManifestParent" />
    </application>

</manifest>

3、主activity页面

public class MainActivity extends AppCompatActivity {
    private ImageView image= null;
    private static  final String PATH="http://192.168.***.***:8080/fengray/images/girl2.png";//图片地址
    private String permission[]=new String[]{Manifest.permission.INTERNET};

    @SuppressLint("WrongViewCast")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        image=findViewById(R.id.image);
        ActivityCompat.requestPermissions(MainActivity.this,permission, 0);

        new Thread(new Runnable() {
            @Override
            public void run() {
                boolean flag=false;
                //创建一个HttpPost请求对象
                HttpPost request=new HttpPost(PATH);
                List<NameValuePair> params =new ArrayList<>();
                //将个参数添加到list集合中
                params.add(new BasicNameValuePair("id","ncepu"));
                params.add(new BasicNameValuePair("password","ncepup"));

                //设置请求的参数
                try {
                    byte [] data=getUrlData();
                    Bitmap bitmap= BitmapFactory.decodeByteArray(data,0,data.length);//把二进制变为图片
                    image.setImageBitmap(bitmap);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }

            public byte[] getUrlData() throws Exception{//通过操作读取指定地址上的信息
                ByteArrayOutputStream byteArrayOutputStream = null;//通过内存操作流来完成
                try {
                    //读取url
                    URL url=new URL(PATH);
                    //创建一个byte的输出流
                    byteArrayOutputStream=new ByteArrayOutputStream();
                    //创建byte数组来存放从输出流读取的byte数据
                    byte [] data=new byte[1024];
                    //获取网络连接
                    HttpURLConnection connection= (HttpURLConnection) url.openConnection();
                    //创建一个输入流
                    InputStream inputStream=connection.getInputStream();
                    //输入流长度
                    int len=0;
                    while((len=inputStream.read(data))!=-1){//如果没有读取完
                        //将data数组写入到输出流中
                        byteArrayOutputStream.write(data,0,len);
                    }
                    //将输出流转为数组
                    return byteArrayOutputStream.toByteArray();

                }catch (Exception e) {
                    throw e;
                }finally {
                    if (byteArrayOutputStream!=null){
                        byteArrayOutputStream.close();
                    }
                }
            }
        }).start();

    }

}

结果为:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值