I am new to android app development. I have created a simple hello world android app and I am trying to invoke a REST api endpoint of a HelloWorldService
running on my local machine. The service is running using Spring Boot in IntelliJ. Service code is as below:
@RestController
public class SimpleController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String sayHello() {
return "Hello world";
}
}
To invoke this api from mobile app, I am using Retrofit library. The code is as below:
Dependencies
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
compileOnly 'org.projectlombok:lombok:1.18.20'
annotationProcessor 'org.projectlombok:lombok:1.18.20'
SimpleService.java
public interface SimpleService {
@GET("/hello")
Call<String> sayHello();
}
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = findViewById(R.id.button);
TextView textView = findViewById(R.id.textView);
button.setOnClickListener(view -> {
OkHttpClient httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://x.x.x.x:8080")
.client(httpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
final SimpleService simpleService = retrofit.create(SimpleService.class);
final Call<String> stringCall = simpleService.sayHello();
stringCall.enqueue(new Callback<String>() {
@Override
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
textView.setText(response.body());
}
@Override
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
t.printStackTrace();
}
});
});
}
What I have tried?
localhost
as the IP address to access the web-service and I have to use actual network IP. Also, laptop and phone needs to be on the same network. Hence, I updated my base url to use inet address x.x.x.x:port_number
.<uses-permission android:name="android.permission.INTERNET" />
10.0.2.2
, I am able to access it.However, I am unable to connect to the endpoint and getting following error:
W/System.err: java.net.SocketTimeoutException: failed to connect to /192.168.0.11 (port 8080) from /192.168.0.26 (port 56860) after 120000ms
W/System.err: at libcore.io.IoBridge.connectErrno(IoBridge.java:191)
at libcore.io.IoBridge.connect(IoBridge.java:135)
W/System.err: at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:142)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212)
W/System.err: at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436)
at java.net.Socket.connect(Socket.java:621)
at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:71)
at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:263)
W/System.err: at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:183)
at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.java:224)
at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.java:108)
at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.java:88)
at okhttp3.internal.connection.Transmitter.newExchange(Transmitter.java:169)
W/System.err: at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:41)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
W/System.err: at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:229)
W/System.err: at okhttp3.RealCall$AsyncCall.execute(RealCall.java:172)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Any pointers are appreciated.
If you're running the android app on an emulator, you can just use the ip of 10.0.2.2 By default, this refers to the host of the emulator.
If you're on a real device, use the real IP. This means the server either needs to be on the saw WIFI network AND the network firewall has to be set up to allow traffic to it, or you need a publicly addressable IP address. Most router setups NAT by default, so you'll have to poke a hole in it.
Also, make sure the server is using the right IP address and isn't just bound to localhost.