说起去年的Demo。以今天的免费整齐优势。

原理很easy,虽然没有写android申请书。但,好了~ 高级语言是相通的。傲慢约。就这么简单研究了一下api后,找到相机对象有一个预览回调方法。

意识到发生了什么Camera.PreviewCallback接口。就能够得到一个每一帧画面的回调事件,那么思路就非常easy了。

拿到画面后,进行下简单的压缩,然后把图像用Socket传输到server上。server上绑定到一个窗体的picBox上就能够了。

当然,这里还牵扯到多线程的问题,由于一个SocketServer能够实现和多个client建立连接,而每个连接都须要独立的线程来实现监听。

安卓端代码:

package com.xwg.monitorclient;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.List;
import java.util.zip.DeflaterOutputStream; import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.app.Activity;
import android.content.SharedPreferences;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText; public class MainActivity extends Activity implements SurfaceHolder.Callback,
Camera.PreviewCallback{
private SurfaceView mSurfaceview = null; // SurfaceView对象:(视图组件)视频显示
private SurfaceHolder mSurfaceHolder = null; // SurfaceHolder对象:(抽象接口)SurfaceView支持类
private Camera mCamera = null; // Camera对象,相机预览 /**服务器地址*/
private String pUsername="XZY";
/**服务器地址*/
private String serverUrl="192.168.0.3";
/**服务器端口*/
private int serverPort=9999;
/**视频刷新间隔*/
private int VideoPreRate=1;
/**当前视频序号*/
private int tempPreRate=0;
/**视频质量*/
private int VideoQuality=85; /**发送视频宽度比例*/
private float VideoWidthRatio=1;
/**发送视频高度比例*/
private float VideoHeightRatio=1; /**发送视频宽度*/
private int VideoWidth=320;
/**发送视频高度*/
private int VideoHeight=240;
/**视频格式索引*/
private int VideoFormatIndex=0;
/**是否发送视频*/
private boolean startSendVideo=false;
/**是否连接主机*/
private boolean connectedServer=false; private Button myBtn01, myBtn02; private EditText txtIP; @Override
public void onStart()//又一次启动的时候
{
mSurfaceHolder = mSurfaceview.getHolder(); // 绑定SurfaceView。取得SurfaceHolder对象
mSurfaceHolder.addCallback(this); // SurfaceHolder增加回调接口
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// 设置显示器类型,setType必须设置
//读取配置文件
SharedPreferences preParas = PreferenceManager.getDefaultSharedPreferences(MainActivity.this);
pUsername=preParas.getString("Username", "XZY");
serverUrl=preParas.getString("ServerUrl", "192.168.0.3");
String tempStr=preParas.getString("ServerPort", "9999");
serverPort=Integer.parseInt(tempStr);
tempStr=preParas.getString("VideoPreRate", "1");
VideoPreRate=Integer.parseInt(tempStr);
tempStr=preParas.getString("VideoQuality", "85");
VideoQuality=Integer.parseInt(tempStr);
tempStr=preParas.getString("VideoWidthRatio", "100");
VideoWidthRatio=Integer.parseInt(tempStr);
tempStr=preParas.getString("VideoHeightRatio", "100");
VideoHeightRatio=Integer.parseInt(tempStr);
VideoWidthRatio=VideoWidthRatio/100f;
VideoHeightRatio=VideoHeightRatio/100f; super.onStart();
} @Override
protected void onResume() {
super.onResume();
InitCamera();
} /**初始化摄像头*/
private void InitCamera(){
try{ mCamera = Camera.open();
List<Size> list = mCamera.getParameters().getSupportedPreviewSizes();
for(Size s : list)
{
if(s.width<=640)
{
Camera.Parameters params = mCamera.getParameters();
params.setPreviewSize(s.width, s.height);
mCamera.setParameters(params);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
} @Override
protected void onPause() {
try{
if (mCamera != null) {
mCamera.setPreviewCallback(null); // 。。这个必须在前。不然退出出错
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
} catch (Exception e) {
e.printStackTrace();
} super.onPause();
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); //禁止屏幕休眠
getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); mSurfaceview = (SurfaceView) findViewById(R.id.camera_preview);
myBtn01=(Button)findViewById(R.id.button1);
myBtn02=(Button)findViewById(R.id.button2);
txtIP = (EditText)findViewById(R.id.editText1);
//開始连接主机按钮
myBtn01.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
serverUrl = txtIP.getText().toString();
if(connectedServer){//停止连接主机,同一时候断开传输
startSendVideo=false;
connectedServer=false;
myBtn02.setEnabled(false);
myBtn01.setText("開始连接");
myBtn02.setText("開始传输"); //断开连接
//Thread th = new MySendCommondThread("PHONEDISCONNECT|"+pUsername+"|");
//th.start(); }
else//连接主机
{
//启用线程发送命令PHONECONNECT connectedServer=true;
myBtn02.setEnabled(true);
myBtn01.setText("停止连接");
}
}}); myBtn02.setEnabled(false);
myBtn02.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
if(startSendVideo)//停止传输视频
{
startSendVideo=false;
myBtn02.setText("開始传输");
}
else{ // 開始传输视频
Thread th = new MyThread();
th.start();
startSendVideo=true;
myBtn02.setText("停止传输");
}
}});
} @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;
} @Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
if (mCamera == null) {
return;
}
mCamera.stopPreview();
mCamera.setPreviewCallback(this);
mCamera.setDisplayOrientation(90); //设置横行录制 //获取摄像头參数
Camera.Parameters parameters = mCamera.getParameters(); Size size = parameters.getPreviewSize();
VideoWidth=size.width;
VideoHeight=size.height; VideoFormatIndex=parameters.getPreviewFormat(); mCamera.startPreview();
} @Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
}
} catch (IOException e) {
e.printStackTrace();
}
} @Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
if (null != mCamera) {
mCamera.setPreviewCallback(null); // !。这个必须在前,不然退出出错
mCamera.stopPreview();
mCamera = null;
}
} @Override
public void onPreviewFrame(byte[] data, Camera camera) {
// TODO Auto-generated method stub
//假设没有指令传输视频,就先不传
if(!startSendVideo)
return;
// if(tempPreRate<VideoPreRate){
// tempPreRate++;
// return;
// }
// tempPreRate=0;
try {
if(data!=null)
{
YuvImage image = new YuvImage(data,VideoFormatIndex, VideoWidth, VideoHeight,null);
if(image!=null)
{
ByteArrayOutputStream outstream = new ByteArrayOutputStream(); //在此设置图片的尺寸和质量
image.compressToJpeg(new Rect(0, 0, (int)(VideoWidthRatio*VideoWidth),
(int)(VideoHeightRatio*VideoHeight)), VideoQuality, outstream);
outstream.flush(); SendMessage(outstream.toByteArray()); //启用线程将图像数据发送出去
//Thread th = new MySendFileThread(outstream.toByteArray());
//th.start();
}
}
} catch (IOException e) {
e.printStackTrace();
}
} Socket client = null; public void SendMessage(byte[] content)
{
if(client==null)
return;
OutputStream outsocket;
try{
outsocket = client.getOutputStream(); //BufferedOutputStream dos = new BufferedOutputStream(outsocket);
DataOutputStream dos = new DataOutputStream(outsocket);
int len = content.length;
byte[] header = Int2Byte(len);
//outsocket.write(header); dos.write(header);
//outsocket.flush();
//outsocket.write(content);
// byte byteBuffer[] = new byte[1024];
// ByteArrayInputStream inputstream = new ByteArrayInputStream(content);
//
// PrintWriter pw = new PrintWriter(outsocket);
//
// int amount;
// while ((amount = inputstream.read(byteBuffer)) != -1) {
// outsocket.write(byteBuffer, 0, amount);
// }
//outsocket.write(content);
dos.write(content);
//dos.flush();
//dos.close();
//outsocket.flush(); }catch(Exception e)
{
e.printStackTrace();
}
} public byte[] Int2Byte(int len)
{
byte[] rtn = new byte[5];
rtn[0] = (byte)0;
rtn[1] = (byte)(len&0xff);
rtn[2] = (byte)((len>>8)&0xff);
rtn[3] = (byte)((len>>16)&0xff);
rtn[4] = (byte)(len>>>24);
return rtn; } /**发送命令线程*/
class MyThread extends Thread{ public void run(){
//实例化Socket
try {
client=new Socket(serverUrl,serverPort); } catch (UnknownHostException e) {
} catch (IOException e) {
}
}
} /**发送文件线程*/
class MySendFileThread extends Thread{
byte[] content = null;
public MySendFileThread(byte[] content){
this.content = content;
} public void run() {
try{
SendMessage(this.content);
//tempSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
</pre><p></p><p>安卓端代码通过一个全局Socket创建连接,然后通过onPreviewFrame事件,捕获图像帧。然后压缩,处理成byte[]然后发送啦。</p><p>只是java这里没有int和byte[]的转换,非常二有木有,歧视一下java。

还得自己写代码转换,这里直接生成了header[],因为没设计其它操作,所以第一位默认0,</p><p>后4位是图片byte[]长度。

</p><p>然后依次发送数据出去。</p><p>其它的相机设置的代码,来自baidu。

</p><p>话说java这里不熟,所以比較乱。没有详细封装什么的。

</p>C#代码<p>ClientInfo。一个用来保存连接的实体类,嘛~因为Demo吗,没细致处理,一下也是同样原因,没有详细优化过,只是測试过wifi条件下,传600p左右画质,开2~3个client还是能够的。

</p><p></p><pre code_snippet_id="419870" snippet_file_name="blog_20140707_3_9307192" name="code" class="csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets; namespace com.xwg.net
{
public class ClientInfo
{
public Thread ReceiveThread; public Socket Client; public string ip; public string name; }
}

serverSocket管理类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
using xwg.common;
using System.IO; namespace com.xwg.net
{
public class SocketServer
{
#region 变量定义
List<ClientInfo> clientList = null; private Socket socketServer = null; /// <summary>
/// 服务器IP
/// </summary>
private IPAddress serverIP; /// <summary>
/// 监听端口号
/// </summary>
private int portNo = 15693; /// <summary>
/// 完整终端地址包括端口
/// </summary>
private IPEndPoint serverFullAddr; // Server监听线程
Thread accpetThread = null; #endregion #region 构造函数
public SocketServer(string ServerIP)
{
this.serverIP = IPAddress.Parse(ServerIP);
} public SocketServer(string ServerIP, int portNo)
{
this.serverIP = IPAddress.Parse(ServerIP);
this.portNo = portNo;
}
#endregion #region Event // 客户端接入事件
public event ClientAccepted OnClientAccepted; // 连接接收数据事件
public event StreamReceived OnStreamReceived; public event ClientBreak OnClentBreak; #endregion public void StartListen()
{
//取得完整地址
serverFullAddr = new IPEndPoint(serverIP, portNo);//取端口号
try
{
// 实例化Server对象
socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // 绑定监听端口
socketServer.Bind(serverFullAddr); // 启动监听。制定最大20挂起
socketServer.Listen(20); }
catch (Exception e)
{
Logger.Write("StartListen方法:"+e.Message);
} clientList = new List<ClientInfo>(); accpetThread = new Thread(new ThreadStart(AcceptSocket));
accpetThread.IsBackground = true;
accpetThread.Start();
} private void AcceptSocket()
{
while (true)
{
// client Socket 获得客户端连接
Socket acceptSock = socketServer.Accept(); Logger.Write("接收到连接!");
string ip = ((IPEndPoint)acceptSock.RemoteEndPoint).Address.ToString();
Logger.Write("客户端IP:");
ClientInfo info = new ClientInfo();
info.Client = acceptSock;
info.ip = ip;
info.name = ip; Thread recThread = new Thread(new ParameterizedThreadStart(ReceiveMsg));
recThread.IsBackground = true;
info.ReceiveThread = recThread; clientList.Add(info); recThread.Start(info); // 客户端接入响应事件
if (OnClientAccepted != null)
OnClientAccepted(this, info);
}
} private void ReceiveMsg(object obj)
{
ClientInfo info = (ClientInfo)obj;
Socket clientSock = info.Client;
try
{
while (true)
{
// 推断连接状态
if (!clientSock.Connected)
{
clientList.Remove(info);
info.ReceiveThread.Abort();
clientSock.Close(); } try
{
byte[] header = new byte[5];
int len = clientSock.Receive(header,SocketFlags.None);
if (len != 5)
{
// 错误 终端连接
Logger.Write("数据头接收错误,长度不足:" + len);
clientSock.Close();
info.ReceiveThread.Abort();
return;
} int conLen = BitConverter.ToInt32(header, 1); //byte[] content = new byte[conLen];
//len = clientSock.Receive(content, SocketFlags.None);
MemoryStream stream = new MemoryStream();
//byte [] buffer = new byte[1024];
//while ((len = clientSock.Receive(buffer)) > 0)
//{
// stream.Write(buffer,0,len);
//}
//if (conLen != stream.Length)
//{
// Logger.Write("长度错误:"+stream.Length+"/"+conLen);
//}
for (int i = 0; i < conLen; i++)
{
byte[] arr = new byte[1];
clientSock.Receive(arr,SocketFlags.None);
stream.Write(arr,0,1);
} //stream.Write(content,0,content.Length);
stream.Flush(); //len = clientSock.Receive(content, SocketFlags.None); //if (len != conLen)
//{
// // 错误 终端连接
// Logger.Write("header:" + header[1] + "," + header[2] + "," + header[3] + "," + header[4]);
// Logger.Write("Content接收错误。长度不足:" + len+"/"+conLen);
// clientSock.Close();
// return;
//} // 接收事件
if (OnStreamReceived != null)
{
OnStreamReceived(info, stream);
}
}
catch (Exception ex)
{
if (OnClentBreak != null)
{
OnClentBreak(this, info);
}
Logger.Write("Receive数据:"+ex.Message);
clientSock.Close();
return;
}
}
}
catch (Exception e)
{
if (OnClentBreak != null)
{
OnClentBreak(this, info);
}
Logger.Write("ReceiveMsg:" + e.Message);
clientSock.Close();
return;
}
}
} public delegate void ClientAccepted(object sender,ClientInfo info); public delegate void StreamReceived(object sender,MemoryStream stream); public delegate void ClientBreak(object sender,ClientInfo info);
}

这里面涉及了Socket和多线程处理的知识。

简单一说,Socket既能够做Server,也能够做Client,当然你用TCPListener也一样效果就是了。

这里因为是服务端,所以Socket被我Bind到了一个port上面,启用了Listen,监听方法。

然后启用了一个accpet线程。总用时实现port监听。

每当accpet到一个client的时候,会触发 OnClientAccepted 事件。accpet方法是会触发堵塞的,所以绝对不能够用主线程。否则就是程序无响应。

C#处理过程中,实现封装的最好方法就是使用事件机制了,这是我觉得比Java方便的多的设计。能够把逻辑的实现。全然的抛出封装对象。

然后就是AcceptSocket 这种方法了,这种方法其中,一旦接收到client连接,会创建一个ClientInfo对象。把一些相关属性设置上去保存。

同一时候新建一个线程,实现ReceiveMessage的监听。IsBackground是一个小技巧,表示主线程结束时,把这些线程同一时候结束掉。

比起手动结束方便多。

假设你应用关闭,发现程序还在后台跑,那么多数是因为创建的线程没有结束的原因。这时候这个属性会起到关键作用。

ReceiveMsg是接收数据的方法。这里简单定义了一个数据协议,数据发送时,分成两部分发送,先发送一个5byte的header。然后是实际内容content。

header第一位表示操作标示(由于demo简单,所以没有详细设计协议,这个能够自己定义的,也是通用的处理方法)。后4位标示content内容流的长度,这样取数据的时候,就不至于乱掉。

正常来说,Socket.Receive是有堵塞的啦,只是这里不知道为什么,接收的时候有问题,怀疑安卓socket流导致的。所以没办法直接定义buffer。一次性接受全部content。因为时间紧。没细致研究。反正总长度是一定不会变的,所以直接循环处理了...偷懒了有木有...

接受到信息后,通过事件OnStreamReceived 吧数据流返回出去。

服务端基本就这样了。由于不牵扯双向消息。所以没处理send啦。

然后就是界面:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using com.xwg.net;
using System.IO;
using xwg.common; namespace MonitorServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} SocketServer server = null;
List<ViewForm> list = new List<ViewForm>();
//ViewForm vf = new ViewForm(); private void button1_Click(object sender, EventArgs e)
{ server = new SocketServer(txtIP.Text, int.Parse(txtPort.Text));
Logger.Write("server = new SocketServer(txtIP.Text, int.Parse(txtPort.Text));");
server.OnClientAccepted += ClientAccepted;
server.OnStreamReceived += StreamReceived;
server.OnClentBreak += ClientBreak;
server.StartListen();
Logger.Write("StartListen");
button1.Enabled = false;
} public void AddClient(string ip)
{
try
{
this.Invoke((EventHandler)delegate
{
listBox1.Items.Add(ip);
});
}
catch (Exception e)
{ }
} public void RemoveClient(string ip)
{
try
{
this.Invoke((EventHandler)delegate
{
listBox1.Items.Remove(ip);
});
}
catch (Exception e)
{ }
} public void CloseViewForm(string ip)
{
try
{
ViewForm vf = GetViewByIP(ip);
if (vf == null)
return;
vf.Invoke((EventHandler)delegate
{
vf.Close();
});
}
catch (Exception e)
{ }
} public void SetViewImage(ViewForm vf, MemoryStream stream)
{
try
{
vf.Invoke((EventHandler)delegate
{
Image img = Image.FromStream(stream);
vf.SetImage(img);
stream.Close();
});
}
catch (Exception e)
{ }
} protected void ClientAccepted(object sender, ClientInfo info)
{
Logger.Write("ClientAccepted:"+info.ip);
AddClient(info.ip); //ViewForm vf = new ViewForm();
//list.Add(vf);
//vf.SetTitle(info.ip);
//vf.Show();
} private ViewForm GetViewByIP(string ip)
{
foreach (ViewForm vf in list)
{
if (vf.Text == ip)
return vf;
}
return null;
} protected void StreamReceived(object sender, MemoryStream stream)
{
ClientInfo info = (ClientInfo) sender;
try
{
//Image img = Image.FromStream(stream);
////img.Save("a.jpg");
ViewForm vf = GetViewByIP(info.ip);
if (vf == null)
{
stream.Close();
return;
}
SetViewImage(vf, stream); //vf.SetImage(img);
//stream.Close();
}
catch (Exception e)
{
Logger.Write("StreamReceived:"+e.Message);
}
} protected void ClientBreak(object sender, ClientInfo info)
{
CloseViewForm(info.ip);
list.Remove(GetViewByIP(info.ip));
RemoveClient(info.ip);
} private void listBox1_MouseDoubleClick(object sender, MouseEventArgs e)
{
if (listBox1.SelectedItem == null)
return;
string ip = listBox1.SelectedItem.ToString();
ViewForm vf = new ViewForm();
list.Add(vf);
vf.SetTitle(ip);
vf.Show();
}
}
}

界面实现了那几个事件,通过事件机制得到数据,进行UI设置。(界面嘛~就是UI层啦。一般仅仅关注UI,不要放逻辑代码)

然后用来展示的窗口

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms; namespace MonitorServer
{
public partial class ViewForm : Form
{
public ViewForm()
{
InitializeComponent();
} public void SetTitle(string title)
{
this.Text = title;
} public void SetImage(Image img)
{
pictureBox1.Image = img;
}
}
}

事实上就是绑定了一个pictureBox啦。

到此就结束了,启动server应用。開始监听。然后启动安卓端应用,输入server地址(要保证一个网络中),连接。

服务端就会发现client连接,这时。双击ip,就会打开预览窗体。

支持多client连接预览,可是打开多了会卡,毕竟演示demo。没处理优化。

实际上,应该是连接后,server发送命令给client,client才開始传图片流,如今没处理。所以比較卡哦。

而且这样的图片帧传输的方法。尽管比較清晰。可是压缩比小。会产生大量流量。所以仅仅能演示用哦。

对了,还一个原因,这里用的tcp协议,可以保证数据包丢失重发。可是该机制会导致性能瓶颈,重发就会有时间影响哦,网络不好。easy出现抖动等现象,事实上是因为丢包引起的。这里可以换用udp,尽管可能会出现丢帧,可是抖动现象应该会有改善,速度也会比較快。

而且这里不支持音频哦,假设想要完美实现的话。还是用上一篇文章提到的方法吧。

做一个控制server,然后实现C#client和androidclient的直连,效果应该比較好。当然,这里也是因为spyroid这个项目。内置实现了rtsp协议server的原因啦。

站在巨人身上总是会让事情变得简单。这里感谢国外开源项目组,同一时候歧视一下国内人员,百度到实用的东西,都不放出源代码,而是要收费。。。

希望对大家实用。

对了,源代码我上传到资源里面了,大家能够去我空间下载,包括安卓和C#后台完整项目代码。

地址:http://download.csdn.net/detail/lanwilliam/7602669

10资源子其实真的不高,调试后,1天离开。

版权声明:欢迎转载,但请保留源解释

Android和C#实时视频传输Demo的更多相关文章

  1. Android -BLE蓝牙小DEMO

    代码地址如下:http://www.demodashi.com/demo/13890.html 原文地址: https://blog.csdn.net/vnanyesheshou/article/de ...

  2. I.MX6 Android backlight modify by C demo

    /************************************************************************** * I.MX6 Android backligh ...

  3. Android handler Thread 修改UI Demo

    /********************************************************************** * Android handler Thread 修改U ...

  4. Android微信分享功能实例+demo

    Android微信分享功能实例 1 微信开放平台注册 2 获得appId,添加到程序中,并运行程序 3 使用应用签名apk生成签名,添加到微信开放平台应用签名,完成注册 4 测试分享功能. 有问题请留 ...

  5. Android中Service的一个Demo例子

    Android中Service的一个Demo例子  Service组件是Android系统重要的一部分,网上看了代码,很简单,但要想熟练使用还是需要Coding.  本文,主要贴代码,不对Servic ...

  6. Android和jS互调技术Demo实现

    package com.loaderman.webviewdemo; import android.os.Bundle; import android.support.v7.app.AppCompat ...

  7. 树莓派+android things+实时音视频传输demo之遥控小车

    做了个测试小车,上面安装了摄像头,通过外网进行视频传输: https://www.bilibili.com/video/av23817880/

  8. 关于android端的json传输

    比较通用的传输方法 import java.util.ArrayList; import java.util.List; import org.apache.http.HttpEntity; impo ...

  9. 使用 Android Studio 跑新浪微博SDK Demo遇到的问题及解决

    概述 这是新浪微博官方 Android SDK Demo 使用 Android Studio 导入.编译并运行通过的版本. 源码:WeiboSdkDemo 官方项目请点击: weibo_android ...

随机推荐

  1. OpenGL3D迷宫场景设计

    近期学习用opengl库来构建一个3D场景,以及实现场景漫游.粒子系统等效果.终于算是是做了一个3D走迷宫游戏吧. 感觉近期学了好多东西,所以有必要整理整理. 一 实现效果 watermark/2/t ...

  2. FileUpload类别FileUpload1.FileName和FileUpload1.PostedFile.FileName差异

    FileUpload1.FileName 用来获取client上使用 FileUpload 控件上载的文件的名称.此属性返回的文件名称不包括此文件在client上的路径. FileUpload1.Po ...

  3. Thread.join()分析方法

    API: join public final void join() throws InterruptedException 等待该线程终止. 抛出: InterruptedException - 假 ...

  4. Blend4精选案例图解教程(五):可视数据管理

    原文:Blend4精选案例图解教程(五):可视数据管理 应用程序中我们会经常需要操作数据,在程序设计之初示例数据一般都是手工添加,Blend4提供了非常方便的数据管理能力,包括丰富的数据类型和内置示例 ...

  5. 简单的反射 把datatable 转换成list对象

    /// <summary> /// 把datatable 转换成list对象 /// </summary> /// <typeparam name="T&quo ...

  6. 开源 自由 java CMS - FreeCMS1.9 分纪录

    项目地址:http://www.freeteam.cn/ 2.4.1 积分记录 查看系统全部会员积分记录. 从左側管理菜单点击积分记录进入. 版权声明:本文博客原创文章,博客,未经同意,不得转载.

  7. HTML5之Canvas影片广场

    HTML5之Canvas影片广场 1.设计源代码 <!DOCTYPE html> <head> <meta charset="utf-8" /> ...

  8. Chrome 小工具: 启动本地应用 (Native messaging)

    最近遇到一个新的问题.需要使用Chrome 插件, 从我们对我们当地的一个网站之一启动C#应用,同时通过本申请值执行不同的操作. 在这里记录下解决的过程.以便以后查找 首先我们须要新建一个google ...

  9. Xampp mysql无法启动的解决方案(转)

    如果出现mysql 无法启动表明在安装xampp 前已经安装了mysql,造成mysql服务无法启动. [mysql] MySQL Service detected with wrong path23 ...

  10. SecureCRT使用提示

    一旦itpub我写上面,我不知道这个博客的背后,我们无法上传和修改内容.好恼火啊! 原文链接:SecureCRT的几个使用方法设置 在原文的基础上,再补充几个功能: 1.最好将全部设置定制在Globa ...