android004,简易PC-Android图片发送
一、思路:通过PC服务器向Android手机客户机发送图片
1、创建java工程PC服务器
1)、创建服务器对象,带有指定端口
2)、让服务器循环等待客户机的连接
3)、点击按钮出现文件选择器,得到文件路径
4)、取得连结对象上的流对象,再将流传送给客户机
5)、创建一个界面,点击按钮,选择图片,取得图片的信息,发送给客户机
2、Android工程手机客户端
1)、创建好工程
2)、在第一个页面显示之后,创建客户对象(记得加互联网权限android.permission.INTERNET)
得到输入输出流
3)、编辑想要的页面(在第二个页面操作),编辑第一个页面的内容(main.xml)
除第一个Activity外,其他Activity需要在AndroidManifest中注册;
4)、取得各组件的ID并转型为所要的组件类型,跳转页面的条件
5)、点击“接收”按钮,得到服务器传来的流,并转换成bitmap再显示在页面上
二、一些细节:
1、文件选择器JFileChooser不是你想用就能用的,需要借助JFrame才能显示
2、文件选择,显示提示框,选择文件,并得到其路径的方法:
JFileChooser jfc = new JFileChooser();// 创建一个文件选择器
jfc.showOpenDialog(null);// 提示对话框
File file = jfc.getSelectedFile();// 得到所选中的文件
srcFile = file.getAbsolutePath();// 文件的绝对路劲
3、可能出于使用无线网或其他什么原因,ip可能一下子又变了,所以,创建客户对象的时候一定要小心其IP:
client = new Socket("192.168.1.24", 8090);//创建客户对象(每次都要取得服务器的ip)
4、将所得到的流转换为bitmap,并将其显示到页面上:
final Bitmap bitmap = new BitmapFactory().decodeByteArray(data, 0, in);// 转换成bitmap格式的方法,这里由于在下面这个run方法里需要用到bitmap,所以要定义成final类型的
icon_1.post(new Runnable() {
public void run() {
// 将bitmap显示到界面上
icon_1.setImageBitmap(bitmap);
}
});
5、其他:流的顺序;添加权限;Activity注册,通过找到相应的ID转换成相应的组件也是需要注意的
三、其他拓展:
EditText中 android:password="true",设置编辑框为密码输入框
ImageView为图片组件
四、代码及注释:
1、PC服务器端:
package androidke.flycatdeng.PCServer;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
/**
* 图片发送电脑服务器至android手机端
* @author flycatdeng
*/
public class PhotoSentServer extends JFrame {
// 声明
Socket client;// 客户对象
String srcFile;// 图片地址
InputStream ins;// 输入流对象
OutputStream ous;// 输出流对象
DataOutputStream dos;// 封装成数据输出流对象
DataInputStream dis;// 封装成数据输入流对象
// 主函数
public static void main(String[] args) {
try {
PhotoSentServer pss = new PhotoSentServer();
pss.frameShow();// 显示窗体
pss.setupServer(8090);// 启动服务器
} catch (Exception e) {
e.printStackTrace();
}
}
// 显示窗体的方法
public void frameShow() {
this.setTitle("服务器端");// 标题
this.setSize(200, 200);// 窗体大小
this.setLayout(new FlowLayout(0, 0, 0));// 流式布局
JButton jbt = new JButton("发送图片");// 创建一个按钮
jbt.setActionCommand("sendPhoto");// 按钮监听发送消息
jbt.addActionListener(al);// 按钮添加事件监听器
this.add(jbt);// 按钮显示在窗体上
this.setDefaultCloseOperation(3);// 关闭窗体后退出程序
this.setVisible(true);// 设置窗体可见
}
// 内部类
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("sendPhoto")) {
choosephoto();// 点击按钮后选择照片
try {
processPhoto(srcFile);// 发送图片
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
};
// 选择照片的方法
public void choosephoto() {
JFileChooser jfc = new JFileChooser();// 创建一个文件选择器
jfc.showOpenDialog(null);// 提示对话框
File file = jfc.getSelectedFile();// 得到所选中的文件
srcFile = file.getAbsolutePath();// 文件的绝对路劲
System.out.println("选择的图片成功,地址是:" + srcFile);
}
// 发送图片的方法
public void processPhoto(String srcFile) throws Exception {
InputStream ins = new FileInputStream(srcFile);// 得到选中文件的流
DataInputStream dis = new DataInputStream(ins);// 包装
int fileLen = dis.available();// 得到文件的大小
System.out.println("图片的大小为" + fileLen);
if (fileLen > 0) {// 如果有流则执行下面的
System.out.println("准备读流中");
dos.writeInt(fileLen);// 将文件的大小以int输出
byte[] data = new byte[fileLen];
dis.read(data);// 以字节数组读取
dos.write(data);// 输出
dos.flush();// 强制完全输出
System.out.println("读完流了");
}
}
// 创建服务器的方法
public void setupServer(int port) throws Exception {
ServerSocket server = new ServerSocket(port);// 创建服务器对象,带有指定的端口
System.out.println("创建服务器成功,端口:" + port);
// 让服务器循环等待客户的连接
while (true) {
client = server.accept();// 等待客户连接
System.out.println("有客户连接进来啦,IP地址:"
+ client.getRemoteSocketAddress());// 取得打印客户机的IP地址
ous = client.getOutputStream();// 得到客户输出流
ins = client.getInputStream();
dos = new DataOutputStream(ous);
dis = new DataInputStream(ins);
}
}
}
2、Android客户端:
1)、第一个Activity:
package androidke.fycatdeng.lesson004;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class FirstActivit extends Activity {
// 声明
Button button_send;
EditText edit_username, edit_password;
Socket client;
// 定义静态的输入输出流,以便其他页面使用
static InputStream ins;
static OutputStream ous;
// 重写(这个相当于主函数)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 显示第一个页面后,创建客户对象
try {
client = new Socket("192.168.1.24", 8090);//创建客户对象(每次都要取得服务器的ip)
System.out.println("客户创建成功!!!");
ins = client.getInputStream();// 得到客户输入输出流
ous = client.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(FirstActivit.this, "未连接到服务器,请重新其启动!", 3).show();
}
// 可视后取得各个组件的id并强制转换为相应的组件类型
button_send = (Button) this.findViewById(R.id.button_send);// 提交按钮
edit_username = (EditText) this.findViewById(R.id.edit_username);// 用户名编辑框
edit_password = (EditText) this.findViewById(R.id.edit_password);// 密码编辑框
button_send.setOnClickListener(ocl);// 给按钮添加(设置)监听器
}
// 内部匿名类
OnClickListener ocl = new OnClickListener() {// 这个包引进的时候需要注意,选择的是第二个:android.view.View.OnClickListener;
// 重写方法
public void onClick(View v) {
// 将编辑框的内容得到并转换为字符串
String username = edit_username.getText().toString();
String password = edit_password.getText().toString();
if ("dck".equals(username) && "1".equals(password)) {
// 用户名个密码都正确后则跳转页面
Intent intent = new Intent(FirstActivit.this,
SecondActivity.class);
// 跳转页面的时候,把那个客户对象也传过去
// intent.putExtra("clientFlag",client);
FirstActivit.this.startActivity(intent);
} else {
// 如果登录错误则提示
Toast.makeText(FirstActivit.this, "用户名不存在活密码错误!", 3).show();// 副本,内容,停留时间以秒为单位
}
}
};
}
2)、第二个Activity:
package androidke.fycatdeng.lesson004;
import java.io.DataInputStream;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class SecondActivity extends Activity {
Button button_recivePhoto;
ImageView icon_1;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second);// 转到第二个页面second.xml、
// 取得第二页面的按钮id转型为所需组件类型
button_recivePhoto = (Button) this
.findViewById(R.id.button_recivePhoto);
button_recivePhoto.setOnClickListener(ocl);// 接收按钮绑定监听器
icon_1 = (ImageView) this.findViewById(R.id.icon_1);
}
// 内部匿名类
OnClickListener ocl = new OnClickListener() {//
// 这个包引进的时候需要注意,选择的是第二个:android.view.View.OnClickListener;
// 重写方法
public void onClick(View v) {
try {
System.out.println("点击按钮准备接收图片!");
recivePhoto();// 点击按钮后接收图片
} catch (Exception e) {
e.printStackTrace();
}
}
};
// 接收图片的方法
public void recivePhoto() throws Exception {
DataInputStream dis = new DataInputStream(FirstActivit.ins);
int in = dis.readInt();
byte[] data = new byte[in];
dis.read(data);
System.out.println("读完流了!准备转换图片");
final Bitmap bitmap = new BitmapFactory().decodeByteArray(data, 0, in);// 转换成bitmap格式的方法,这里由于在下面这个run方法里需要用到bitmap,所以要定义成final类型的
icon_1.post(new Runnable() {
public void run() {
// 将bitmap显示到界面上
icon_1.setImageBitmap(bitmap);
}
});
System.out.println("转换完了!");
}
}
3)、第一个页面:main.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"
>
<!-- 这下面的前两句是每个组件必要的属性 -->
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="欢迎使用手机CC"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="用户名:"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/edit_username"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="密码:"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:password="true"
android:id="@+id/edit_password"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="提交"
android:id="@+id/button_send"
/>
</LinearLayout>
4)、第二个页面:second.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"
>
<!-- 这下面的前两句是每个组件必要的属性 -->
<!-- dip表示像素 -->
<Button
android:layout_width="100dip"
android:layout_height="wrap_content"
android:text="接收"
android:id="@+id/button_recivePhoto"
/>
<!-- ImageView为图片组件 -->
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/icon_1"
/>
</LinearLayout>
五、效果: