Wi-Fi Direct (P2P) umożliwia urządzeniom z odpowiednim sprzętem bezpośrednie łączenie się ze sobą przez Wi-Fi bez pośredniego punktu dostępu. Za pomocą tych interfejsów API możesz wykrywać inne urządzenia i łączyć się z nimi, jeśli każde z nich obsługuje Wi-Fi P2P, a następnie komunikować się przez szybkie połączenie na odległość znacznie większą niż w przypadku połączenia Bluetooth. Jest to przydatne w przypadku aplikacji, które udostępniają dane użytkownikom, takich jak gra wieloosobowa czy aplikacja do udostępniania zdjęć.
Interfejsy Wi-Fi P2P API składają się z tych głównych części:
- Metody, które umożliwiają wykrywanie połączeń równorzędnych, wysyłanie do nich żądań i łączenie się z nimi, zdefiniowane w klasie
WifiP2pManager. - detektory, które umożliwiają otrzymywanie powiadomień o powodzeniu lub niepowodzeniu wywołań metody
WifiP2pManager. Podczas wywoływania metodWifiP2pManagerkażda metoda może otrzymać konkretny obiekt nasłuchujący przekazany jako parametr. - Intencje, które powiadamiają o konkretnych zdarzeniach wykrytych przez platformę Wi-Fi P2P, takich jak zerwanie połączenia lub nowo wykryte urządzenie równorzędne.
Często będziesz używać tych 3 głównych komponentów interfejsów API razem. Możesz na przykład podać WifiP2pManager.ActionListener w wywołaniu discoverPeers(), aby metody ActionListener.onSuccess() i ActionListener.onFailure() mogły Cię powiadomić. Intencja WIFI_P2P_PEERS_CHANGED_ACTION jest też transmitowana, jeśli metoda discoverPeers() wykryje, że lista urządzeń równorzędnych uległa zmianie.
Przegląd interfejsów API
Klasa WifiP2pManager udostępnia metody umożliwiające interakcję ze sprzętem Wi-Fi na urządzeniu, np. wykrywanie innych urządzeń i łączenie się z nimi.
Dostępne są te opcje:
Tabela 1. Metody Wi-Fi P2P
| Metoda | Opis |
initialize()
|
Rejestruje aplikację w platformie Wi-Fi. Wywołaj tę metodę przed wywołaniem jakiejkolwiek innej metody Wi-Fi P2P. |
connect()
|
Rozpoczyna połączenie peer-to-peer z urządzeniem o określonej konfiguracji. |
cancelConnect()
|
Anuluje wszystkie trwające negocjacje w grupie połączeń równorzędnych. |
requestConnectInfo()
|
Wysyła prośbę o informacje o połączeniu urządzenia. |
createGroup()
|
Tworzy grupę połączeń równorzędnych, w której bieżące urządzenie jest właścicielem grupy. |
removeGroup()
|
Usuwa bieżącą grupę połączeń równorzędnych. |
requestGroupInfo()
|
Wysyła prośbę o informacje o grupie połączeń równorzędnych. |
discoverPeers()
|
Inicjuje wykrywanie węzłów równorzędnych. |
requestPeers()
|
Wysyła żądanie o aktualną listę wykrytych urządzeń równorzędnych. |
Metody WifiP2pManager umożliwiają przekazanie detektora, dzięki czemu platforma Wi-Fi P2P może powiadomić Twoją aktywność o stanie połączenia. Dostępne interfejsy detektorów i odpowiadające im wywołania metod WifiP2pManager, które korzystają z detektorów, opisano w tabeli 2.
Tabela 2. Detektory Wi-Fi P2P
| Interfejs detektora | Powiązane działania |
WifiP2pManager.ActionListener
|
connect(), cancelConnect(), createGroup(), removeGroup() i discoverPeers()
|
WifiP2pManager.ChannelListener
|
initialize()
|
WifiP2pManager.ConnectionInfoListener
|
requestConnectInfo()
|
WifiP2pManager.GroupInfoListener
|
requestGroupInfo()
|
WifiP2pManager.PeerListListener
|
requestPeers()
|
Interfejsy Wi-Fi P2P API definiują intencje, które są rozsyłane, gdy wystąpią określone zdarzenia Wi-Fi P2P, np. gdy zostanie wykryte nowe urządzenie równorzędne lub gdy zmieni się stan Wi-Fi urządzenia. Możesz zarejestrować się, aby otrzymywać te intencje w aplikacji, tworząc odbiornik komunikatów, który obsługuje te intencje:
Tabela 3. Intencje Wi-Fi P2P
| Intencja | Opis |
WIFI_P2P_CONNECTION_CHANGED_ACTION
|
Transmisja po zmianie stanu połączenia Wi-Fi urządzenia. |
WIFI_P2P_PEERS_CHANGED_ACTION
|
Transmisja, gdy dzwonisz do: discoverPeers(). Jeśli obsługujesz tę intencję w aplikacji, zwykle wywołujesz requestPeers(), aby uzyskać zaktualizowaną listę peerów.
|
WIFI_P2P_STATE_CHANGED_ACTION
|
Transmisja, gdy Wi-Fi P2P jest włączone lub wyłączone na urządzeniu. |
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
|
Transmisja, gdy zmienią się szczegóły urządzenia, np. jego nazwa. |
Tworzenie odbiornika do obsługi intencji Wi-Fi P2P
Odbiornik komunikatów umożliwia odbieranie intencji wysyłanych przez system Android, dzięki czemu aplikacja może reagować na interesujące Cię zdarzenia. Oto podstawowe czynności, które należy wykonać, aby utworzyć odbiornik do obsługi intencji Wi-Fi P2P:
Utwórz klasę, która rozszerza klasę
BroadcastReceiver. W konstruktorze klasy użyjesz parametrów dlaWifiP2pManager,WifiP2pManager.Channeli aktywności, w której zostanie zarejestrowany ten odbiornik. Dzięki temu odbiorca może wysyłać aktualizacje do aktywności, a także w razie potrzeby ma dostęp do sprzętu Wi-Fi i kanału komunikacyjnego.W odbiorniku komunikatów sprawdź intencje, które Cię interesują, w metodzie
onReceive(). Wykonaj niezbędne działania w zależności od otrzymanej intencji. Jeśli na przykład odbiornik otrzyma intencjęWIFI_P2P_PEERS_CHANGED_ACTION, możesz wywołać metodęrequestPeers(), aby uzyskać listę obecnie wykrytych urządzeń równorzędnych.
Poniższy kod pokazuje, jak utworzyć typowy odbiornik komunikatów. Odbiornik komunikatów przyjmuje obiekt WifiP2pManager i aktywność jako argumenty i używa tych 2 klas do odpowiedniego wykonywania potrzebnych działań, gdy odbierze intencję:
Kotlin
/** * A BroadcastReceiver that notifies of important Wi-Fi p2p events. */ class WiFiDirectBroadcastReceiver( private val manager: WifiP2pManager, private val channel: WifiP2pManager.Channel, private val activity: MyWifiActivity ) : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val action: String = intent.action when (action) { WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> { // Check to see if Wi-Fi is enabled and notify appropriate activity } WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> { // Call WifiP2pManager.requestPeers() to get a list of current peers } WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> { // Respond to new connection or disconnections } WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> { // Respond to this device's wifi state changing } } } }
Java
/** * A BroadcastReceiver that notifies of important Wi-Fi p2p events. */ public class WiFiDirectBroadcastReceiver extends BroadcastReceiver { private WifiP2pManager manager; private Channel channel; private MyWiFiActivity activity; public WiFiDirectBroadcastReceiver(WifiP2pManager manager, Channel channel, MyWifiActivity activity) { super(); this.manager = manager; this.channel = channel; this.activity = activity; } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) { // Check to see if Wi-Fi is enabled and notify appropriate activity } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { // Call WifiP2pManager.requestPeers() to get a list of current peers } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { // Respond to new connection or disconnections } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) { // Respond to this device's wifi state changing } } }
Na urządzeniach z Androidem 10 lub nowszym te intencje rozgłaszania nie są trwałe:
WIFI_P2P_CONNECTION_CHANGED_ACTION- Aplikacje mogą używać
requestConnectionInfo(),requestNetworkInfo()lubrequestGroupInfo()do pobierania informacji o bieżącym połączeniu. WIFI_P2P_THIS_DEVICE_CHANGED_ACTION- Aplikacje mogą używać
requestDeviceInfo()do pobierania informacji o bieżącym połączeniu.
Tworzenie aplikacji Wi-Fi P2P
Tworzenie aplikacji Wi-Fi P2P obejmuje utworzenie i zarejestrowanie odbiornika komunikatów dla aplikacji, wykrywanie urządzeń równorzędnych, łączenie się z urządzeniem równorzędnym i przesyłanie danych do urządzenia równorzędnego. W sekcjach poniżej opisujemy, jak to zrobić.
Konfiguracja początkowa
Zanim zaczniesz korzystać z interfejsów API Wi-Fi P2P, musisz się upewnić, że aplikacja ma dostęp do sprzętu i że urządzenie obsługuje protokół Wi-Fi P2P. Jeśli Wi-Fi P2P jest obsługiwane, możesz uzyskać instancję WifiP2pManager, utworzyć i zarejestrować odbiornik i zacząć korzystać z interfejsów API Wi-Fi P2P.
Poproś o uprawnienia do korzystania ze sprzętu Wi-Fi na urządzeniu i zadeklaruj w pliku manifestu Androida, że aplikacja ma prawidłową minimalną wersję pakietu SDK:
<uses-sdk android:minSdkVersion="14" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- If your app targets Android 13 (API level 33) or higher, you must declare the NEARBY_WIFI_DEVICES permission. --> <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" <!-- If your app derives location information from Wi-Fi APIs, don't include the "usesPermissionFlags" attribute. --> android:usesPermissionFlags="neverForLocation" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" <!-- If any feature in your app relies on precise location information, don't include the "maxSdkVersion" attribute. --> android:maxSdkVersion="32" />Oprócz uprawnień wymienionych powyżej te interfejsy API wymagają również włączenia trybu lokalizacji:
Sprawdź, czy połączenie Wi-Fi P2P jest włączone i obsługiwane. Dobrym miejscem do sprawdzenia tego jest odbiornik, gdy odbiera on intencję
WIFI_P2P_STATE_CHANGED_ACTION. Powiadom aktywność o stanie Wi-Fi P2P i odpowiednio zareaguj:Kotlin
override fun onReceive(context: Context, intent: Intent) { ... val action: String = intent.action when (action) { WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> { val state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1) when (state) { WifiP2pManager.WIFI_P2P_STATE_ENABLED -> { // Wifi P2P is enabled } else -> { // Wi-Fi P2P is not enabled } } } } ... }
Java
@Override public void onReceive(Context context, Intent intent) { ... String action = intent.getAction(); if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) { int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1); if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) { // Wifi P2P is enabled } else { // Wi-Fi P2P is not enabled } } ... }
W metodzie
onCreate()aktywności pobierz instancjęWifiP2pManageri zarejestruj aplikację w platformie Wi-Fi P2P, wywołującinitialize(). Ta metoda zwraca obiektWifiP2pManager.Channel, który służy do łączenia aplikacji z platformą Wi-Fi P2P. Należy też utworzyć instancję odbiornika z obiektamiWifiP2pManageriWifiP2pManager.Channeloraz odwołaniem do aktywności. Dzięki temu odbiornik może powiadamiać aktywność o interesujących zdarzeniach i odpowiednio ją aktualizować. Umożliwia też w razie potrzeby zmianę stanu Wi-Fi urządzenia:Kotlin
val manager: WifiP2pManager? by lazy(LazyThreadSafetyMode.NONE) { getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager? } var channel: WifiP2pManager.Channel? = null var receiver: BroadcastReceiver? = null override fun onCreate(savedInstanceState: Bundle?) { ... channel = manager?.initialize(this, mainLooper, null) channel?.also { channel -> receiver = WiFiDirectBroadcastReceiver(manager, channel, this) } }
Java
WifiP2pManager manager; Channel channel; BroadcastReceiver receiver; ... @Override protected void onCreate(Bundle savedInstanceState){ ... manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); channel = manager.initialize(this, getMainLooper(), null); receiver = new WiFiDirectBroadcastReceiver(manager, channel, this); ... }
Utwórz filtr intencji i dodaj te same intencje, które sprawdza odbiornik:
Kotlin
val intentFilter = IntentFilter().apply { addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION) addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION) addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION) addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION) }
Java
IntentFilter intentFilter; ... @Override protected void onCreate(Bundle savedInstanceState){ ... intentFilter = new IntentFilter(); intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); ... }
Zarejestruj odbiornik transmisji w metodzie
onResume()aktywności i wyrejestruj go w metodzieonPause()aktywności:Kotlin
/* register the broadcast receiver with the intent values to be matched */ override fun onResume() { super.onResume() receiver?.also { receiver -> registerReceiver(receiver, intentFilter) } } /* unregister the broadcast receiver */ override fun onPause() { super.onPause() receiver?.also { receiver -> unregisterReceiver(receiver) } }
Java
/* register the broadcast receiver with the intent values to be matched */ @Override protected void onResume() { super.onResume(); registerReceiver(receiver, intentFilter); } /* unregister the broadcast receiver */ @Override protected void onPause() { super.onPause(); unregisterReceiver(receiver); }
Gdy uzyskasz
WifiP2pManager.Channeli skonfigurujesz odbiornik, aplikacja będzie mogła wykonywać wywołania metod Wi-Fi P2P i odbierać intencje Wi-Fi P2P.Zaimplementuj aplikację, korzystając z funkcji Wi-Fi P2P, wywołując metody w
WifiP2pManager.
W następnych sekcjach opisano, jak wykonywać typowe działania, takie jak wykrywanie połączeń i łączenie się z innymi urządzeniami.
Odkrywanie innych użytkowników
Wywołaj discoverPeers(), aby wykryć dostępne urządzenia, które są w zasięgu i z którymi można się połączyć. Wywołanie tej funkcji jest asynchroniczne, a informacja o powodzeniu lub niepowodzeniu jest przekazywana do aplikacji za pomocą onSuccess() i onFailure(), jeśli utworzono WifiP2pManager.ActionListener. Metoda onSuccess() tylko powiadamia o powodzeniu procesu wykrywania i nie podaje żadnych informacji o wykrytych urządzeniach równorzędnych. Poniższy przykładowy kod pokazuje, jak to skonfigurować.
Kotlin
manager?.discoverPeers(channel, object : WifiP2pManager.ActionListener { override fun onSuccess() { ... } override fun onFailure(reasonCode: Int) { ... } })
Java
manager.discoverPeers(channel, new WifiP2pManager.ActionListener() { @Override public void onSuccess() { ... } @Override public void onFailure(int reasonCode) { ... } });
Jeśli proces wykrywania się powiedzie i wykryje urządzenia, system wyśle komunikat systemowy WIFI_P2P_PEERS_CHANGED_ACTION, który możesz nasłuchiwać w odbiorniku, aby uzyskać listę urządzeń. Gdy aplikacja otrzyma intencję WIFI_P2P_PEERS_CHANGED_ACTION, możesz poprosić o listę wykrytych urządzeń równorzędnych za pomocą requestPeers(). Poniższy kod pokazuje, jak to skonfigurować.
Kotlin
override fun onReceive(context: Context, intent: Intent) { val action: String = intent.action when (action) { ... WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> { manager?.requestPeers(channel) { peers: WifiP2pDeviceList? -> // Handle peers list } } ... } }
Java
PeerListListener myPeerListListener; ... if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) { // request available peers from the wifi p2p manager. This is an // asynchronous call and the calling activity is notified with a // callback on PeerListListener.onPeersAvailable() if (manager != null) { manager.requestPeers(channel, myPeerListListener); } }
Metoda requestPeers() jest również asynchroniczna i może powiadomić aktywność, gdy lista urządzeń peer-to-peer jest dostępna, za pomocą onPeersAvailable(), która jest zdefiniowana w interfejsie WifiP2pManager.PeerListListener. Metoda onPeersAvailable() udostępnia obiekt WifiP2pDeviceList, który można iterować, aby znaleźć urządzenie, z którym można się połączyć.
Łączenie z innymi użytkownikami
Po uzyskaniu listy możliwych urządzeń równorzędnych i wybraniu urządzenia, z którym chcesz się połączyć, wywołaj metodę connect(), aby połączyć się z urządzeniem. To wywołanie metody wymaga obiektu WifiP2pConfig, który zawiera informacje o urządzeniu, z którym ma zostać nawiązane połączenie.
WifiP2pManager.ActionListener może powiadomić Cię o powodzeniu lub niepowodzeniu połączenia. Poniższy kod pokazuje, jak utworzyć połączenie z urządzeniem.
Kotlin
val device: WifiP2pDevice = ... val config = WifiP2pConfig() config.deviceAddress = device.deviceAddress channel?.also { channel -> manager?.connect(channel, config, object : WifiP2pManager.ActionListener { override fun onSuccess() { //success logic } override fun onFailure(reason: Int) { //failure logic } } )}
Java
//obtain a peer from the WifiP2pDeviceList WifiP2pDevice device; WifiP2pConfig config = new WifiP2pConfig(); config.deviceAddress = device.deviceAddress; manager.connect(channel, config, new ActionListener() { @Override public void onSuccess() { //success logic } @Override public void onFailure(int reason) { //failure logic } });
Przenieś dane
Po nawiązaniu połączenia możesz przesyłać dane między urządzeniami za pomocą gniazd. Podstawowe kroki przenoszenia danych:
- Utwórz
ServerSocket. To gniazdo czeka na połączenie z klientem na określonym porcie i blokuje je, dopóki nie zostanie nawiązane, więc wykonaj tę czynność w wątku w tle. - Utwórz klienta
Socket. Klient używa adresu IP i portu gniazda serwera, aby połączyć się z urządzeniem serwera. - Wysyłanie danych z klienta na serwer. Gdy gniazdo klienta połączy się z gniazdem serwera, możesz wysyłać dane z klienta do serwera za pomocą strumieni bajtów.
- Gniazdo serwera czeka na połączenie klienta (za pomocą metody
accept()). To wywołanie blokuje się, dopóki klient się nie połączy, więc wywołaj je w innym wątku. Po nawiązaniu połączenia urządzenie serwera może odbierać dane od klienta.
Poniższy przykład, zmodyfikowany na podstawie Wi-Fi P2P Demo, pokazuje, jak utworzyć komunikację gniazda klient-serwer i przesyłać obrazy JPEG z klienta na serwer za pomocą usługi. Aby zobaczyć pełny, działający przykład, skompiluj i uruchom wersję demonstracyjną.
Kotlin
class FileServerAsyncTask( private val context: Context, private var statusText: TextView ) : AsyncTask<Void, Void, String?>() { override fun doInBackground(vararg params: Void): String? { /** * Create a server socket. */ val serverSocket = ServerSocket(8888) return serverSocket.use { /** * Wait for client connections. This call blocks until a * connection is accepted from a client. */ val client = serverSocket.accept() /** * If this code is reached, a client has connected and transferred data * Save the input stream from the client as a JPEG file */ val f = File(Environment.getExternalStorageDirectory().absolutePath + "/${context.packageName}/wifip2pshared-${System.currentTimeMillis()}.jpg") val dirs = File(f.parent) dirs.takeIf { it.doesNotExist() }?.apply { mkdirs() } f.createNewFile() val inputstream = client.getInputStream() copyFile(inputstream, FileOutputStream(f)) serverSocket.close() f.absolutePath } } private fun File.doesNotExist(): Boolean = !exists() /** * Start activity that can handle the JPEG image */ override fun onPostExecute(result: String?) { result?.run { statusText.text = "File copied - $result" val intent = Intent(android.content.Intent.ACTION_VIEW).apply { setDataAndType(Uri.parse("file://$result"), "image/*") } context.startActivity(intent) } } }
Java
public static class FileServerAsyncTask extends AsyncTask { private Context context; private TextView statusText; public FileServerAsyncTask(Context context, View statusText) { this.context = context; this.statusText = (TextView) statusText; } @Override protected String doInBackground(Void... params) { try { /** * Create a server socket and wait for client connections. This * call blocks until a connection is accepted from a client */ ServerSocket serverSocket = new ServerSocket(8888); Socket client = serverSocket.accept(); /** * If this code is reached, a client has connected and transferred data * Save the input stream from the client as a JPEG file */ final File f = new File(Environment.getExternalStorageDirectory() + "/" + context.getPackageName() + "/wifip2pshared-" + System.currentTimeMillis() + ".jpg"); File dirs = new File(f.getParent()); if (!dirs.exists()) dirs.mkdirs(); f.createNewFile(); InputStream inputstream = client.getInputStream(); copyFile(inputstream, new FileOutputStream(f)); serverSocket.close(); return f.getAbsolutePath(); } catch (IOException e) { Log.e(WiFiDirectActivity.TAG, e.getMessage()); return null; } } /** * Start activity that can handle the JPEG image */ @Override protected void onPostExecute(String result) { if (result != null) { statusText.setText("File copied - " + result); Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file://" + result), "image/*"); context.startActivity(intent); } } }
Na kliencie połącz się z gniazdem serwera za pomocą gniazda klienta i prześlij dane. W tym przykładzie przesyłany jest plik JPEG z systemu plików urządzenia klienta.
Kotlin
val context = applicationContext val host: String val port: Int val len: Int val socket = Socket() val buf = ByteArray(1024) ... try { /** * Create a client socket with the host, * port, and timeout information. */ socket.bind(null) socket.connect((InetSocketAddress(host, port)), 500) /** * Create a byte stream from a JPEG file and pipe it to the output stream * of the socket. This data is retrieved by the server device. */ val outputStream = socket.getOutputStream() val cr = context.contentResolver val inputStream: InputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg")) while (inputStream.read(buf).also { len = it } != -1) { outputStream.write(buf, 0, len) } outputStream.close() inputStream.close() } catch (e: FileNotFoundException) { //catch logic } catch (e: IOException) { //catch logic } finally { /** * Clean up any open sockets when done * transferring or if an exception occurred. */ socket.takeIf { it.isConnected }?.apply { close() } }
Java
Context context = this.getApplicationContext(); String host; int port; int len; Socket socket = new Socket(); byte buf[] = new byte[1024]; ... try { /** * Create a client socket with the host, * port, and timeout information. */ socket.bind(null); socket.connect((new InetSocketAddress(host, port)), 500); /** * Create a byte stream from a JPEG file and pipe it to the output stream * of the socket. This data is retrieved by the server device. */ OutputStream outputStream = socket.getOutputStream(); ContentResolver cr = context.getContentResolver(); InputStream inputStream = null; inputStream = cr.openInputStream(Uri.parse("path/to/picture.jpg")); while ((len = inputStream.read(buf)) != -1) { outputStream.write(buf, 0, len); } outputStream.close(); inputStream.close(); } catch (FileNotFoundException e) { //catch logic } catch (IOException e) { //catch logic } /** * Clean up any open sockets when done * transferring or if an exception occurred. */ finally { if (socket != null) { if (socket.isConnected()) { try { socket.close(); } catch (IOException e) { //catch logic } } } }