Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
colocvii:colocviu01 [2015/03/27 23:14]
Andrei Roșu-Cojocaru [Model de Subiect]
colocvii:colocviu01 [2015/03/29 12:47] (current)
Andrei Roșu-Cojocaru
Line 3: Line 3:
 ===== Model de Subiect ===== ===== Model de Subiect =====
  
-{{url>http://​pdsd2015.andreirosucojocaru.ro/​_media/​colocvii/​colocviu01/​pdsd2015-tp01-varsim.pdf 90%,800px}}+<HTML> 
 +<​center>​ 
 +</HTML>
  
-{{ :​colocvii:​colocviu01:​pdsd2015-tp01-varsim.pdf }}+{{url>http://​ocw.cs.pub.ro/​courses/​_media/​pdsd/​colocvii/​colocviu01/​pdsd2015-tp01-varsim.pdf 90%,​800px}} 
 + 
 +<​HTML>​ 
 +</​center>​ 
 +</​HTML>​ 
 + 
 +{{ colocvii:​colocviu01:​pdsd2015-tp01-varsim.pdf }}
  
 ===== Observații Generale ===== ===== Observații Generale =====
Line 24: Line 32:
 ===== Rezolvări ===== ===== Rezolvări =====
  
-**1.** Se urmăresc indicațiile disponibile în secțiunea ​[[:tutoriale:​git#​crearea_unui_cont_github|Crearea unui cont Github]], ​subpunctele 3-4.+Proiectul Eclipse corespunzător aplicației Android ce conține rezolvările complete ale cerințelor colocviului este disponibil pe [[https://​github.com/​pdsd2015/​PracticalTest01|contul de Github al disciplinei]]. 
 + 
 +**A.1.** Se accesează [[https://​www.github.com|Github]] ​și se realizează autentificarea în contul personal, prin intermediul butonului //Sign in//. 
 + 
 +{{ :​colocvii:​colocviu01:​github_authentication.png?​nolink&​700 }} 
 + 
 +Se creează o zonă de lucru corespunzătoare unui proiect prin intermediului butonului //New Repository//​. 
 + 
 +{{ :​colocvii:​colocviu01:​github_new_repository.png?​nolink }} 
 + 
 +Configurarea depozitului la distanță presupune specificarea:​ 
 +  * unei denumiri; 
 +  * unei descrieri (opțional);​ 
 +  * tipului de director (public sau privat ​- doar contra cost!!!); 
 +  * modului de inițializare:​ 
 +    * local, prin ''​git init'';​ 
 +    * la distanță, prin ''​git clone''​ - depozitul la distanță nu trebuie să fie vid, în această situațoe  
 +  * unui fișier ''​README''​ (opțional);​ 
 +  * extensiilor ignorate (corespunzătoare limbajului de programare folosit, în cazul de față - Android) - incluse în fișierul ''​.gitignore'';​ 
 +  * tipului de licență sub care este publicat codul sursă. 
 + 
 +{{ :​colocvii:​colocviu01:​github_repository_configuration.png?​nolink }} 
 + 
 +**A.2.** Prin intermediul comenzii ''​git clone''​ se poate descărca întregul conținut în directorul curent (de pe discul local), inclusiv istoricul complet al versiunilor anterioare (care poate fi ulterior reconstituit după această copie, în cazul coruperii informațiilor stocate pe serverul la distanță).
  
-**2.**+<​note>​În situația în care se dorește clonarea conținutului din depozitul la distanță în alt director decât cel curent, acesta poate fi transmis ca parametru al comenzii, după URL-ul la care poate fi accesat proiectul în Github.</​note>​
  
 <​code>​ <​code>​
Line 32: Line 63:
 </​code>​ </​code>​
  
-**3.** Se urmăresc indicațiile disponibile în secțiunea [[:​laboratoare:​laborator01#​crearea_unei_aplicatii_android_in_eclipse_luna_sr1a_441_-_obligatoriu|Crearea unei aplicații Android în Eclipse Luna SR1a (4.4.1)]].+**A.3.** Se urmăresc indicațiile disponibile în secțiunea [[:​laboratoare:​laborator01#​crearea_unei_aplicatii_android_in_eclipse_luna_sr1a_441_-_obligatoriu|Crearea unei aplicații Android în Eclipse Luna SR1a (4.4.1)]].
  
-**4.**+**A.4.** Implementarea interfeței grafice va fi realizată prin intermediul unui fișier ''​.xml''​ care va fi plasat în directorul ''/​res/​layout''​ al proiectului.
  
-<file xml activity_practical_test01_main.xml>​ +De cele mai multe ori, interfața grafică poate fi realizată în două moduri: 
-<LinearLayout ​xmlns:​android="​http://​schemas.android.com/​apk/​res/​android"​+  * prin folosirea unui singur container de tip ''​RelativeLayout''​ în care vor fi plasate toate controalele,​ având poziția definită relativ unele la celelalte sau la marginile părintelui în care sunt incluse; 
 +  * prin folosirea mai multor containere de tip ''​LinearLayout'',​ imbricate, având orientări diferite (orizontal - implicit, sau vertical). 
 + 
 +  * Varianta 1 - un singur container de tip ''​RelativeLayout''​ 
 +<note tip>​Dacă se dorește ca un anumit control să fie aliniat cu un control care se găsește deasupra sa (aliniere pe orizontală),​ acesta va fi indicat ca valoare pentru proprietățile ''​android:​layout_alignLeft''​ și ''​android:​layout_alignRight''​ (proprietatea ''​android:​layout_width''​ fiind ignorată în acest caz). În mod similar, dacă se dorește alinierea cu un control aflat la stânga (aliniere pe verticală),​ acesta va fi precizat ca valoare pentru proprietățile ''​android:​layout_alignTop''​ și ''​android:​layout_alignBottom''​ (proprietatea ''​android:​layout_height''​ fiind ignorată în acest caz). </​note> ​<file xml activity_practical_test01_main.xml>​ 
 +<RelativeLayout ​xmlns:​android="​http://​schemas.android.com/​apk/​res/​android"​
   xmlns:​tools="​http://​schemas.android.com/​tools"​   xmlns:​tools="​http://​schemas.android.com/​tools"​
   android:​layout_width="​match_parent"​   android:​layout_width="​match_parent"​
   android:​layout_height="​wrap_content"​   android:​layout_height="​wrap_content"​
-  android:​orientation="​vertical"​ 
   tools:​context="​ro.pub.cs.systems.pdsd.practicaltest01.PracticalTest01MainActivity"​ >   tools:​context="​ro.pub.cs.systems.pdsd.practicaltest01.PracticalTest01MainActivity"​ >
- +
   <Button   <Button
     android:​id="​@+id/​navigate_to_secondary_activity_button"​     android:​id="​@+id/​navigate_to_secondary_activity_button"​
     android:​layout_width="​wrap_content"​     android:​layout_width="​wrap_content"​
     android:​layout_height="​wrap_content"​     android:​layout_height="​wrap_content"​
-    android:layout_gravity="right"+    android:layout_alignParentTop="true"​ 
 +    android:​layout_alignParentRight="​true"
     android:​text="​@string/​navigate_to_secondary_activity"​ />     android:​text="​@string/​navigate_to_secondary_activity"​ />
 +    ​
 +  <​EditText
 +    android:​id="​@+id/​left_edit_text"​
 +    android:​layout_width="​wrap_content"​
 +    android:​layout_height="​wrap_content"​
 +    android:​saveEnabled="​false"​
 +    android:​enabled="​false"​
 +    android:​inputType="​number"​
 +    android:​ems="​7"​
 +    android:​layout_alignParentLeft="​true"​
 +    android:​layout_below="​@id/​navigate_to_secondary_activity_button"​
 +    android:​gravity="​center"​ />
 +    ​
 +  <​EditText
 +    android:​id="​@+id/​right_edit_text"​
 +    android:​layout_width="​wrap_content"​
 +    android:​layout_height="​wrap_content"​
 +    android:​saveEnabled="​false"​
 +    android:​enabled="​false" ​  
 +    android:​inputType="​number"​
 +    android:​ems="​7"​
 +    android:​layout_alignParentRight="​true"​
 +    android:​layout_below="​@id/​navigate_to_secondary_activity_button"​  ​       ​
 +    android:​gravity="​center"​ />
 +    ​
 +  <Button
 +    android:​id="​@+id/​left_button"​
 +    android:​layout_width="​wrap_content"​
 +    android:​layout_height="​wrap_content"​
 +    android:​layout_alignLeft="​@id/​left_edit_text"​
 +    android:​layout_below="​@id/​left_edit_text"​
 +    android:​layout_alignRight="​@id/​left_edit_text"​
 +    android:​text="​@string/​press_me"​ />
 +   ​
 +  <Button
 +    android:​id="​@+id/​right_button"​
 +    android:​layout_width="​wrap_content"​
 +    android:​layout_height="​wrap_content"​
 +    android:​layout_alignLeft="​@id/​right_edit_text"​
 +    android:​layout_alignRight="​@id/​right_edit_text"​
 +    android:​layout_below="​@id/​right_edit_text"​  ​     ​
 +    android:​text="​@string/​press_me_too"​ />
 +
 +</​RelativeLayout>​
 +</​file>​
 +
 +  * Varianta 2 - mai multe containere de tip ''​LinearLayout''​ imbricate
 +
 +<note tip>​Dacă se dorește ca un anumit control să ocupe o anumită proporție în cadrul continerului,​ se va utiliza proprietatea ''​android:​layout_weight'',​ însă pentru a fi luată în considerare,​ atributul ''​android:​layout_width'',​ respectiv ''​android:​layout_height''​ (în funcție de coordonata pe care se dorește obținerea unei astfel de funcționalități) trebuie să aibă valoarea ''​0dp''​.</​note>​
 +
 +<file xml activity_practical_test01_main.xml>​
 +<​LinearLayout xmlns:​android="​http://​schemas.android.com/​apk/​res/​android"​
 +  xmlns:​tools="​http://​schemas.android.com/​tools"​
 +  android:​layout_width="​match_parent"​
 +  android:​layout_height="​wrap_content"​
 +  android:​orientation="​vertical"​
 +  tools:​context="​ro.pub.cs.systems.pdsd.practicaltest01.PracticalTest01MainActivity"​ >
            
   <​LinearLayout   <​LinearLayout
Line 60: Line 153:
       android:​layout_height="​wrap_content"​       android:​layout_height="​wrap_content"​
       android:​layout_weight="​1"​       android:​layout_weight="​1"​
-      android:​saveEnabled="​false"​ 
       android:​enabled="​false"​       android:​enabled="​false"​
       android:​inputType="​number"​       android:​inputType="​number"​
Line 70: Line 162:
       android:​layout_height="​wrap_content"​       android:​layout_height="​wrap_content"​
       android:​layout_weight="​1"​       android:​layout_weight="​1"​
-      android:​saveEnabled="​false"​ 
       android:​enabled="​false"  ​       android:​enabled="​false"  ​
       android:​inputType="​number"​       android:​inputType="​number"​
Line 115: Line 206:
 </​file>​ </​file>​
  
-<file java PracticalTest01Activity.java>+În activitatea corespunzătoare,​ interfața grafică definită în fișierul ''​.xml''​ trebuie încărcată pe metoda ''​onCreate()''​ prin intermediul ''​setContentView()'',​ căreia i se transmite ca parametru identificatorul (referința) către această resursă (așa cum a fost generată în clasa abstractă ''​R.layout''​). În situația în care este necesar să se realizeze anumite operații pe controalele grafice componente (spre exemplu, să se încarce conținutul acestora), trebuie inițial să se obțină o referință către aceasta printr-un apel al metodei ''​findViewById()'',​ care primește de asemenea ca parametru identificatorul (referința) către această resursă (așa cum a fost generată în clasa abstractă ''​R.id''​).
  
 +<​note>​Nu este necesar să se implementeze metodele ''​onCreateOptionsMenu()'',​ respectiv ''​onOptionsItemSelected()'',​ acestea fiind de regulă generate în mod automat de mediul integrat de dezvoltare Eclipse.</​note>​
 +
 +<file java PracticalTest01Activity.java>​
 +package ro.pub.cs.systems.pdsd.practicaltest01;​
 + 
 +import android.app.Activity;​
 +import android.content.Intent;​
 +import android.os.Bundle;​
 +import android.view.Menu;​
 +import android.view.MenuItem;​
 +import android.view.View;​
 +import android.widget.Button;​
 +import android.widget.EditText;​
 +import android.widget.Toast;​
 + 
 +public class PracticalTest01MainActivity extends Activity {
 + 
 +  @Override
 +  protected void onCreate(Bundle savedInstanceState) {
 +    super.onCreate(savedInstanceState);​
 +    setContentView(R.layout.activity_practical_test01_main);​
 +         
 +    EditText leftEditText = (EditText)findViewById(R.id.left_edit_text);​
 +    EditText rightEditText = (EditText)findViewById(R.id.right_edit_text);​
 +         
 +    leftEditText.setText(String.valueOf(0));​
 +    rightEditText.setText(String.valueOf(0)); ​    
 +  }
 +      ​
 +  @Override
 +  public boolean onCreateOptionsMenu(Menu menu) {
 +    getMenuInflater().inflate(R.menu.practical_test01,​ menu);
 +    return true;
 +  }
 + 
 +  @Override
 +  public boolean onOptionsItemSelected(MenuItem item) {
 +    int id = item.getItemId();​
 +    if (id == R.id.action_settings) {
 +      return true;
 +    }
 +    return super.onOptionsItemSelected(item);​
 +  }
 +}
 </​file>​ </​file>​
  
-**5.**+**B.1.** Pentru procesarea evenimentelor legate de interacțiunea de utilizator este necesară:​ 
 +  * implementarea unei clase ascultător pentru tipul de eveniment respectiv (se recomandă se se folosească o clasă internă - în cadrul activității -, cu nume); 
 +  * înregistrarea unui obiect - instanță a clasei - ca ascultător al controlului grafic, pentru tipul de eveniment respectiv. 
 + 
 +<​note>​Se recomandă să se utilizeze aceeași clasă / același obiect pentru tratarea evenimentelor de același tip, chiar dacă acestea vor fi asociate unor controale grafice diferite. În cazul în care este necesar să se realizeze procesări specifice pentru obiecte de același tip, se va realiza distincția dintre acestea prin intermediul identificatorului controlului grafic care le este asociat.</​note>​ 
 + 
 +Pe metoda ''​onCreate()''​ a activității se obțin referințe ale controlului grafic (prin metoda ''​findViewById()''​) și se înregistrează obiectul ascultător respectiv. 
 + 
 +<note tip>În situația în care în interfața grafică există mai multe obiecte de același tip, având în vedere că operațiile ce trebuie realizate pentru fiecare în parte sunt aceleași, acestea se pot grupa prin procesarea iterativă unui tablou de identificatori (referințe) ale controalelor grafice respective.</​note>​
  
 <code java> <code java>
-private ButtonClickListener buttonClickListener = new ButtonClickListener();​ +public class PracticalTest01MainActivity extends Activity { 
-     ​ +  ​private ButtonClickListener buttonClickListener = new ButtonClickListener();​ 
-private class ButtonClickListener implements Button.OnClickListener {+ 
 +  private class ButtonClickListener implements Button.OnClickListener {
                    
-  ​@Override +    ​@Override 
-  public void onClick(View view) { +    public void onClick(View view) { 
-    EditText leftEditText = (EditText)PracticalTest01MainActivity.this.findViewById(R.id.left_edit_text);​ +      EditText leftEditText = (EditText)PracticalTest01MainActivity.this.findViewById(R.id.left_edit_text);​ 
-    EditText rightEditText = (EditText)PracticalTest01MainActivity.this.findViewById(R.id.right_edit_text);​ +      EditText rightEditText = (EditText)PracticalTest01MainActivity.this.findViewById(R.id.right_edit_text);​ 
-    int leftButtonClickedNumber = Integer.parseInt(leftEditText.getText().toString());​ +      int leftButtonClickedNumber = Integer.parseInt(leftEditText.getText().toString());​ 
-    int rightButtonClickedNumber = Integer.parseInt(rightEditText.getText().toString());​+      int rightButtonClickedNumber = Integer.parseInt(rightEditText.getText().toString());​
     ​     ​
-    ​switch(view.getId()) { +      ​switch(view.getId()) { 
-      case R.id.left_button:​ +        case R.id.left_button:​ 
-        leftButtonClickedNumber++;​ +          leftButtonClickedNumber++;​ 
-        leftEditText.setText(String.valueOf(leftButtonClickedNumber));​ +          leftEditText.setText(String.valueOf(leftButtonClickedNumber));​ 
-        break; +          break; 
-      case R.id.right_button:​ +        case R.id.right_button:​ 
-        rightButtonClickedNumber++;​ +          rightButtonClickedNumber++;​ 
-        rightEditText.setText(String.valueOf(rightButtonClickedNumber));​ +          rightEditText.setText(String.valueOf(rightButtonClickedNumber));​ 
-        break;+          break; 
 +      }
     }     }
-  ​} +  } 
-} +
     ​     ​
-@Override +  ​@Override 
-protected void onCreate(Bundle savedInstanceState) {+  protected void onCreate(Bundle savedInstanceState) { 
 +    super.onCreate(savedInstanceState);​ 
 +     
 +    // ... 
 + 
 +    Button leftButton = (Button)findViewById(R.id.left_button);​ 
 +    leftButton.setOnClickListener(buttonClickListener);​ 
 +    Button rightButton = (Button)findViewById(R.id.right_button);​ 
 +    rightButton.setOnClickListener(buttonClickListener); ​       
 +  } 
 +  ​
   // ...   // ...
 +  ​
 +}
 +</​code>​
  
-  Button leftButton = (Button)findViewById(R.id.left_button); +**B.2.** 
-  ​leftButton.setOnClickListener(buttonClickListener);​ + 
-  ​Button rightButton ​= (Button)findViewById(R.id.right_button);​ +**a)** Pentru majoritatea controalelor grafice, sistemul de operare Android realizează în mod automat salvarea / restaurarea stării în situația în care o activitate este distrusă pentru asigurarea necesarului de memorie. Dacă se dorește ca această operație să fie tratată în alt mod, dezactivarea acestui mecanism se realizează prin specificarea atributului ''​android:​saveEnabled''​ corespunzător controlului grafic respectiv având valoarea ''​false''​. 
-  ​rightButton.setOnClickListener(buttonClickListener); ​       + 
-}    +<code xml> 
 +<​LinearLayout ​... > 
 +  ​<​EditText 
 +    android:id="@+id/​left_edit_text"​ 
 +    android:​saveEnabled="​false"​ 
 +    ​... /> 
 +          
 +  ​<​EditText 
 +    android:​id="​@+id/​right_edit_text"​ 
 +    android:​saveEnabled="​false"​ 
 +    ​... /> 
 +    ​ 
 +  <!-- other nested layouts or widgets --> 
 +     
 +</​LinearLayout>​
 </​code>​ </​code>​
  
-**6.**+**b)** În situația în care sistemul de operare Android distruge activitatea pentru asigurarea resurselor necesare, este necesară asigurarea unui comportament consistent / persistenței aplicației:​ 
 +  * salvarea stării se realizează pe metoda ''​onSaveInstanceState()''​ care primește un parametru de tip ''​Bundle''​ în care vor fi stocate informațiile respective, identificarea lor realizându-se prin intermediul unei chei de tip șir de caractere; metoda este invocată înainte de ''​onStop()''​ deși pot exista situații în care aceasta este apelată chiar înainte de ''​onPause()'';​ 
 +  * restaurarea stării se realizează:​ 
 +    * pe metoda ''​onCreate()''​ pentru care parametrul de tip ''​Bundle''​ este nenul în situația în care există o stare anterioară;​ 
 +    * pe metoda ''​onRestoreInstanceState()''​ care este invocată în mod automat - primind un parametru de tip ''​Bundle''​ numai în situația în care există o stare anterioară;​ metoda se apelează între metodele ''​onStart()''​ și ''​onRestore()''​.
  
-**a)**+<​note>​În parametrul de tip ''​Bundle''​ nu pot fi stocate decât obiecte care implementează ''​android.os.Parcelable''​.</​note>​
  
-**b)**+Salvarea stării implică plasarea în obiectul de tip ''​Bundle''​ a unei valori, prin metode de tip ''​put<​type>​()'',​ folosind un șir de caractere definit de utilizator (o convenție de nume).
  
-**c)**+Restaurarea stării implică preluarea în obiectul de tip ''​Bundle''​ a valorii, prin metode de tip ''​get<​type>​()'',​ folosind șirul de caractere corespunzător (convenția de nume). Se recomandă să se verifice faptul ​că valoarea respectivă este nenulă (respectiv nu a fost furnizată valoarea implicită).
  
-**d)**+<code java> 
 +public class PracticalTest01MainActivity extends Activity { 
 + 
 +  @Override 
 +  protected void onCreate(Bundle savedInstanceState) { 
 +    super.onCreate(savedInstanceState);​ 
 +     
 +    // ... 
 + 
 +    if (savedInstanceState != null) { 
 +      String leftCount = savedInstanceState.getString("​leftCount"​);​ 
 +      if (leftCount != null) { 
 +        leftEditText.setText(leftCount);​ 
 +      } else { 
 +        leftEditText.setText(String.valueOf(0));​ 
 +      } 
 +      String rightCount = savedInstanceState.getString("​rightCount"​);​ 
 +      if (rightCount != null) { 
 +        rightEditText.setText(rightCount);​ 
 +      } else { 
 +        rightEditText.setText(String.valueOf(0));​ 
 +      } 
 +    } else { 
 +      leftEditText.setText(String.valueOf(0));​ 
 +      rightEditText.setText(String.valueOf(0));​ 
 +    } 
 +  } 
 + 
 +  @Override 
 +  protected void onSaveInstanceState(Bundle savedInstanceState) { 
 +    EditText leftEditText = (EditText)findViewById(R.id.left_edit_text);​ 
 +    EditText rightEditText = (EditText)findViewById(R.id.right_edit_text);​ 
 +    savedInstanceState.putString("​leftCount",​ leftEditText.getText().toString());​ 
 +    savedInstanceState.putString("​rightCount",​ rightEditText.getText().toString());​ 
 +  } 
 +   
 +  // ... 
 +}   
 +</​code>​ 
 + 
 +**c)** Pentru a simula faptul că sistemul de operare Android distruge activitatea pentru asigurarea necesarului de resurse, se poate proceda astfel: 
 +  - se oprește activitatea prin accesarea butonului //Menu//, astfel încât activitatea să rămână în memorie, fără a fi însă vizibilă, asigurându-se totodată apelarea metodelor ''​onPause()''​ și ''​onStop()''​ și implicit a metodei ''​onSaveInstanceState()'';​ 
 +  - în DDMS (//Window// → //Open Perspective//​ → //Other// → //DDMS//) se identifică procesul corespunzător activății respective și se oprește forțat (prin intermediul butonului //​Stop//​);​\\ {{ :​colocvii:​colocviu01:​ddms.png?​nolink&​400 }} 
 +  - se (re)pornește activitatea din meniul dispozitivului mobil, astfel încât să  se apeleze metodele ''​onCreate()'',​ respectiv ''​onStart()''​ și ''​onResume()''​ (și, implicit, ''​onRestoreInstanceState()''​). 
 + 
 +**d)** ​În situația în care utilizatorul apasă butonul //Back//, se apelează metodele ''​onPause()'',​ ''​onStop()''​ și ''​onDestroy()'',​ fără a se invoca însă și metoda ''​onSaveInstanceState()''​ întrucât se consideră că în această situație utilizatorul nu își dorește să revină la starea curentă a activității. Din acest motiv, starea nu este salvată în obiectul de tip ''​Bundle''​ și acesta nu va conține informațiile respective care să poată fi astfel restaurate. 
 + 
 +Dacă se dorește salvarea / restaurarea stării în situația în care utilizatorul apasă tasta //Back//, se recomandă să se utilizeze un alt mecanism pentru asigurarea persistenței,​ cum ar fi baza de date SQLite sau un obiect de tipul ''​android.content.SharedPreferences''​. 
 + 
 +**C.1.** Într-o aplicație Android, o activitate trebuie să fie precizată prin următoarele elemente: 
 +  * o etichetă de tip ''<​activity>''​ în fișiserul ''​AndroidManifest.xml'',​ având asociată și un filtru de intenții (etichetă de tip ''<​intent-filter>''​);​ 
 +  * o interfață grafică, definită în cadrul unui fișier ''​.xml''​ în directorul ''/​res/​layout'';​ 
 +  * o clasă derivată din ''​Activity'',​ în care să se implementeze cel puțin metoda ''​onCreate()'',​ pe care să se încarce interfața grafică definită anterior. 
 + 
 +Crearea acestor resurse este realizată în mod automat în mediul integrat de dezvoltare Eclipse în momentul în care se solicită definirea unei resurse de tip //Android Activity// (//File// → //New// → //Other// → //Android// → //Android Activity//​). 
 + 
 +{{ :​colocvii:​colocviu01:​eclipse_activity01.png?​nolink&​500 }} 
 + 
 +{{ :​colocvii:​colocviu01:​eclipse_activity02.png?​nolink&​500 }} 
 + 
 +{{ :​colocvii:​colocviu01:​eclipse_activity03.png?​nolink&​500 }} 
 + 
 +{{ :​colocvii:​colocviu01:​eclipse_activity04.png?​nolink&​500 }} 
 + 
 +**a)** În fișierul ''​AndroidManifest.xml''​ se specifică activitatea printr-o element de tip ''<​activity>''​ în cadrul etichetei ''<​application>''​ pentru care se definesc: 
 +  * atributul ''​android:​name''​ în care se indică denumirea clasei de tip ''​Activity''​ care va gestiona activitatea (afișarea interfeței grafice și tratarea interacțiunii cu utilizatorul);​ 
 +  * atributul ''​android:​label''​ precizează o etichetă care va fi asociată activității;​ 
 +  * un filtru de intenții, prin care se controlează modul în care va putea fi lansată în execuție prin intermediul unei alte intenții: ​  
 +    * eticheta ''<​action>''​ stabilește acțiunea pe care o poate realiza activitatea;​ va avea o valoare definită de utilizator, reprezentând o convenție;​ 
 +    * eticheta ''<​category>''​ clasifică activitatea,​ impunându-se să fie folosită valoarea ''​android.intent.category.DEFAULT''​ pentru ca activitatea să poată fi invocată prin intermediul unei intenții. 
 + 
 +<note tip>În cazul în care activitatea este generată folosind mediul integrat de dezvoltare Eclipse, în fișierul ''​AndroidManifest.xml''​ nu se completează în mod automat și filtrul de intenții, fiind necesar ca acesta să fie menționat de utilizator, manual.</​note>​ 
 + 
 +<file xml AndroidManifest.xml>​ 
 +<​manifest ... > 
 +  <​application ... > 
 +    <​activity 
 +      android:​name="​.PracticalTest01SecondaryActivity"​ 
 +      android:​label="​@string/​title_activity_practical_test01_secondary"​ > 
 +      <​intent-filter>​ 
 +        <action android:​name="​ro.pub.cs.systems.pdsd.intent.action.PracticalTest01SecondaryActivity"​ /> 
 +        <​category android:​name="​android.intent.category.DEFAULT"​ /> 
 +      </​intent-filter>​ 
 +    </​activity>​ 
 +  </​application>​ 
 +</​manifest>​ 
 +</​file>​ 
 + 
 +**b)** O interfață grafică este definită în mod obișnuit, prin intermediul unui fișier ''​.xml''​ plasat în directorul ''/​res/​layout''​ în care sunt precizate controalele grafice cu atributele și valorile lor, sub formă de componente în cadrul unor mecanisme de dispunere. 
 + 
 +<file xml activity_practical_test01_secondary.xml>​ 
 +<​LinearLayout xmlns:​android="​http://​schemas.android.com/​apk/​res/​android"​ 
 +  xmlns:​tools="​http://​schemas.android.com/​tools"​ 
 +  android:​layout_width="​match_parent"​ 
 +  android:​layout_height="​match_parent"​ 
 +  android:​orientation="​vertical"​ 
 +  tools:​context="​ro.pub.cs.systems.pdsd.practicaltest01.PracticalTest01SecondaryActivity"​ > 
 +  
 +  <​TextView 
 +    android:​id="​@+id/​number_of_clicks_text_view"​ 
 +    android:​layout_width="​match_parent"​ 
 +    android:​layout_height="​wrap_content"​ 
 +    android:​gravity="​center"​ /> 
 +  
 +  <​LinearLayout 
 +    android:​layout_width="​wrap_content"​ 
 +    android:​layout_height="​wrap_content"​ 
 +    android:​layout_gravity="​center"​ > 
 +  
 +    <​Button 
 +      android:​id="​@+id/​ok_button"​ 
 +      android:​layout_width="​wrap_content"​ 
 +      android:​layout_height="​wrap_content"​ 
 +      android:​text="​@string/​ok"​ /> 
 +  
 +    <​Button 
 +      android:​id="​@+id/​cancel_button"​ 
 +      android:​layout_width="​wrap_content"​ 
 +      android:​layout_height="​wrap_content"​ 
 +      android:​text="​@string/​cancel"​ /> 
 +  
 +  </​LinearLayout>​ 
 +  
 +</​LinearLayout>​ 
 +</​file>​ 
 + 
 +**c)** În clasa care gestionează comportamentul activității,​ pe metoda ''​onCreate()'',​ în mod obișnuit, se încarcă interfața grafică (prin metoda ''​setContentView()''​),​ se obțin referințe către controalele grafice (printr-un apel al metodei ''​findViewById()''​) și se stabilește conținutul acestora, respectiv se înregistrează obiecte ascultător pentru anumite tipuri de evenimente (după ce în prealabil a fost implementată și clasa corespunzătoare). 
 + 
 +Pentru activitățile care sunt invocate prin intermediul unei intenții:​ 
 +  * se poate obține o referință către intenție, din contextul căruia pot fi obținute informațiile atașate în secțiunea ''​extra''​ prin intermediul metodelor ''​getExtras()''​ sau ''​get<​type>​Extra()''​ care primesc ca parametru cheia sub care au fost stocate datele respective;​ 
 +  * se poate transmite un rezultat înapoi către activitatea din care au fost invocate prin intermediul metodei ''​setResult()''​ care primește ca parametri:​ 
 +    * un cod de rezultat întreg (frecvent, sunt folosite valorile RESULT_OK și RESULT_CANCELED,​ dar poate fi folosită și o valoare definită de utilizator);​ 
 +    * o intenție, în care pot fi plasate informații suplimentare.  
 + 
 +Metoda ''​finish()''​ poate fi folosită pentru a finaliza activitatea în mod forțat (semnalând faptul că procesările corespunzătoare activității au fost terminate).
  
-**7.** 
 <file java PracticalTest01SecondaryActivity.java>​ <file java PracticalTest01SecondaryActivity.java>​
 package ro.pub.cs.systems.pdsd.practicaltest01;​ package ro.pub.cs.systems.pdsd.practicaltest01;​
Line 181: Line 489:
    
 public class PracticalTest01SecondaryActivity extends Activity { public class PracticalTest01SecondaryActivity extends Activity {
 +     
   private ButtonClickListener buttonClickListener = new ButtonClickListener();​   private ButtonClickListener buttonClickListener = new ButtonClickListener();​
-  ​+     
   private class ButtonClickListener implements Button.OnClickListener {   private class ButtonClickListener implements Button.OnClickListener {
                    
Line 198: Line 507:
       }       }
     }     }
-  }  +  }   
-}  ​+  
 +  @Override 
 +  protected void onCreate(Bundle savedInstanceState) { 
 +    super.onCreate(savedInstanceState);​ 
 +    setContentView(R.layout.activity_practical_test01_secondary);​ 
 +          
 +    TextView numberOfClicksTextView = (TextView)findViewById(R.id.number_of_clicks_text_view);​ 
 +     
 +    Intent intent = getIntent();​ 
 +    if (intent != null) { 
 +      String numberOfClicks = intent.getStringExtra("​number_of_clicks"​);​ 
 +      if (numberOfClicks != null) { 
 +        numberOfClicksTextView.setText(getResources().getString(R.string.number_of_clicks).replace("???",​ numberOfClicks));​ 
 +      ​} 
 +    } 
 +          
 +    Button buttonOk = (Button)findViewById(R.id.ok_button);​ 
 +    buttonOk.setOnClickListener(buttonClickListener);​ 
 +    Button buttonCancel = (Button)findViewById(R.id.cancel_button);​ 
 +    buttonCancel.setOnClickListener(buttonClickListener); ​      
 +  } 
 +  
 +  @Override 
 +  public boolean onCreateOptionsMenu(Menu menu) { 
 +    getMenuInflater().inflate(R.menu.practical_test01_secondary,​ menu); 
 +    return true; 
 +  } 
 +  
 +  @Override 
 +  public boolean onOptionsItemSelected(MenuItem item) { 
 +    int id = item.getItemId();​ 
 +    if (id == R.id.action_settings) { 
 +      return true; 
 +    } 
 +    return super.onOptionsItemSelected(item);​ 
 +  } 
 +}
 </​file>​ </​file>​
  
-**8.**+**C.2.** Pentru a invoca o altă activitate prin intermediul unei intenții, o activitate trebuie: 
 +  * să definească în interfața grafică un control prin intermediul căruia va fi lansată în execuție activitatea respectivă (în fișierul ''​.xml''​ din directorul ''/​res/​layout''​);​
  
-**9.**+<code xml> 
 +<​LinearLayout xmlns:​android="​http://​schemas.android.com/​apk/​res/​android"​ 
 +  xmlns:​tools="​http://​schemas.android.com/​tools"​ 
 +  android:​layout_width="​match_parent"​ 
 +  android:​layout_height="​wrap_content"​ 
 +  android:​orientation="​vertical"​ 
 +  tools:​context="​ro.pub.cs.systems.pdsd.practicaltest01.PracticalTest01MainActivity"​ > 
 +  
 +  <​Button 
 +    android:​id="​@+id/​navigate_to_secondary_activity_button"​ 
 +    android:​layout_width="​wrap_content"​ 
 +    android:​layout_height="​wrap_content"​ 
 +    android:​layout_gravity="​right"​ 
 +    android:​text="​@string/​navigate_to_secondary_activity"​ /> 
 +     
 +  <!-- other nested layouts or widgets --> 
 +   
 +</​LinearLayout>​ 
 +</​code>​ 
 + 
 +  - în codul sursă corespunzător clasei care gestionează activitatea respectivă:​ 
 +    - pe metoda ''​onCreate()'':​ 
 +      - să obțină o referință către controlul grafic prin intermediul căruia va fi lansată în execuție o altă activitate;​ 
 +      - să înregistreze un obiect ascultător care va trata evenimentul legat de controlul grafic respectiv;​ 
 +    - să definească o clasă ascultător (internă, cu nume) pentru tipul de eveniment respectiv, iar pe metoda de tratare se vor realiza următoarele operații:​ 
 +      - se va instanția un obiect de tip ''​Intent'',​ care poate primi ca parametru:​ 
 +        - contextul curent (obiectul ''​this''​) și clasa care deservește activitatea (obiect de tip ''​.class''​) - adecvată situației în care activitatea invocată se găsește în aceeași aplicație ca și activitatea care invocă; 
 +        - acțiunea asociată activității în filtrul de intenții - adecvată situației în care activitatea invocată se găsește în altă aplicație decât activitatea care o invocă; 
 +      - se asociază un set de informații care vor fi transmise celeilalte activități (în secțiunea ''​extra''​ a intenției) prin intermediul metodei ''​putExtra()'',​ fiecare valoare (de tip ''​android.os.Parcelable''​) având asociat un atribut prin care va fi identificat ulterior, de tip șir de caractere;​ 
 +      - se lansează în execuție activitatea prin intermediul metodei ''​startActivityForResult()''​ care primește ca parametru intenția și un cod de cerere, având rolul de a identifica ulterior instanța activității din care se revine. 
 +    - să implementeze metoda ''​onActivityResult()'',​ apelată în mod automat la revenirea din activitatea invocată, aceasta primind ca parametrii:​ 
 +      - codul de cerere trimis în momentul în care activitatea a fost lansată în execuție;​ 
 +      - rezultatul furnizat de activitatea invocată;​ 
 +      - intenția generată de activitatea invocată. 
 + 
 +<code java> 
 +public class PracticalTest01MainActivity extends Activity { 
 +      
 +  private final static int SECONDARY_ACTIVITY_REQUEST_CODE = 1; 
 +   
 +  private ButtonClickListener buttonClickListener = new ButtonClickListener();​ 
 +      
 +  private class ButtonClickListener implements Button.OnClickListener { 
 +          
 +    @Override 
 +    public void onClick(View view) { 
 +      EditText leftEditText = (EditText)PracticalTest01MainActivity.this.findViewById(R.id.left_edit_text);​ 
 +      EditText rightEditText = (EditText)PracticalTest01MainActivity.this.findViewById(R.id.right_edit_text);​ 
 +      switch(view.getId()) { 
 +        case R.id.navigate_to_secondary_activity_button:​ 
 +          Intent intent = new Intent("​ro.pub.cs.systems.pdsd.intent.action.PracticalTest01SecondaryActivity"​);​ 
 +          intent.putExtra("​number_of_clicks",​ 
 +            String.valueOf( 
 +              Integer.parseInt(leftEditText.getText().toString()) 
 +              + Integer.parseInt(rightEditText.getText().toString()) 
 +            )); 
 +          startActivityForResult(intent,​ SECONDARY_ACTIVITY_REQUEST_CODE);​ 
 +          break; 
 +        // ... 
 +      } 
 +    } 
 +     
 +  } 
 +   
 +  @Override 
 +  protected void onCreate(Bundle savedInstanceState) { 
 +    super.onCreate(savedInstanceState);​ 
 +    // ... 
 +          
 +    Button navigateToSecondaryActivityButton = (Button)findViewById(R.id.navigate_to_secondary_activity_button);​ 
 +    navigateToSecondaryActivityButton.setOnClickListener(buttonClickListener); ​     
 +  } 
 +   
 +  @Override 
 +  public void onActivityResult(int requestCode,​ int resultCode, Intent intent) { 
 +    Toast.makeText(this,​ "The activity returned with result "​+resultCode,​ Toast.LENGTH_LONG).show();​ 
 +  } 
 +   
 +  // ... 
 +       
 +} 
 +</​code>​ 
 + 
 +**C.3.** Pentru încărcarea codului în contextul depozitului din cadrul contului Github personal: 
 +  - se transferă modificările din zona de lucru în zona de lucru în zona de așteptare prin intermediul comenzii ''​git add'',​ indicându-se și fișierele respective (pot fi folosite șabloane pentru a desemna mai multe fișiere);​ 
 +  - se consemnează modificările din zona de așteptare în directorul Git prin intermediul comenzii ''​git commit -m'',​ precizându-se și un mesaj sugestiv: 
 +  - se încarcă modificările la distanță, prin intermediul comenzii ''​git push'',​ care primește ca parametrii:​ 
 +    - sursa (prin eticheta ''​origin''​ se indică depozitul de unde au fost descărcat conținutul);​ 
 +    - destinația:​ ramificația curentă (implicit, aceasta poartă denumirea ''​master''​).
  
 <​code>​ <​code>​
Line 210: Line 644:
 student@pdsd2015:​~/​PracticalTest01$ git commit -m "​finished tasks for PracticalTest01"​ student@pdsd2015:​~/​PracticalTest01$ git commit -m "​finished tasks for PracticalTest01"​
 student@pdsd2015:​~/​PracticalTest01$ git push origin master student@pdsd2015:​~/​PracticalTest01$ git push origin master
 +</​code>​
 +
 +În cazul în care este necesar, vor fi configurați parametrii necesari operației de consemnare (numele de utilizator și adresa de poștă electronică):​
 +
 +<​code>​
 +student@pdsd2015:​~/​PracticalTest01$ git config --global user.name "​Perfect Student"​
 +student@pdsd2015:​~/​PracticalTest01$ git config --global user.email perfectstudent@cs.pub.ro
 </​code>​ </​code>​
colocvii/colocviu01.1427490882.txt.gz · Last modified: 2015/03/27 23:14 by Andrei Roșu-Cojocaru
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0