Apache HTTP Components

Apache HTTP Components este un proiect open-source, dezvoltat sub licență Apache, punând la dispoziția utilizatorilor o bibliotecă Java pentru accesarea de resurse prin intermediul protocolului HTTP.

Vom folosi o versiune legacy in acest laborator. In cadrul laboratorului veti putea folosi orice alternative, precum OkHttp.

Pentru ca metodele din API-ul Apache HTTP Components să poată fi utilizate într-o aplicație Android este necesar să se specifice catre sistemul de build, în fișierul build.gradle din app:

...

android {

  // pentru fisiere build.gradle.kt
  useLibrary("org.apache.http.legacy")
  // pentru fisiere build.gradle
  useLibrary 'org.apache.http.legacy'
}

...

De asemenea, in android manifest trebuie sa punem permisiunea de network

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission
        android:name="android.permission.INTERNET"/>
    ...

Pentru a evita blocarea thread-ului main, oricare din apelurile catre API-ul de HTTP va trebui executat pe un thread secundar. Va reamintim o varianta cu un Thread si un handler pentru comunicare.

public class MainActivity extends AppCompatActivity {

    // Handler to communicate with UI thread
    private Handler mainHandler = new Handler(Looper.getMainLooper());
    private TextView resultTextView;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        resultTextView = findViewById(R.id.resultTextView);
        
        // Start HTTP request when a button is clicked
        Button fetchButton = findViewById(R.id.fetchButton);
        // When the button is pressed, make the HTTP request
        fetchButton.setOnClickListener(v -> makeHttpRequest());
    }
    
    private void makeHttpRequest() {
        // We create a new thread, and inside we will run the code for the HTTP API.
        new Thread(() -> {
            try {
                // mak
                mainHandler.post(() -> {
                    // Here we can run code on the main thread, and use variables
                    // defined in the activity such as restulTextView
                    resultTextView.setText(result);
                });
                
            } catch (Exception e) {
                // Handle error on main thread
                mainHandler.post(() -> {
                    resultTextView.setText("Error: " + e.getMessage());
                });
            }
        }).start();
    }
}

GET. Urmatorul exemplu prezinta o cere simpla de tip GET.

try {
  HttpClient httpClient = new DefaultHttpClient();
  HttpGet httpGet = new HttpGet("http://jepi.cs.pub.ro/expr/expr_get.php?operation=times&t1=9&t2=2");

  ResponseHandler<String> responseHandler = new BasicResponseHandler();
  String content = httpClient.execute(httpGet, responseHandler);
  if (content != null) {  
    /* do something with the response */
    Log.i(Constants.TAG, EntityUtils.toString(httpGetEntity));
  }            
} catch (Exception exception) {
  Log.e(Constants.TAG, exception.getMessage());
  if (Constants.DEBUG) {
    exception.printStackTrace();
  }
}

În situația în care se dorește transmiterea de parametri către serverul web, aceștia trebuie incluși în URL (în clar), fără a se depăși limita de 2048 de caractere și folosind numai caractere ASCII:

HttpGet httpGet = new HttpGet("http:*www.server.com?attribute1=value1&...&attributen=valuen");

POST. Urmatorul exemplu prezinta o cere simpla de tip POST.

try {
  HttpClient httpClient = new DefaultHttpClient();        
  HttpPost httpPost = new HttpPost("http://www.server.com");
  /* Lista de perechi tip (atribut, valoare) care vor contine
     informatiile transmise de client pe baza carora serverul
     va genera continutul, de exemplu (user, eim), (parola, 123)
  */  
  List<NameValuePair> params = new ArrayList<NameValuePair>();        
  params.add(new BasicNameValuePair("attribute1", "value1"));
  * ...
  params.add(new BasicNameValuePair("attributen", "valuen"));

  UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
  httpPost.setEntity(urlEncodedFormEntity);
             
  HttpResponse httpPostResponse = httpClient.execute(httpPost);  
  HttpEntity httpPostEntity = httpPostResponse.getEntity();  
  if (httpPostEntity != null) {
    * do something with the response
    Log.i(Constants.TAG, EntityUtils.toString(httpPostEntity));
   }
} catch (Exception exception) {
  Log.e(Constants.TAG, exception.getMessage());
  if (Constants.DEBUG) {
    exception.printStackTrace();
  }
}

Prelucrarea raspunsurilor. Prelucrarea unui răspuns HTTP se poate realiza:

  • prin prelucrarea obiectului de tip HttpEntity, utilizând fluxuri de intrare/ieșire:
    BufferedReader bufferedReader = null;
    StringBuilder result = new StringBuilder();
    try {
      * ...
      bufferedReader = new BufferedReader(new InputStreamReader(httpEntity.getContent()));
      int currentLineNumber = 0;
      String currentLineContent;
      while ((currentLineContent = bufferedReader.readLine()) != null) {
        currentLineNumber++;
        result.append(currentLineNumber).append(": ").append(currentLineContent).append("\n");
      }
      Log.i(Constants.TAG, result.toString());
    } catch (Exception exception) {
      Log.e(Constants.TAG, exception.getMessage());
      if (Constants.DEBUG) {
        exception.printStackTrace();
      }
    } finally {
      if(bufferedReader != null) {
        try {
          bufferedReader.close();
        } catch (IOException ioException) {
          Log.e(Constants.TAG, exception.getMessage());
          if (Constants.DEBUG) {
            ioException.printStackTrace();
          }
        }
      }
    }
    
  • utilizând un obiect de tip ResponseHandler, ce furnizează conținutul resursei solicitate, transmis ca parametru al metodei execute() a clasei HttpClient (pe lângă obiectul HttpGet|HttpPost)