首页 文章 精选 留言 我的

精选列表

搜索[移动解析],共10000篇文章
优秀的个人博客,低调大师

移动端图片操作(二)——预览、旋转、合成

在上一节中已经提到了预览,预览可以通过data: URL格式或URL对象。 var file = upload.files[0]; //URL对象 var url = URL.createObjectURL(file); var img = new Image(); img.style.width = '100%'; img.src = url; img.onload = function(e) { window.URL.revokeObjectURL(this.src); //销毁 } //data:URL格式 var img = new Image(); img.style.width = '100%'; var reader = new FileReader(); reader.onload = function() { img.src = this.result; }; reader.readAsDataURL(file); 一切都很顺利,但其实有很多的坑,需要慢慢讲来。先从前面做的一个小功能说起。 这个小功能就是将两张图片合成起来,组成一张新的图片。 一、技术实现 1)上传的控件就用“input[type=file]”实现 Android的webview不支持此控件,怪不得按钮怎么按都按不动,后面只得用客户端提供的接口做上传 期间发现UC浏览器会自动将上传控件包装成三个按钮的样子,只需设置为“opacity:0;”即可。 2)使用“FileReader”,通过方法readAsDataURL获取data URL格式的图片内容,赋值给image。 IOS在上传图片或拍照的时候,显示出来的宽高是反的,这个时候我们增加了一步旋转的操作,让用户自己来控制。 在给image赋src值的同时,赋“crossOrigin”的值,用于后面的图片跨域 3)将图片画在“canvas”上,旋转其实也就是转这个canvas。通过计算坐标和角度实现旋转 4)将旋转后的“canvas”与剩下的两张文字图片,通过一个新的“canvas”合并到一起。 在将两个“canvas”画在一起后,发现通过webview上传的图片,不能使用“toDataURL()”方法了,这是因为画布被污染,第一个画布中的图片是跨域的。 5)最后将dataURL格式的内容上传到服务器中保存。 总共开发时间是3天,在这个过程中有过几次技术推翻重做或者逻辑重整,兼容性方面也还有很大问题,包括图片的宽高的自适应等,还很不完善。 下图是最终效果,挑了张松狮的写真照: 二、预览 原先我在做的时候,第2步和第3布是合在一起的,也就是图片显示出来的时候,已经校准好位置。 只是在实现的过程中碰到了很多麻烦,并且时间仓促,BUG修复起来比较费时,只得分两步。 先说说原先的过程: 1)IOS图片上传或拍照,宽高相反 我用的是Android手机,刚开始并没有发现这个问题,后面别人帮忙测试的时候,才发现了这个重大问题,接下来就是折腾这个事儿,想要自动校正方向。 1.通过exif.js获取图片元数据,通过获取“Orientation”属性判断方向【我的Android机中这个属性为undefined,IOS有值】,总共有8个值 左边是说明,右边是展示。表格中带“*”的是指翻转过来了。 接下来就是做计算,网上有很多计算方式,对于“>IOS7”的系统,计算逻辑可以参考下localResizeIMG插件195行。 顺便说下,这个插件使用到了gulp的开发方式,如果要调试就要配置相关代码,可以参考《前端自动化构建工具gulp记录》 插件中还大量使用了Promises/A+规范,关于这个规范可以参考《JavaScript中Promises/A+规范的实现》 exif.getData(typeof file === 'object' ? file : img, function() { orientation = exif.getTag(this, "Orientation"); //计算逻辑.... }); 2.“<=IOS7”系统的计算方式略有不同。IOS6中图片拍照上传会被压扁(当照片超过2M时),这是IOS6的BUG,较大的图片可能会发生。 计算逻辑也可以参考localResizeIMG插件165行。要解决这个BUG需要引入megapix-image.js。 require(['megapix-image'], function(MegaPixImage) { var mpImg = new MegaPixImage(img); //计算逻辑 }); 2)将画布“canvas”通过方法“toDataURL”,变成dataURL格式 1. 在手机QQ浏览器中,canvas对象使用toDataURL方法获取不到任何数据,需要引用jpeg-encoder.js解决。 var cvs = document.createElement('canvas'); var ctx = cvs.getContext("2d"); ctx.drawImage(theImg, 0, 0); var theImgData = ctx.getImageData(0, 0, cvs.width, cvs.height); // Encode the image and get a URI back, toRaw is false by default var jpegURI = encoder.encode(theImgData, quality); 在开发的时候方向自动旋转花了很多时间。碰到各种问题,例如“orientation”属性获取不到、自动旋转的角度不对。 后面贪简单,就找了个canvasResize插件,虽然会自动校正,但是图片有点模糊,而且图片的宽高不容易控制。效果不尽如意,只好分两步做。 最终的过程: 1)添加旋转页面 先计算起始坐标点X与Y,简单点就是宽度和高度各除以2,再通过canvas的“translate”,再用“rotate”计算角度。在“drawImage”的时候X和Y点变成负数,移位过去。 var xpos = canvas_width / 2; var ypos = canvas_height / 2; ctx.translate(xpos, ypos); ctx.rotate(angle * Math.PI / 180); ctx.drawImage(rotate_img, -width / 2, -height / 2, width, height); 三、合成 在上图中点击确认就会自动合成。 1)图片宽高自适应 画布的宽高只做了简单的比率,画布的宽度除以图片的宽度,我把头部的图片和底部的图片宽度都做的相同,下图所示: var multiple = width / header.width;//画布宽度除以图片宽度 var header_height = header.height * multiple;//顶部图片 var footer_height = footer.height * multiple;//底部图片 var footer_y = canvas_height - footer_height; 2)将顶部与底部图片、与上一个旋转后的canvas画一起在第二个画布上 ctx.drawImage(rotate_canvas, 0, 0, width, height); ctx.drawImage(header, 0, 25, width, header_height); ctx.drawImage(footer, 0, footer_y, width, footer_height); 这里碰到了一个画布污染的问题。上面的“rotate_canvas”,图片的获取有两种,一个是通过“file”控件上传的,另一个是在webview提供的接口上传的。 两个唯一的不同是跨域,第二个接口返回的是另外一个域名中的图片。图片跨域了,那么rotate_canvas也算是跨域了。 跨域的话,会影响“toDataURL()”方法。这个时候就需要img图片跨域。 1.图片设置crossOrigin属性,这是一个HTML5属性,兼容性不是很好,测试了几台Android机,有的行,有的不行。“crossOrigin”属性设置要在“src”之前,否则IOS不可使用。 rotate_img.crossOrigin = "Anonymous"; 2. 服务器需要设置,可以正确响应 Access-Control-Allow-Origin 头。 调试的时候,如果服务器还没配置,可以用Fiddler模拟响应头。 a. 先找到filter选项 b.设置请求头 c.设置响应头,注意与请求头中的内容要一模一样,少个“http”都不行 参考资料: H5拍照应用开发经历的那些坑儿 图片自动旋转的前端实现方案 JPEG Rotation and EXIF Orientation 利用exif.js解决ios手机上传竖拍照片旋转90度问题 Html5 create thumbnail 本文转自 咖啡机(K.F.J) 博客园博客,原文链接:http://www.cnblogs.com/strick/p/5183570.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

【移动开发】Android中WIFI开发总结(二)

搞了好几天终于有点眉目了,这里接着总结一下Android中WiFi的使用,在前面(http://smallwoniu.blog.51cto.com/3911954/1334951)我们已经简单了解了Wifi实际操作中所用到的几个主要类,今天就剖析一个WIFI搜索、创建、关闭、连接及一些简单的动画的综合案例。 首先,我们还是看一下我们项目的框架 MainActivity类:(处理wifi消息,加载UI) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 /** * 主界面 * @author ZHF * */ public class MainActivity extends Activity implements EventHandler{ //消息事件 public static final int m_nWifiSearchTimeOut = 0 ; // 搜索超时 public static final int m_nWTScanResult = 1 ; // 搜索到wifi返回结果 public static final int m_nWTConnectResult = 2 ; // 连接上wifi热点 public static final int m_nCreateAPResult = 3 ; // 创建热点结果 public static final int m_nUserResult = 4 ; // 用户上线人数更新命令(待定) public static final int m_nWTConnected = 5 ; // 点击连接后断开wifi,3.5秒后刷新adapter //一些常量 public static final String PACKAGE_NAME = "com.zhf.wifidemo.wifi" ; //应用包名 public static final String FIRST_OPEN_KEY = "version" ; //版本号信息 public static final String WIFI_AP_HEADER = "zhf_" ; public static final String WIFI_AP_PASSWORD = "zhf12345" ; //wifi操作事件(枚举)-->方便弹出对话框处理事件 private int wFOperateEnum = WFOperateEnum.NOTHING; //三个重要的类 public WFSearchProcess m_wtSearchProcess; //WiFi搜索进度条线程 public WifiAdmin m_wiFiAdmin; //Wifi管理类 public CreateAPProcess m_createAPProcess; //创建Wifi热点线程 //相关控件 private WFSearchAnimationFrameLayout m_FrameLWTSearchAnimation; //自定义雷达动画布局 private GifView m_gifRadar; //wifi信号动画布局 private LinearLayout m_linearLCreateAP; //创建热点View private ProgressBar m_progBarCreatingAP; //创建热点进度条 private TextView m_textVPromptAP; //创建热点进度条文字 private Button m_btnBack; //左上角返回按钮 private Button m_btnSearchWF; //右上角wifi搜索按钮 private Button m_btnCreateWF; //创建wifi热点 private ListView m_listVWT; //显示信息 private LinearLayout m_LinearLDialog; //提醒对话框 private TextView m_textVContentDialog; //对话框文本内容 private Button m_btnConfirmDialog, m_btnCancelDialog; //提醒对话框上的按钮 private TextView m_textVWTPrompt; //中间文字提示 private boolean m_isFirstOpen = true ; //标记是否是第一次打开 ArrayList<ScanResult> m_listWifi = new ArrayList(); //检测到热点信息列表 private WTAdapter m_wTAdapter; //网络列表适配器 public Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case m_nWifiSearchTimeOut: // 搜索超时 m_wtSearchProcess.stop(); m_FrameLWTSearchAnimation.stopAnimation(); m_listWifi.clear(); //网络列表 //设置控件 m_textVWTPrompt.setVisibility(View.VISIBLE); m_textVWTPrompt.setText( "需要重新搜索,点右上角重新搜索或创建新的热点..." ); break ; case m_nWTScanResult: //扫描到结果 m_listWifi.clear(); if (m_wiFiAdmin.mWifiManager.getScanResults() != null ) { for ( int i = 0 ; i < m_wiFiAdmin.mWifiManager.getScanResults().size(); i++) { ScanResult scanResult = m_wiFiAdmin.mWifiManager.getScanResults().get(i); //和指定连接热点比较,将其他的过滤掉! if (scanResult.SSID.startsWith(WIFI_AP_HEADER)) { m_listWifi.add(scanResult); } } if (m_listWifi.size() > 0 ) { m_wtSearchProcess.stop(); m_FrameLWTSearchAnimation.stopAnimation(); m_textVWTPrompt.setVisibility(View.GONE); //更新列表,显示出搜索到的热点 m_wTAdapter.setData(m_listWifi); m_wTAdapter.notifyDataSetChanged(); } } break ; case m_nWTConnectResult: //连接结果 m_wTAdapter.notifyDataSetChanged(); //刷新适配器数据 break ; case m_nCreateAPResult: //创建wifi热点结果 m_createAPProcess.stop(); m_progBarCreatingAP.setVisibility(View.GONE); //旋转进度条 if ((m_wiFiAdmin.getWifiApState() == 3 || m_wiFiAdmin.getWifiApState() == 13 ) && (m_wiFiAdmin.getApSSID().startsWith(WIFI_AP_HEADER))) { //设置控件 m_textVWTPrompt.setVisibility(View.GONE); m_linearLCreateAP.setVisibility(View.VISIBLE); m_btnCreateWF.setVisibility(View.VISIBLE); m_gifRadar.setVisibility(View.VISIBLE); m_btnCreateWF.setBackgroundResource(R.drawable.x_ap_close); m_textVPromptAP.setText( "热点创建成功!" + "\n热点名:" + m_wiFiAdmin.getApSSID()+ "\n连接密码:zhf12345" ); } else { m_btnCreateWF.setVisibility(View.VISIBLE); m_btnCreateWF.setBackgroundResource(R.drawable.x_wt_create); m_textVPromptAP.setText( "热点创建失败,您可以重新创建或者搜索其它热点" ); } break ; case m_nUserResult : //更新用户上线人数 break ; case m_nWTConnected: //点击连接后断开wifi,3.5s后刷新 m_wTAdapter.notifyDataSetChanged(); break ; } }; }; @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.wt_main); //搜索Wifi m_wtSearchProcess = new WFSearchProcess( this ); //创建Wifi热点 m_createAPProcess = new CreateAPProcess( this ); //wifi管理类 m_wiFiAdmin = WifiAdmin.getInstance( this ); //初始化View initView(); } /**初始化View**/ private void initView() { // 监听广播 WIFIBroadcast.ehList.add( this ); /******************************实例化布局**************************************/ m_linearLCreateAP = (LinearLayout) findViewById(R.id.create_ap_llayout_wt_main); //创建热点View m_progBarCreatingAP = (ProgressBar) findViewById(R.id.creating_progressBar_wt_main); //创建热点进度条 m_textVPromptAP = (TextView) findViewById(R.id.prompt_ap_text_wt_main); //创建热点进度条文字 m_FrameLWTSearchAnimation = ((WFSearchAnimationFrameLayout) findViewById(R.id.search_animation_wt_main)); // 搜索时的动画 m_listVWT = ((ListView) findViewById(R.id.wt_list_wt_main)); // 搜索到的热点listView //注意此处 m_wTAdapter = new WTAdapter( this , m_listWifi); m_listVWT.setAdapter(m_wTAdapter); m_textVWTPrompt = (TextView) findViewById(R.id.wt_prompt_wt_main); //中间提醒文字 m_gifRadar = (GifView) findViewById(R.id.radar_gif_wt_main); //gif动画 //提醒对话框布局 m_LinearLDialog = (LinearLayout) findViewById(R.id.dialog_layout_wt_main); m_textVContentDialog = (TextView) findViewById(R.id.content_text_wtdialog); m_btnConfirmDialog = (Button) findViewById(R.id.confirm_btn_wtdialog); m_btnCancelDialog = (Button) findViewById(R.id.cancel_btn_wtdialog); //左上角返回键 m_btnBack = (Button) findViewById(R.id.back_btn_wt_main); m_btnBack.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { onBackPressed(); //相当于调用系统返回键,结束当前Activity } }); //右上角搜索热点按钮 m_btnSearchWF = (Button) findViewById(R.id.search_btn_wt_main); m_btnSearchWF.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { if (!m_wtSearchProcess.running) { //搜索线程没有开启 //1.当前热点或wifi连接着 WIFI_STATE_ENABLED 3 //WIFI_AP_STATE_ENABLED 13 if (m_wiFiAdmin.getWifiApState() == 3 || m_wiFiAdmin.getWifiApState() == 13 ) { wFOperateEnum = WFOperateEnum.SEARCH; //搜索wifi事件 m_LinearLDialog.setVisibility(View.VISIBLE); ///wifi提示对话框显示 m_textVContentDialog.setText( "是否关闭当前热点去搜索其他热点?" ); return ; //跳出此方法,交由对话框来处理事件 } //2.当前没有热点或wifi连接着 if (!m_wiFiAdmin.mWifiManager.isWifiEnabled()) { //如果wifi没打开 m_wiFiAdmin.OpenWifi(); } m_textVWTPrompt.setVisibility(View.VISIBLE); //中间提示文字 m_textVWTPrompt.setText( "正在搜索附近的热点..." ); m_linearLCreateAP.setVisibility(View.GONE); //创建wifi热点布局消失 m_gifRadar.setVisibility(View.GONE); //热点连接动画消失 m_btnCreateWF.setBackgroundResource(R.drawable.x_wt_create); //更改按钮文字“创建” //开始搜索wifi m_wiFiAdmin.startScan(); m_wtSearchProcess.start(); //开启搜索线程 m_FrameLWTSearchAnimation.startAnimation(); //开启波纹动画 } else { //搜索线程开启着,再次点击按钮 //重新启动 m_wtSearchProcess.stop(); m_wiFiAdmin.startScan(); //开始搜索wifi m_wtSearchProcess.start(); } } }); //中间创建wifi热点按钮 m_btnCreateWF = (Button) findViewById(R.id.create_btn_wt_main); m_btnCreateWF.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { if (m_wiFiAdmin.getWifiApState() == 4 ) { // WIFI_STATE_UNKNOWN Toast.makeText(getApplicationContext(), "您的设备不支持热点创建!" , Toast.LENGTH_SHORT).show(); return ; } if (m_wiFiAdmin.mWifiManager.isWifiEnabled()) { //目前连着wifi wFOperateEnum = WFOperateEnum.CREATE; //wifi热点创建事件 m_LinearLDialog.setVisibility(View.VISIBLE); //对话框可用 m_textVContentDialog.setText( "创建热点会关闭当前的WiFi,确认继续?" ); return ; } if ((m_wiFiAdmin.getWifiApState() == 3 || m_wiFiAdmin.getWifiApState() == 13 ) && (!m_wiFiAdmin.getApSSID().startsWith(WIFI_AP_HEADER))) { //目前连接着其他热点名 wFOperateEnum = WFOperateEnum.CREATE; //wifi热点创建事件 m_LinearLDialog.setVisibility(View.VISIBLE); m_textVContentDialog.setText( "系统热点被占用,点确定开启热点以传输文件!" ); return ; } if (((m_wiFiAdmin.getWifiApState() == 3 ) || (m_wiFiAdmin.getWifiApState() == 13 )) && (m_wiFiAdmin.getApSSID().startsWith(WIFI_AP_HEADER))) { //目前连接着自己指定的Wifi热点 wFOperateEnum = WFOperateEnum.CLOSE; //wifi热点关闭事件 m_LinearLDialog.setVisibility(View.VISIBLE); m_textVContentDialog.setText( "关闭热点会中断当前传输,您确定这么做?" ); return ; } if (m_wtSearchProcess.running) { m_wtSearchProcess.stop(); //停止线程 m_FrameLWTSearchAnimation.stopAnimation(); //停止动画 } /******************点击创建热点时没有连接wifi或热点的情况*****************************/ //关闭Wifi m_wiFiAdmin.closeWifi(); //创建热点(名字,密码,加密类型,wifi/ap类型) m_wiFiAdmin.createWifiAP(m_wiFiAdmin.createWifiInfo(WIFI_AP_HEADER + getLocalHostName(), WIFI_AP_PASSWORD, 3 , "ap" ), true ); m_createAPProcess.start(); //开启创建热点线程 //将wifi信息列表设置到listview中 m_listWifi.clear(); m_wTAdapter.setData(m_listWifi); m_wTAdapter.notifyDataSetChanged(); //设置布局 m_linearLCreateAP.setVisibility(View.VISIBLE); //热点布局可用 m_progBarCreatingAP.setVisibility(View.VISIBLE); m_textVPromptAP.setText( "正在创建热点" ); //进度条文字 m_btnCreateWF.setVisibility(View.GONE); //点击一次不可再点 m_textVWTPrompt.setVisibility(View.GONE); } }); //对话框确认按钮 m_btnConfirmDialog.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { m_LinearLDialog.setVisibility(View.GONE); //让对话框布局消失 switch (wFOperateEnum) { //根据wifi操作事件 case WFOperateEnum.CLOSE: //关闭wifi热点 //设置布局 m_textVWTPrompt.setVisibility(View.VISIBLE); m_textVWTPrompt.setText( "热点已关闭!可以进行其他操作了!" ); //中间提醒文字 m_btnCreateWF.setBackgroundResource(R.drawable.x_wt_create); //按钮文字改回“创建” m_gifRadar.setVisibility(View.GONE); //热点动画停止 m_linearLCreateAP.setVisibility(View.GONE); //下部创建热点布局不可用 //关闭热点 m_wiFiAdmin.createWifiAP(m_wiFiAdmin.createWifiInfo(m_wiFiAdmin.getApSSID(), "zhf123456" , 3 , "ap" ), false ); break ; case WFOperateEnum.CREATE: //创建wifi热点 if (m_wtSearchProcess.running) { m_wtSearchProcess.stop(); //搜索wifi线程停止 m_FrameLWTSearchAnimation.stopAnimation(); //搜索wifi动画停止 } //关闭wifi m_wiFiAdmin.closeWifi(); //创建WiFi热点 m_wiFiAdmin.createWifiAP(m_wiFiAdmin.createWifiInfo(WIFI_AP_HEADER + getLocalHostName(), WIFI_AP_PASSWORD, 3 , "ap" ), true ); m_createAPProcess.start(); //刷新listView布局 m_listWifi.clear(); m_wTAdapter.setData(m_listWifi); m_wTAdapter.notifyDataSetChanged(); //设置布局 m_linearLCreateAP.setVisibility(View.VISIBLE); m_progBarCreatingAP.setVisibility(View.VISIBLE); //旋转进度条 m_btnCreateWF.setVisibility(View.GONE); m_textVWTPrompt.setVisibility(View.GONE); m_textVPromptAP.setText( "正在创建热点..." ); //进度条文字 break ; case WFOperateEnum.SEARCH: //搜索可用热点 //设置布局 m_textVWTPrompt.setVisibility(View.VISIBLE); m_textVWTPrompt.setText( "正在搜索附近的热点..." ); m_linearLCreateAP.setVisibility(View.GONE); //创建热点布局不可用 m_btnCreateWF.setVisibility(View.VISIBLE); m_btnCreateWF.setBackgroundResource(R.drawable.x_wt_create); //按钮文字改回“创建” m_gifRadar.setVisibility(View.GONE); //热点动画停止 m_linearLCreateAP.setVisibility(View.GONE); //下部创建热点布局不可用 //搜索热点线程关闭 if (m_createAPProcess.running) m_createAPProcess.stop(); //关闭热点 m_wiFiAdmin.createWifiAP(m_wiFiAdmin.createWifiInfo(m_wiFiAdmin.getApSSID(), WIFI_AP_PASSWORD, 3 , "ap" ), false ); //打开wifi m_wiFiAdmin.OpenWifi(); m_wtSearchProcess.start(); m_FrameLWTSearchAnimation.startAnimation(); break ; } } }); //对话框取消按钮事件 m_btnCancelDialog.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { //对话框布局消失 m_LinearLDialog.setVisibility(View.GONE); } }); } /**Wifi是否连接**/ private boolean isWifiConnect() { boolean isConnect = true ; //用于网络连接状态的检测 ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); if (!cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnected()) isConnect = false ; return isConnect; } /**获取wifi热点状态**/ public boolean getWifiApState() { try { WifiManager localWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); Method m = localWifiManager.getClass().getMethod( "getWifiApState" , new Class[ 0 ]); int i = (Integer)(m.invoke(localWifiManager, new Object[ 0 ])); return ( 3 == i) || ( 13 == i); //WIFI_STATE_ENABLED 3 //WIFI_AP_STATE_ENABLED 13 } catch (Exception e) { e.printStackTrace(); } return false ; } /**获取手机信息**/ public String getLocalHostName() { String str1 = Build.BRAND; //主板 String str2 = Build.MODEL; //机型 if (- 1 == str2.toUpperCase().indexOf(str1.toUpperCase())) str2 = str1 + "_" + str2; return str2; } private void init() { //线程是否在运行 if ( this .m_wtSearchProcess.running || this .m_createAPProcess.running) { return ; } //没有连接上wifi或者是wifi热点 if (!isWifiConnect() && !getWifiApState()) { m_wiFiAdmin.OpenWifi(); m_wtSearchProcess.start(); //开启搜索wifi超时检测线程 m_wiFiAdmin.startScan(); //开启搜索wifi //开启搜索动画 m_FrameLWTSearchAnimation.startAnimation(); //设置控件 m_textVWTPrompt.setVisibility(View.VISIBLE); m_textVWTPrompt.setText( " 正在搜索附近的热点..." ); m_linearLCreateAP.setVisibility(View.GONE); m_btnCreateWF.setBackgroundResource(R.drawable.x_wt_create); } //连接上wifi if (isWifiConnect()) { this .m_wiFiAdmin.startScan(); this .m_wtSearchProcess.start(); this .m_FrameLWTSearchAnimation.startAnimation(); //设置控件 this .m_textVWTPrompt.setVisibility( 0 ); this .m_textVWTPrompt.setText( "正在搜索附近的热点..." ); this .m_linearLCreateAP.setVisibility(View.GONE); this .m_btnCreateWF.setBackgroundResource(R.drawable.x_wt_create); this .m_gifRadar.setVisibility(View.GONE); m_listWifi.clear(); if (m_wiFiAdmin.mWifiManager.getScanResults() != null ) { for ( int i = 0 ; i < m_wiFiAdmin.mWifiManager.getScanResults().size(); i++) { //识别出自己自定连接的wifi if (m_wiFiAdmin.mWifiManager.getScanResults().get(i).SSID.startsWith(WIFI_AP_HEADER)) { m_listWifi.add(m_wiFiAdmin.mWifiManager.getScanResults().get(i)); //将指定wifi添加进去 } } m_wTAdapter.setData(m_listWifi); //将连接的信息添加到listView中 m_wTAdapter.notifyDataSetChanged(); } //连接上wifi热点 if (getWifiApState()){ if (m_wiFiAdmin.getApSSID().startsWith(WIFI_AP_HEADER)) { //设置控件 m_textVWTPrompt.setVisibility(View.GONE); m_linearLCreateAP.setVisibility(View.VISIBLE); m_progBarCreatingAP.setVisibility(View.GONE); m_btnCreateWF.setVisibility(View.VISIBLE); m_gifRadar.setVisibility(View.VISIBLE); m_btnCreateWF.setBackgroundResource(R.drawable.x_ap_close); m_textVPromptAP.setText( "\n热点名:" + m_wiFiAdmin.getApSSID() + "\n连接密码:zhf12345" ); } } } } @Override protected void onDestroy() { // TODO Auto-generated method stub super .onDestroy(); WIFIBroadcast.ehList.remove( this ); } @Override public void handleConnectChange() { Message msg = mHandler.obtainMessage(m_nWTConnectResult); mHandler.sendMessage(msg); } @Override public void scanResultsAvaiable() { Message msg = mHandler.obtainMessage(m_nWTScanResult); mHandler.sendMessage(msg); } @Override public void wifiStatusNotification() { m_wiFiAdmin.mWifiManager.getWifiState(); //获取当前wifi状态 } } 貌似有点长。。。简单说明一下: 1.首先,初始化主界面(xml有些复杂,慢慢理一下就好了,不是什么大问题)接下来,处理三个重要的按钮事件:右上角的搜索wifi按钮、中间创建或关闭热点按钮、对话框中确定按钮。处理前两者事件时,需关注当前wifi状态,若为占用,需弹出提醒对话框来根据当前WiFi操作(WFOperateEnum类中定义好了)事件,来创建、关闭、搜索等具体事务。 2.之所以定义广播接收者,是为了监听当wifi状态发生变化时,能够及时更新界面 广播接收者WIFIBroadcast类: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package com.zhf.wifidemo.broadcast; import java.util.ArrayList; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.net.wifi.WifiManager; import android.util.Log; /** * 监听wifi热点变化 * @author ZHF * */ public class WIFIBroadcast extends BroadcastReceiver{ public static ArrayList<EventHandler> ehList = new ArrayList<EventHandler>(); @Override public void onReceive(Context context, Intent intent) { //搜索到wifi热点结果的广播: "android.net.wifi.SCAN_RESULTS" if (intent.getAction().endsWith(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { Log.i( "WTScanResults---->扫描到了可用网络---->" , "android.net.wifi.SCAN_RESULTS" ); //遍历通知各个监听接口 for ( int i = 0 ; i < ehList.size(); i++) { ((EventHandler)ehList.get(i)).scanResultsAvaiable(); } //wifi打开或关闭状态变化 "android.net.wifi.WIFI_STATE_CHANGED" } else if (intent.getAction().endsWith(WifiManager.WIFI_STATE_CHANGED_ACTION)) { Log.i( "WTScanResults----->wifi状态变化--->" , "android.net.wifi.WIFI_STATE_CHANGED" ); //这里不需要连接一个SSID(wifi名称) for ( int j = 0 ; j < ehList.size(); j++) { ((EventHandler)ehList.get(j)).wifiStatusNotification(); } //连接上一个SSID后发出的广播,(注:与android.net.wifi.WIFI_STATE_CHANGED的区别) } else if (intent.getAction().endsWith(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { Log.i( "WTScanResults----->网络状态变化---->" , "android.net.wifi.STATE_CHANGE" ); for ( int m = 0 ; m < ehList.size(); m++) { ((EventHandler)ehList.get(m)).handleConnectChange(); } } } /** * 事件监听接口 * @author ZHF * */ public static abstract interface EventHandler { /**处理连接变化事件**/ public abstract void handleConnectChange(); /**扫描结果是有效事件**/ public abstract void scanResultsAvaiable(); /**wifi状态变化事件**/ public abstract void wifiStatusNotification(); } } 说明:监听系统wifi状态变化,内部定义了一个事件处理接口,当wifi状态发生变化时,让其实现类去发送消息更新界面。 CreateAPProcess类: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package com.zhf.wifidemo.ui; import android.net.wifi.WifiManager; import android.os.Message; import com.zhf.wifidemo.wifi.MainActivity; /** * 创建Wifi热点 * @author ZHF * */ public class CreateAPProcess implements Runnable{ public MainActivity context; public boolean running = false ; private long startTime = 0L; private Thread thread = null ; public CreateAPProcess(MainActivity context) { super (); this .context = context; } @Override public void run() { while ( true ) { if (!running) return ; //WIFI_STATE_ENABLED 3 //WIFI_AP_STATE_ENABLED 13 if ((context.m_wiFiAdmin.getWifiApState() == WifiManager.WIFI_STATE_ENABLED) || (context.m_wiFiAdmin.getWifiApState() == 13 ) || (System.currentTimeMillis() - this .startTime >= 30000L)){ //wifi可用 或 热点可用 Message msg = context.mHandler.obtainMessage(context.m_nCreateAPResult); context.mHandler.sendMessage(msg); } try { Thread.sleep(5L); } catch (Exception e) { e.printStackTrace(); } } } public void start() { try { thread = new Thread( this ); running = true ; startTime = System.currentTimeMillis(); thread.start(); //开启线程 } catch (Exception e) { e.printStackTrace(); } } public void stop() { try { running = false ; thread = null ; startTime = 0L; } catch (Exception e) { // TODO: handle exception } } } 其他类文件具体看源码,当创建一个热点成功后,等待其他客户端搜索 上图: WIFIAdapte类: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 /** * 网络列表适配器 * @author ZHF * */ public class WTAdapter extends BaseAdapter { private LayoutInflater mInflater; private List<ScanResult> mList; //扫描到的网络结果列表 private MainActivity mContext; public WTAdapter(MainActivity context, List<ScanResult> list) { // TODO Auto-generated constructor stub this .mContext = context; this .mList = list; this .mInflater = LayoutInflater.from(context); } //新加的一个函数,用来更新数据 public void setData(List<ScanResult> list) { this .mList = list; notifyDataSetChanged(); } @Override public int getCount() { return mList.size(); } @Override public Object getItem( int position) { return mList.get(position); } @Override public long getItemId( int position) { return position; } @Override public View getView( final int position, View convertView, ViewGroup parent) { //获取点击向的扫描结果 final ScanResult localScanResult = mList.get(position); //获取wifi类 // final WifiAdmin wifiAdmin = WifiAdmin.getInstance(mContext); final WifiAdmin wifiAdmin = mContext.m_wiFiAdmin; final ViewHolder viewHolder; if (convertView == null ) { viewHolder = new ViewHolder(); convertView = mInflater.inflate(R.layout.wtitem, null ); //加载布局模板控件 viewHolder.textVName = ((TextView) convertView.findViewById(R.id.name_text_wtitem)); viewHolder.textConnect = ((TextView) convertView.findViewById(R.id.connect_text_wtitem)); viewHolder.linearLConnectOk = ((LinearLayout) convertView.findViewById(R.id.connect_ok_layout_wtitem)); viewHolder.progressBConnecting = ((ProgressBar) convertView.findViewById(R.id.connecting_progressBar_wtitem)); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } //点击连接处理事件 viewHolder.textConnect.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { //创建wifi网络 WifiConfiguration localWifiConfiguration = wifiAdmin.createWifiInfo(localScanResult.SSID, MainActivity.WIFI_AP_PASSWORD, 3 , "wt" ); //添加到网络 wifiAdmin.addNetwork(localWifiConfiguration); //"点击链接"消失,显示进度条, viewHolder.textConnect.setVisibility(View.GONE); viewHolder.progressBConnecting.setVisibility(View.VISIBLE); viewHolder.linearLConnectOk.setVisibility(View.GONE); //点击后3.5s发送消息 mContext.mHandler.sendEmptyMessageDelayed(mContext.m_nWTConnected, 3500L); } }); // 点击断开处理事件 viewHolder.linearLConnectOk.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { //断开指定wifi热点 wifiAdmin.disconnectWifi(wifiAdmin.getWifiInfo().getNetworkId()); //"断开连接"消失,进度条显示 viewHolder.textConnect.setVisibility(View.GONE); viewHolder.progressBConnecting.setVisibility(View.VISIBLE); viewHolder.linearLConnectOk.setVisibility(View.GONE); //点击后3.5s发送消息 mContext.mHandler.sendEmptyMessageDelayed(mContext.m_nWTConnected, 3500L); } }); //初始化布局 viewHolder.textConnect.setVisibility(View.GONE); viewHolder.progressBConnecting.setVisibility(View.GONE); viewHolder.linearLConnectOk.setVisibility(View.GONE); viewHolder.textVName.setText(localScanResult.SSID); //显示热点名称 // 正连接的wifi信息 WifiInfo localWifiInfo = wifiAdmin.getWifiInfo(); if (localWifiInfo != null ) { try { //正在连接 if ((localWifiInfo.getSSID() != null )&& (localWifiInfo.getSSID().equals(localScanResult.SSID))) { viewHolder.linearLConnectOk.setVisibility(View.VISIBLE); return convertView; } } catch (NullPointerException e) { e.printStackTrace(); return convertView; } viewHolder.textConnect.setVisibility(View.VISIBLE); } return convertView; } public final class ViewHolder { public LinearLayout linearLConnectOk; public ProgressBar progressBConnecting; public TextView textConnect; public TextView textVName; } } 点击连接,实现客户连接,此时他们将处于同一网段内,接下来就可以自己实现传输数据,操控等一系列操作了。 在下一篇中我会继实现一个基于wif热点的多人聊天室,希望能帮助到大家! 源码:http://down.51cto.com/data/1036876 本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1338618,如需转载请自行联系原作者

优秀的个人博客,低调大师

【移动开发】Android波纹动画效果实现

今天我实现一个wifi当中搜索时的动画效果,通常我们会使用多张图片进行Frame动画播放,这里我使用了Tween动画,仅对一张图片进行操作,实现了wifi扫描动画效果,有兴趣的可以看看! 效果图: 这里我们采用了自定义布局的方式 activity_main.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 < 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" > < com.zhf.android_ripple.AnimationFrameLayout android:id = "@+id/search_animation_wf_main" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > </ com.zhf.android_ripple.AnimationFrameLayout > < Button android:id = "@+id/button1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_alignParentRight = "true" android:text = "开启波纹动画" /> </ RelativeLayout > AnimationFrameLayout类: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 package com.zhf.android_ripple; import java.lang.ref.SoftReference; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationSet; import android.view.animation.ScaleAnimation; import android.widget.FrameLayout; import android.widget.ImageView; public class AnimationFrameLayout extends FrameLayout { private SoftReference<Bitmap> m_bitmapRipple; //波纹图片 (软引用) private ImageView[] m_imageVRadars; //ImageView数组 public AnimationFrameLayout(Context context) { super (context); init(); } public AnimationFrameLayout(Context context, AttributeSet attrs, int defStyle) { super (context, attrs, defStyle); init(); } public AnimationFrameLayout(Context context, AttributeSet attrs) { super (context, attrs); init(); } /**初始化**/ private void init() { loadRadarBitmap(); m_imageVRadars = new ImageView[ 3 ]; View v = LayoutInflater.from(getContext()).inflate(R.layout.wt_search_device_anima, this ); m_imageVRadars[ 0 ] = (ImageView) v.findViewById(R.id.radar_ray_1); m_imageVRadars[ 1 ] = (ImageView) v.findViewById(R.id.radar_ray_2); m_imageVRadars[ 2 ] = (ImageView) v.findViewById(R.id.radar_ray_3); } /**加载图片**/ private void loadRadarBitmap() { try { //获取波纹图片 m_bitmapRipple = new SoftReference<Bitmap>(BitmapFactory.decodeStream(getContext().getResources() .openRawResource(R.drawable.wifi_body_ripple))); } catch (Exception localException) { Log.e( "WTSearchAnimationFrameLayout" , Log.getStackTraceString(localException)); } catch (OutOfMemoryError localOutOfMemoryError) { Log.e( "WTSearchAnimationFrameLayout" , Log.getStackTraceString(localOutOfMemoryError)); System.gc(); //回收 } } /**重置,停止动画**/ public void stopAnimation() { for ( int i= 0 ; i< m_imageVRadars.length; ++i) { if (m_bitmapRipple != null ){ Bitmap localBitmap = m_bitmapRipple.get(); //软引用获取对象 if (localBitmap != null && !localBitmap.isRecycled()) { //回收图片资源 localBitmap.recycle(); } m_bitmapRipple = null ; ImageView localImageView = m_imageVRadars[i]; localImageView.setImageBitmap( null ); //设置ImageView为空 localImageView.setVisibility(View.GONE); localImageView.clearAnimation(); //取消动画 } } } /**开始动画**/ public void startAnimation() { if (m_bitmapRipple == null ) { loadRadarBitmap(); } for ( int i = 0 ; i < m_imageVRadars.length; i++) { ImageView localImageView; long ltime; while ( true ) { localImageView = m_imageVRadars[i]; localImageView.setImageBitmap(m_bitmapRipple.get()); //获取图片 localImageView.setVisibility(View.VISIBLE); //放大 ltime= 333L * i; if (localImageView.getAnimation() == null ) { break ; } localImageView.getAnimation().start(); } ScaleAnimation localScaleAnimation = new ScaleAnimation( 1 .0f, 14 .0f, 1 .0f, 14 .0f, 1 , 0 .5f, 1 , 0 .5f); localScaleAnimation.setRepeatCount(- 1 ); //动画重复 AlphaAnimation localAlphaAnimation = new AlphaAnimation( 1 .0f, 0 .2f); AnimationSet localAnimationSet = new AnimationSet( true ); //true:使用相同的加速器 localAnimationSet.addAnimation(localScaleAnimation); localAnimationSet.addAnimation(localAlphaAnimation); //将两种动画效果添加进去 //设置相关属性 localAnimationSet.setDuration(1000L); //持续时间 localAnimationSet.setFillEnabled( true ); localAnimationSet.setFillBefore( true ); //控件保持在动画开始之前 localAnimationSet.setStartOffset(ltime); //动画效果推迟ltime秒钟后启动 localAnimationSet.setInterpolator( new AccelerateDecelerateInterpolator()); localAnimationSet.setAnimationListener( new MySearchAnimationHandler( this ,localImageView)); //绑定监听器 //将动画集合设置进去 localImageView.setAnimation(localAnimationSet); localImageView.startAnimation(localAnimationSet); //开启动画 } } /**动画监听类**/ public class MySearchAnimationHandler implements AnimationListener{ private ImageView m_imageVRadar; public MySearchAnimationHandler(AnimationFrameLayout paramImageView,ImageView m_imageVRadar) { super (); this .m_imageVRadar = m_imageVRadar; } @Override public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub } @Override public void onAnimationEnd(Animation animation) { this .m_imageVRadar.setVisibility(View.GONE); } @Override public void onAnimationRepeat(Animation animation) { animation.setStartOffset(0L); } } } 重要说明: 1.该类中我们对图片的操作使用软引用,目的是防止OOM. 2.至于动画,使用ImageView[]来依次加载图片,通过更改对每个ImageView实现缩放和透明动画 动画布局 wt_search_device_anima.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <? xml version = "1.0" encoding = "utf-8" ?> < RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > < ImageView android:id = "@+id/radar_ray_1" android:layout_width = "70.0dip" android:layout_height = "70.0dip" android:layout_alignParentRight = "true" android:layout_alignParentTop = "true" android:layout_marginLeft = "10.0dip" /> < ImageView android:id = "@+id/radar_ray_2" android:layout_width = "70.0dip" android:layout_height = "70.0dip" android:layout_alignParentRight = "true" android:layout_alignParentTop = "true" android:layout_marginLeft = "10.0dip" /> < ImageView android:id = "@+id/radar_ray_3" android:layout_width = "70.0dip" android:layout_height = "70.0dip" android:layout_alignParentRight = "true" android:layout_alignParentTop = "true" android:layout_marginLeft = "10.0dip" /> </ RelativeLayout > 程序主入口: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package com.zhf.android_ripple; import android.os.Bundle; import android.app.Activity; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { public Button m_btn1; AnimationFrameLayout afl; //动画布局 @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); afl = ((Animat ionFrameLayout) findViewById(R.id.search_animation_wf_main)); // 搜索时的动画 m_btn1 = (Button) findViewById(R.id.button1); m_btn1.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { afl.startAnimation(); } }); } @Override protected void onDestroy() { // TODO Auto-generated method stub super .onDestroy(); afl.stopAnimation(); } } ok! 源码已添加!试试效果吧! 本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1334425,如需转载请自行联系原作者

优秀的个人博客,低调大师

【移动开发】Android无线调试 使用adbWireless软件

最近发现一款名为adbWireless的软件,很好玩!不通过USB线就可以进行真机调试的方法: 1.先到网上下一款dbWireless(http://www.coolapk.com/apk/siir.es.adbWireless)的软件,安装到手机上 2.之后让手机(前提手机必须root过)与电脑处于同一局域网下 3.点击界面按钮,获取分配的IP,如图: 4.随后打开命令行,进入安装SDK的目录中platform-tools文件夹并输入: adb connect手机IP地址(我的是192.168.0.100)回车,没有出现错误 5.最后看看Eclipse的Device中发现手机已经与电脑连上了,而且来源显示的是IP地址: 随便运行一个工程,手机上成功运行了工程,Log日记和调试信息都可以看到,OK,一切搞定,享受不用USB线开发的生活吧。 本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1248143,如需转载请自行联系原作者

优秀的个人博客,低调大师

【移动开发】Android中WIFI开发总结(一)

WIFI就是一种无线联网技术,常见的是使用无线路由器。那么在这个无线路由器的信号覆盖的范围内都可以采用WIFI连接的方式进行联网。如果无线路由器连接了一个ADSL线路或其他的联网线路,则又被称为“热点”。 在Android中对Wifi操作,android本身提供了一些有用的包,在android.net.wifi包下面,主要包括以下几个类和接口: 1.ScanResult 主要用来描述已经检测出的接入点,包括接入点的地址,接入点的名称,身份认证,频率,信号强度等信息。其实就是通过wifi 硬件的扫描来获取一些周边的wifi 热点的信息。 2.WifiConfiguration Wifi网络的配置,包括安全设置等,在我们连通一个wifi 接入点的时候,需要获取到的一些信息。主要包含四个属性: BSSID: BSS是一种特殊的Ad-hoc LAN(一种支持点对点访问的无线网络应用模式)的应用,一个无线网络至少由一个连接到有线网络的AP和若干无线工作站组成,这种配置称为一个基本服务装置。一群计算机设定相同的 BSS名称,即可自成一个group,而此BSS名称,即所谓BSSID。通常,手机WLAN中,bssid其实就是无线路由的MAC地址。 networkid:网络ID。 PreSharedKey:无线网络的安全认证模式。 SSID:SSID(Service Set Identif)用于标识无线局域网,SSID不同的无线网络是无法进行互访的。 3.WifiInfo wifi无线连接的描述,包括(接入点,网络连接状态,隐藏的接入点,IP地址,连接速度,MAC地址,网络ID,信号强度等信息)。这里简单介绍一下WifiManager中常用的方法: getSSID() 获得SSID(热点名称) getBSSID() 获取BSSID getDetailedStateOf() 获取客户端的连通性 getHiddenSSID() 获得SSID 是否被隐藏 getIpAddress() 获取IP 地址 getLinkSpeed() 获得连接的速度 getMacAddress() 获得Mac 地址 getRssi() 获得802.11n 网络的信号 4.WifiManager wifi连接统一管理类,获取WIFI网卡的状态(WIFI网卡的状态是由一系列的整形常量来表示的) WIFI_STATE_DISABLING = 0 WIFI网卡正在关闭 WIFI_STATE_DISABLED = 1 WIFI网卡不可用 WIFI_STATE_ENABLING = 2 WIFI网正在打开(WIFI启动需要一段时间) WIFI_STATE_ENABLED = 3 WIFI网卡可用 WIFI_STATE_UNKNOWN = 4 未知网卡状态 WIFI_AP_STATE_DISABLING = 10 WIFI热点正在关闭 WIFI_AP_STATE_DISABLED = 11 WIFI热点不可用 WIFI_AP_STATE_ENABLING = 12 WIFI热点正在打开 WIFI_AP_STATE_ENABLED = 13 WIFI热点可用 5. 在AndroidManifest.xml进行对WIFI操作的权限设置 1 2 3 4 5 <!--以下是使用wifi访问网络所需的权限--> <uses-permissionandroid:name= "android.permission.CHANGE_NETWORK_STATE" ></uses-permission> <uses-permissionandroid:name= "android.permission.CHANGE_WIFI_STATE" ></uses-permission> <uses-permissionandroid:name= "android.permission.ACCESS_NETWORK_STATE" ></uses-permission> <uses-permissionandroid:name= "android.permission.ACCESS_WIFI_STATE" ></uses-permission> 下面是汇总的一个wifi管理工具类,我完善了一下,并加上了详细的注解,很实用的! WifiAdmin类: (wifi管理工具类) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 package com.zhf.wifidemo.wifi.utils; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Iterator; import java.util.List; import android.content.Context; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; /** *WIFI管理类 *@authorZHF * */ public class WifiAdmin{ private static WifiAdminwifiAdmin= null ; private List<WifiConfiguration>mWifiConfiguration; //无线网络配置信息类集合(网络连接列表) private List<ScanResult>mWifiList; //检测到接入点信息类集合 //描述任何Wifi连接状态 private WifiInfomWifiInfo; WifiManager.WifiLockmWifilock; //能够阻止wifi进入睡眠状态,使wifi一直处于活跃状态 public WifiManagermWifiManager; /** *获取该类的实例(懒汉) *@paramcontext *@return */ public static WifiAdmingetInstance(Contextcontext){ if (wifiAdmin== null ){ wifiAdmin= new WifiAdmin(context); } return wifiAdmin; } private WifiAdmin(Contextcontext){ //获取系统Wifi服务WIFI_SERVICE this .mWifiManager=(WifiManager)context.getSystemService( "wifi" ); //获取连接信息 this .mWifiInfo= this .mWifiManager.getConnectionInfo(); } /** *是否存在网络信息 *@paramstr热点名称 *@return */ private WifiConfigurationisExsits(Stringstr){ IteratorlocalIterator= this .mWifiManager.getConfiguredNetworks().iterator(); WifiConfigurationlocalWifiConfiguration; do { if (!localIterator.hasNext()) return null ; localWifiConfiguration=(WifiConfiguration)localIterator.next(); } while (!localWifiConfiguration.SSID.equals( "\"" +str+ "\"" )); return localWifiConfiguration; } /**锁定WifiLock,当下载大文件时需要锁定**/ public void AcquireWifiLock(){ this .mWifilock.acquire(); } /**创建一个WifiLock**/ public void CreateWifiLock(){ this .mWifilock= this .mWifiManager.createWifiLock( "Test" ); } /**解锁WifiLock**/ public void ReleaseWifilock(){ if (mWifilock.isHeld()){ //判断时候锁定 mWifilock.acquire(); } } /**打开Wifi**/ public void OpenWifi(){ if (! this .mWifiManager.isWifiEnabled()){ //当前wifi不可用 this .mWifiManager.setWifiEnabled( true ); } } /**关闭Wifi**/ public void closeWifi(){ if (mWifiManager.isWifiEnabled()){ mWifiManager.setWifiEnabled( false ); } } /**端口指定id的wifi**/ public void disconnectWifi( int paramInt){ this .mWifiManager.disableNetwork(paramInt); } /**添加指定网络**/ public void addNetwork(WifiConfigurationparamWifiConfiguration){ int i=mWifiManager.addNetwork(paramWifiConfiguration); mWifiManager.enableNetwork(i, true ); } /** *连接指定配置好的网络 *@paramindex配置好网络的ID */ public void connectConfiguration( int index){ //索引大于配置好的网络索引返回 if (index>mWifiConfiguration.size()){ return ; } //连接配置好的指定ID的网络 mWifiManager.enableNetwork(mWifiConfiguration.get(index).networkId, true ); } /** *根据wifi信息创建或关闭一个热点 *@paramparamWifiConfiguration *@paramparamBoolean关闭标志 */ public void createWifiAP(WifiConfigurationparamWifiConfiguration, boolean paramBoolean){ try { ClasslocalClass= this .mWifiManager.getClass(); Class[]arrayOfClass= new Class[ 2 ]; arrayOfClass[ 0 ]=WifiConfiguration. class ; arrayOfClass[ 1 ]=Boolean.TYPE; MethodlocalMethod=localClass.getMethod( "setWifiApEnabled" ,arrayOfClass); WifiManagerlocalWifiManager= this .mWifiManager; Object[]arrayOfObject= new Object[ 2 ]; arrayOfObject[ 0 ]=paramWifiConfiguration; arrayOfObject[ 1 ]=Boolean.valueOf(paramBoolean); localMethod.invoke(localWifiManager,arrayOfObject); return ; } catch (Exceptione){ e.printStackTrace(); } } /** *创建一个wifi信息 *@paramssid名称 *@parampassawrd密码 *@paramparamInt有3个参数,1是无密码,2是简单密码,3是wap加密 *@paramtype是"ap"还是"wifi" *@return */ public WifiConfigurationcreateWifiInfo(Stringssid,Stringpassawrd, int paramInt,Stringtype){ //配置网络信息类 WifiConfigurationlocalWifiConfiguration1= new WifiConfiguration(); //设置配置网络属性 localWifiConfiguration1.allowedAuthAlgorithms.clear(); localWifiConfiguration1.allowedGroupCiphers.clear(); localWifiConfiguration1.allowedKeyManagement.clear(); localWifiConfiguration1.allowedPairwiseCiphers.clear(); localWifiConfiguration1.allowedProtocols.clear(); if (type.equals( "wt" )){ //wifi连接 localWifiConfiguration1.SSID=( "\"" +ssid+ "\"" ); WifiConfigurationlocalWifiConfiguration2=isExsits(ssid); if (localWifiConfiguration2!= null ){ mWifiManager.removeNetwork(localWifiConfiguration2.networkId); //从列表中删除指定的网络配置网络 } if (paramInt== 1 ){ //没有密码 localWifiConfiguration1.wepKeys[ 0 ]= "" ; localWifiConfiguration1.allowedKeyManagement.set( 0 ); localWifiConfiguration1.wepTxKeyIndex= 0 ; } else if (paramInt== 2 ){ //简单密码 localWifiConfiguration1.hiddenSSID= true ; localWifiConfiguration1.wepKeys[ 0 ]=( "\"" +passawrd+ "\"" ); } else { //wap加密 localWifiConfiguration1.preSharedKey=( "\"" +passawrd+ "\"" ); localWifiConfiguration1.hiddenSSID= true ; localWifiConfiguration1.allowedAuthAlgorithms.set( 0 ); localWifiConfiguration1.allowedGroupCiphers.set( 2 ); localWifiConfiguration1.allowedKeyManagement.set( 1 ); localWifiConfiguration1.allowedPairwiseCiphers.set( 1 ); localWifiConfiguration1.allowedGroupCiphers.set( 3 ); localWifiConfiguration1.allowedPairwiseCiphers.set( 2 ); } } else { //"ap"wifi热点 localWifiConfiguration1.SSID=ssid; localWifiConfiguration1.allowedAuthAlgorithms.set( 1 ); localWifiConfiguration1.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); localWifiConfiguration1.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); localWifiConfiguration1.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40); localWifiConfiguration1.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104); localWifiConfiguration1.allowedKeyManagement.set( 0 ); localWifiConfiguration1.wepTxKeyIndex= 0 ; if (paramInt== 1 ){ //没有密码 localWifiConfiguration1.wepKeys[ 0 ]= "" ; localWifiConfiguration1.allowedKeyManagement.set( 0 ); localWifiConfiguration1.wepTxKeyIndex= 0 ; } else if (paramInt== 2 ){ //简单密码 localWifiConfiguration1.hiddenSSID= true ; //网络上不广播ssid localWifiConfiguration1.wepKeys[ 0 ]=passawrd; } else if (paramInt== 3 ){ //wap加密 localWifiConfiguration1.preSharedKey=passawrd; localWifiConfiguration1.allowedAuthAlgorithms.set( 0 ); localWifiConfiguration1.allowedProtocols.set( 1 ); localWifiConfiguration1.allowedProtocols.set( 0 ); localWifiConfiguration1.allowedKeyManagement.set( 1 ); localWifiConfiguration1.allowedPairwiseCiphers.set( 2 ); localWifiConfiguration1.allowedPairwiseCiphers.set( 1 ); } } return localWifiConfiguration1; } /**获取热点名**/ public StringgetApSSID(){ try { MethodlocalMethod= this .mWifiManager.getClass().getDeclaredMethod( "getWifiApConfiguration" , new Class[ 0 ]); if (localMethod== null ) return null ; ObjectlocalObject1=localMethod.invoke( this .mWifiManager, new Object[ 0 ]); if (localObject1== null ) return null ; WifiConfigurationlocalWifiConfiguration=(WifiConfiguration)localObject1; if (localWifiConfiguration.SSID!= null ) return localWifiConfiguration.SSID; FieldlocalField1=WifiConfiguration. class .getDeclaredField( "mWifiApProfile" ); if (localField1== null ) return null ; localField1.setAccessible( true ); ObjectlocalObject2=localField1.get(localWifiConfiguration); localField1.setAccessible( false ); if (localObject2== null ) return null ; FieldlocalField2=localObject2.getClass().getDeclaredField( "SSID" ); localField2.setAccessible( true ); ObjectlocalObject3=localField2.get(localObject2); if (localObject3== null ) return null ; localField2.setAccessible( false ); Stringstr=(String)localObject3; return str; } catch (ExceptionlocalException){ } return null ; } /**获取wifi名**/ public StringgetBSSID(){ if ( this .mWifiInfo== null ) return "NULL" ; return this .mWifiInfo.getBSSID(); } /**得到配置好的网络**/ public List<WifiConfiguration>getConfiguration(){ return this .mWifiConfiguration; } /**获取ip地址**/ public int getIPAddress(){ return (mWifiInfo== null )? 0 :mWifiInfo.getIpAddress(); } /**获取物理地址(Mac)**/ public StringgetMacAddress(){ return (mWifiInfo== null )? "NULL" :mWifiInfo.getMacAddress(); } /**获取网络id**/ public int getNetworkId(){ return (mWifiInfo== null )? 0 :mWifiInfo.getNetworkId(); } /**获取热点创建状态**/ public int getWifiApState(){ try { int i=((Integer) this .mWifiManager.getClass() .getMethod( "getWifiApState" , new Class[ 0 ]) .invoke( this .mWifiManager, new Object[ 0 ])).intValue(); return i; } catch (ExceptionlocalException){ } return 4 ; //未知wifi网卡状态 } /**获取wifi连接信息**/ public WifiInfogetWifiInfo(){ return this .mWifiManager.getConnectionInfo(); } /**得到网络列表**/ public List<ScanResult>getWifiList(){ return this .mWifiList; } /**查看扫描结果**/ public StringBuilderlookUpScan(){ StringBuilderlocalStringBuilder= new StringBuilder(); for ( int i= 0 ;i<mWifiList.size();i++) { localStringBuilder.append( "Index_" + new Integer(i+ 1 ).toString()+ ":" ); //将ScanResult信息转换成一个字符串包 //其中把包括:BSSID、SSID、capabilities、frequency、level localStringBuilder.append((mWifiList.get(i)).toString()); localStringBuilder.append( "\n" ); } return localStringBuilder; } /**设置wifi搜索结果**/ public void setWifiList(){ this .mWifiList= this .mWifiManager.getScanResults(); } /**开始搜索wifi**/ public void startScan(){ this .mWifiManager.startScan(); } /**得到接入点的BSSID**/ public StringGetBSSID(){ return (mWifiInfo== null )? "NULL" :mWifiInfo.getBSSID(); } } 最后,成功连接到wifi后,通过本机IP地址便可以进行相关网络开发,在下一篇中我会讲解一个WIFI热点搜索、创建、连接的Demo(http://smallwoniu.blog.51cto.com/3911954/1338618),希望能帮助到大家! 本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1334951 ,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册