Interface design to have multiple implementations of network call libraries (Retrofit or Volley) I am learning design patterns from Head First Design Patterns and a principle I came across is to "code to interface". Now I want to apply this principle in my Android app, which includes lots of API calls. I am using Retrofit for network calls.

I have applied this principle considering some scenario something like this:


Suppose in the future I need to shift from Retrofit to Volley or any other networking library.
I created an interface with a method to getData from the server and created a class which implements that interface. The implemented method includes the Retrofit code to getData from the server.
Now in the future, if I want to use Volley, I'll create a new class implementing the interface and with Volley code to retrieve data from the server.


Interface

public interface NetworkCallsApi {
    String getDataFromServer(Activity activity,String url,String Callback);
}


Retrofit Implementation

public class NetworkCallsRetrofitImpl implements NetworkCallsApi{

private Retrofit retrofit;

@Override
public String getDataFromServer(Activity activity, String url, String Callback) {

retrofit = new Retrofit.Builder()
        .baseUrl(StringConstants.ROOT_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .build();

RetrofitApi apiCalls = retrofit.create(RetrofitApi.class);

Call&lt;ResponseBody&gt; call = apiCalls.getDataFromServer(url);

call.enqueue(new Callback&lt;ResponseBody&gt;() {
    @Override
    public void onResponse(Call&lt;ResponseBody&gt; call, Response&lt;ResponseBody&gt; response) {

    }

    @Override
    public void onFailure(Call&lt;ResponseBody&gt; call, Throwable t) {

    }
});
return null;
}
}


ServiceCalls.java

public class ServiceCalls {

    public static ServiceCalls serviceCalls;
    public NetworkCallsApi networkCallsimpl;

    public static ServiceCalls getInstance(){

        if(serviceCalls == null){
            serviceCalls = new ServiceCalls();
        }
        return serviceCalls;
    }

    public void setNetworkCallsimpl(NetworkCallsApi networkCallsimpl) {
        this.networkCallsimpl = networkCallsimpl;
    }

    public String getDataFromServer(Activity activity, String url, String callback){
        networkCallsimpl.getDataFromServer(activity,url,callback);
        return null;
     }
 }


MainFragment:

public class StatusFragment extends Fragment {    

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Setting the implementation
        ServiceCalls.getInstance().setNetworkCallsimpl(new NetworkCallsRetrofitImpl());
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        view = inflater.inflate(R.layout.fragment_pnr_status,container,false);

        try{
          init();
        }catch(Exception e){}
        return view;
   }

    private void init() {

        ok.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            setUrlKeysAndValues();
            ServiceCalls.getInstance().getDataFromServer(getActivity()
                ,Utils.getInstance().buildUrl(urlKeys,urlValues),"onResponse");
        }
        });

    }
}


Have I correctly applied that principle? If not, what changes do I need to make? In onCreate of MainFragment, I am hardcoding the implementation. How can the interface design pattern be better applied in this scenario?
Let me point out an other aspect, you might miss at the moment. I know that this is a learner question/example, but keep in mind that your approach is designing an application where you can switch the network library (in extreme) at runtime. This is not the most common scenario.

Actually it is more likely that you want to switch Retrofit against a mock or Volley against a mock in your tests. So you have done everything right, if you can write tests for related parts of your system (e.g. the StatusFragment)  without doing real network calls and there is no test switch in your production code. (The network stuff will get it's own test.)

On the other hand, although I'm not familiar with the libraries, Google told me that both seems to have some own mocking concepts. So there might not even be a need to switch your implementation in unit tests. In case you finally end up with only one implementation now and optional a total replacement in the future, this approach might add an unnecessary (mental and technical) overhead.

Implementing against an interface don't necessary mean a Java interface. If you only have one implementation at a time, it is totally fine to drop NetworkCallsApi and move NetworkCallsRetrofitImpl into ServiceCalls. Afterwards you are implementing against the interface of ServiceCalls and you don't care about is implementation. It is also pretty straight forward to change the implementation in ServiceCalls later without changing other parts of the application.