(三)通信和联网
3.1显示Web信息
1.WebView通过loadUrl()方法直接访问网页时,点击跳转链接会打开系统默认的浏览器,若要拦截WebView事件,可为其添加WebViewClient
webView.setWebViewClient(new WebViewClient())
2.WebView默认不支持JavaScript,要通过setJavaScriptEnabled()进行设置
webView.getSettings().setJavaScriptEnabled(true);
3.WebView可以直接显示Html内容
3.4下载图片文件
1.自定义一个ImageView控件,实现资源的下载与显示
值得一提的是,设置本地资源应该提供2个方法,一个通过资源id获取,一个通过drawable获取
网络下载可以通过asynctask实现,要注意不要在doInBackground()中更新UI线程
下面附上完整代码
public class WebImageView extends ImageView { private Drawable mPlaceholder, mImage; public WebImageView(Context context) { this(context, null); } public WebImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public WebImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void setPlaceholderImage(Drawable drawable) { mPlaceholder = drawable; if (mImage == null) { setImageDrawable(mPlaceholder); } } public void setPlaceholderImage(int resid) { mPlaceholder = getResources().getDrawable(resid); System.out.println(1); if (mImage == null) { System.out.println(2); setImageDrawable(mPlaceholder); } } public void setImageUrl(String url) { DownloadTask task = new DownloadTask(); task.execute(url); } private class DownloadTask extends AsyncTask<String, Void, Bitmap> { @Override protected Bitmap doInBackground(String... params) { String url = params[0]; try { URLConnection connection = (new URL(url)).openConnection(); InputStream is = connection.getInputStream(); return BitmapFactory.decodeStream(is); } catch (IOException e) { e.printStackTrace(); return null; } } @Override protected void onPostExecute(Bitmap bitmap) { mImage = new BitmapDrawable(getContext().getResources(), bitmap); setImageDrawable(mImage); } } }
3.5完全在后台下载
1.DownloadManager适合处理和管理需要长时间运行的下载操作。其优点是即使在下载失败,链接改变甚至设备重启时,依然会继续尝试下载
2.首先实现一个广播接收者来监听下载状态
private BroadcastReceiver receiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { queryDownloadStatus(); } }; private void queryDownloadStatus(){ DownloadManager.Query query=new DownloadManager.Query(); query.setFilterById(prefs.getLong(DL_ID,0)); Cursor c=dm.query(query); if(c.moveToFirst()){ int status=c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)); switch (status){ case DownloadManager.STATUS_PAUSED: case DownloadManager.STATUS_PENDING: case DownloadManager.STATUS_RUNNING: break; case DownloadManager.STATUS_SUCCESSFUL: try { ParcelFileDescriptor file=dm.openDownloadedFile(prefs.getLong(DL_ID,0)); FileInputStream fis=new ParcelFileDescriptor.AutoCloseInputStream(file); imageView.setImageBitmap(BitmapFactory.decodeStream(fis)); Toast.makeText(this,"download over!",Toast.LENGTH_SHORT).show(); } catch (FileNotFoundException e) { e.printStackTrace(); } break; case DownloadManager.STATUS_FAILED: dm.remove(prefs.getLong(DL_ID, 0)); prefs.edit().clear().apply(); break; } } }
3.接着获取系统服务
dm= (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
4.最后,在onResume中注册广播并开始下载
@Override protected void onResume() { super.onResume(); if(!prefs.contains(DL_ID)){ Uri resource=Uri.parse("http://f2.market.xiaomi.com/download/AppChannel/0965d34f016634cb83347f609306d9a3fa045a9c5/com.netease.onmyoji.mi.apk"); DownloadManager.Request request=new DownloadManager.Request(resource); request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE| DownloadManager.Request.NETWORK_WIFI); request.setTitle("Download Sample"); request.setDescription("Download SSR!"); request.setAllowedOverRoaming(false); long id=dm.enqueue(request); prefs.edit().putLong(DL_ID,id).apply(); }else{ queryDownloadStatus(); } registerReceiver(receiver,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); }
3.10发送短信
1.与之前的DownloadManager一样,发送短信的SmsManager也是系统级服务,二者的调用极为相似
2..首先实现广播接收者,发送短信一共有2个接受者,一个返回发送是否成功
private BroadcastReceiver sent = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (getResultCode()) { case Activity.RESULT_OK: Toast.makeText(SendSmsActivity.this, "发送成功", Toast.LENGTH_SHORT).show(); break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: case SmsManager.RESULT_ERROR_NO_SERVICE: case SmsManager.RESULT_ERROR_NULL_PDU: case SmsManager.RESULT_ERROR_RADIO_OFF: Toast.makeText(SendSmsActivity.this, "发送失败", Toast.LENGTH_SHORT).show(); break; } } };
另一个返回接收是否成功
private BroadcastReceiver delivered = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (getResultCode()) { case Activity.RESULT_OK: Toast.makeText(SendSmsActivity.this, "传递成功", Toast.LENGTH_SHORT).show(); break; case Activity.RESULT_CANCELED: Toast.makeText(SendSmsActivity.this, "传递失败", Toast.LENGTH_SHORT).show(); break; } } };
3.接着,分别在resume和pause中注册和注销广播
@Override protected void onResume() { super.onResume(); registerReceiver(sent, new IntentFilter(ACTION_SENT)); registerReceiver(delivered,new IntentFilter(ACTION_DELIVERED)); }
@Override protected void onPause() { super.onPause(); unregisterReceiver(sent); unregisterReceiver(delivered); }
4.最后调用SmsManager即可
private void sendSms(String msg) { PendingIntent sIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_SENT),0); PendingIntent dIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_DELIVERED),0); SmsManager manager=SmsManager.getDefault(); manager.sendTextMessage(RECIPIENT_ADDRESS,null,msg,sIntent,dIntent); }
3.11蓝牙通信
1.蓝牙通信需要获取权限
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
2.有时蓝牙并没有开启,所以要通过startActivityForResult启动
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE);
3.此时应该设置一个onActivityResult方法来获取蓝牙的启动情况
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_ENABLE: if (resultCode != RESULT_OK) { Toast.makeText(this, "蓝牙启动失败", Toast.LENGTH_SHORT).show(); finish(); } break; case REQUEST_DISCOVERABLE: if (resultCode == RESULT_CANCELED) { Toast.makeText(this, "蓝牙必须被设置为可见", Toast.LENGTH_SHORT).show(); finish(); } else { startListening(); } break; default: break; } }
4.蓝牙功能分两方,一方让设备处于监听状态,监听其他设备的连入
listenButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { email = emailField.getText().toString(); if (mBtAdapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) { Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 3000); startActivityForResult(discoverableIntent, REQUEST_DISCOVERABLE); } startListening(); } });
监听时要用到唯一的UUID
private void startListening() { AcceptTask task = new AcceptTask(); task.execute(MY_UUID); setProgressBarIndeterminateVisibility(true); }
5.另一方要让设备扫描可连入的设备,主要通过startDiscovery()方法
scanButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { email = emailField.getText().toString(); mBtAdapter.startDiscovery(); setProgressBarIndeterminateVisibility(true); } });
6.程序要使用2个AsyncTask来执行具体的功能,一个用来连接
private class AcceptTask extends AsyncTask<UUID, Void, BluetoothSocket> { @Override protected BluetoothSocket doInBackground(UUID... params) { String name = mBtAdapter.getName(); mBtAdapter.setName(SEARCH_NAME); try { BluetoothServerSocket socket = mBtAdapter.listenUsingRfcommWithServiceRecord("BluetoothRecipe", params[0]); BluetoothSocket connected = socket.accept(); mBtAdapter.setName(name); return connected; } catch (IOException e) { e.printStackTrace(); mBtAdapter.setName(name); return null; } } @Override protected void onPostExecute(BluetoothSocket bluetoothSocket) { mBtSocket = bluetoothSocket; ConnectedTask task = new ConnectedTask(); task.execute(mBtSocket); } }
7.另一个用来传输数据
private class ConnectedTask extends AsyncTask<BluetoothSocket, Void, String> { @Override protected String doInBackground(BluetoothSocket... params) { InputStream in = null; OutputStream out = null; try { //发送数据 out = params[0].getOutputStream(); out.write(email.getBytes()); //接受其他数据 in = params[0].getInputStream(); byte[] buffer = new byte[1024]; in.read(buffer); String result = new String(buffer); mBtSocket.close(); return result.trim(); } catch (IOException e) { e.printStackTrace(); return null; } } @Override protected void onPostExecute(String result) { Toast.makeText(ExchangeActivity.this, result, Toast.LENGTH_SHORT).show(); setProgressBarIndeterminateVisibility(false); } }
8.两个AsyncTask之间使用BroadCast进行连接
private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device.getName().equals(SEARCH_NAME)) { mBtAdapter.cancelDiscovery(); try { mBtSocket = device.createRfcommSocketToServiceRecord(MY_UUID); mBtSocket.connect(); ConnectedTask task = new ConnectedTask(); task.execute(mBtSocket); } catch (IOException e) { e.printStackTrace(); } } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { setProgressBarIndeterminateVisibility(false); } } };
9.广播接收者分别在resume和pause中注册和注销
@Override protected void onResume() { super.onResume(); IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); registerReceiver(mReceiver, filter); }
10.create中一些初始化信息
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.activity_exchange); mBtAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBtAdapter == null) { Toast.makeText(this, "不支持蓝牙", Toast.LENGTH_SHORT).show(); finish(); } //开启蓝牙 if (!mBtAdapter.isEnabled()) { Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, REQUEST_ENABLE); } emailField = (EditText) findViewById(R.id.emailField);
11.退出时将蓝牙的Socket清除
@Override protected void onDestroy() { super.onDestroy(); if (mBtSocket != null) { try { mBtSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }
3.12查询网络状态
1.通过系统服务ConnectivityManager来获取网络状态
2.是否可以获取网络
public static boolean isNetworkReachable(Context context) { final ConnectivityManager mManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo current = mManager.getActiveNetworkInfo(); return current != null && current.getState() == NetworkInfo.State.CONNECTED; }
3.是否可以获取wifi
public static boolean isWifiReachable(Context context) { final ConnectivityManager mManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo current = mManager.getActiveNetworkInfo(); return current != null && current.getType() == ConnectivityManager.TYPE_WIFI; }