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/28 18:49]
Andrei Roșu-Cojocaru
colocvii:colocviu01 [2017/02/20 20:54] (current)
Line 7: Line 7:
 </​HTML>​ </​HTML>​
  
-{{url>​http://​ocw.cs.pub.ro/courses/_media/pdsd/​colocvii/​colocviu01/​pdsd2015-tp01-varsim.pdf 90%,800px}}+{{url>​http://​eim2016.andreirosucojocaru.ro/​_media/​colocvii/​colocviu01/​eim2016-tp01-varsim.pdf 90%,800px}}
  
 <​HTML>​ <​HTML>​
Line 13: Line 13:
 </​HTML>​ </​HTML>​
  
-{{ colocvii:​colocviu01:​pdsd2015-tp01-varsim.pdf }}+{{ :colocvii:​colocviu01:​eim2016-tp01-varsim.pdf }}
  
 ===== Observații Generale ===== ===== Observații Generale =====
Line 20: Line 20:
   * un cont Github personal, pe care să existe drepturi de citire și de scriere;   * un cont Github personal, pe care să existe drepturi de citire și de scriere;
   * SDK-ul de Android (cu o imagine pentru nivelul de API 16 - Jelly Bean 4.1);   * SDK-ul de Android (cu o imagine pentru nivelul de API 16 - Jelly Bean 4.1);
-  * mediul de dezvoltare integrat Eclipse, împreună cu plugin-ul Android Developer Tools;+  * mediul de dezvoltare integrat ​(Eclipse împreună cu plugin-ul Android Developer Tools sau Android Studio);
   * un dispozitiv mobil:   * un dispozitiv mobil:
     * fizic (bring your own device);     * fizic (bring your own device);
     * virtual: Genymotion, AVD.     * virtual: Genymotion, AVD.
  
-<note important>În situația în care lucrați pe calculatoarele din laboratorul Ixia (EG106) este recomandat să folosiți:+<hidden>În situația în care lucrați pe calculatoarele din laboratorul Ixia (EG106) este recomandat să folosiți:
   * fluxbox ca utilitar pentru gestiunea ferestrelor (se alege din interfața de autentificare); ​   * fluxbox ca utilitar pentru gestiunea ferestrelor (se alege din interfața de autentificare); ​
   * epiphany pentru navigare Internet.   * epiphany pentru navigare Internet.
-Este de preferat să nu se depășească memoria disponibilă,​ întrucât comportamentul acestor mașini este imprevizibil în momentul în care se folosește swap-ul (se blochează, fără posibilitatea de recuperare din eroare).</​note>+Este de preferat să nu se depășească memoria disponibilă,​ întrucât comportamentul acestor mașini este imprevizibil în momentul în care se folosește swap-ul (se blochează, fără posibilitatea de recuperare din eroare).</​hidden>
  
 ===== Rezolvări ===== ===== Rezolvări =====
 +
 +Proiectele Eclipse / Android Studio corespunzătoare aplicației Android ce conține rezolvările complete ale cerințelor colocviului sunt disponibile pe [[https://​github.com/​eim2016/​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//. **A.1.** Se accesează [[https://​www.github.com|Github]] și se realizează autentificarea în contul personal, prin intermediul butonului //Sign in//.
Line 58: Line 60:
  
 <​code>​ <​code>​
-student@pdsd2015:~$ git clone https://​www.github.com/​perfectstudent/​PracticalTest01+student@eim2016:~$ git clone https://​www.github.com/​perfectstudent/​PracticalTest01
 </​code>​ </​code>​
  
-**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)]].+**A.3.** Se urmăresc indicațiile disponibile în secțiunea [[:​laboratoare:​laborator01#​crearea_unei_aplicatii_android_in_eclipse_mars_1_451_-_obligatoriu|Crearea unei aplicații Android în Eclipse ​Mars 1 (4.5.1)]] sau [[:​laboratoare:​laborator01#​crearea_unei_aplicatii_android_in_android_studio_151_-_obligatoriu|Crearea unei aplicații Android în Android Studio 1.5.1]].
  
 **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. **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.
Line 69: Line 71:
   * prin folosirea mai multor containere de tip ''​LinearLayout'',​ imbricate, având orientări diferite (orizontal - implicit, sau vertical).   * 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"​
 +  android:​layout_width="​match_parent"​
 +  android:​layout_height="​wrap_content"​
 +  tools:​context="​ro.pub.cs.systems.eim.practicaltest01.PracticalTest01MainActivity"​ >
 +
 +  <Button
 +    android:​id="​@+id/​navigate_to_secondary_activity_button"​
 +    android:​layout_width="​wrap_content"​
 +    android:​layout_height="​wrap_content"​
 +    android:​layout_alignParentTop="​true"​
 +    android:​layout_alignParentRight="​true"​
 +    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>​ <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>​
  
Line 77: Line 141:
   android:​layout_height="​wrap_content"​   android:​layout_height="​wrap_content"​
   android:​orientation="​vertical"​   android:​orientation="​vertical"​
-  tools:​context="​ro.pub.cs.systems.pdsd.practicaltest01.PracticalTest01MainActivity"​ >+  tools:​context="​ro.pub.cs.systems.eim.practicaltest01.PracticalTest01MainActivity"​ >
            
   <​LinearLayout   <​LinearLayout
Line 138: Line 202:
   </​LinearLayout>​   </​LinearLayout>​
    
 +</​LinearLayout>​
 +</​file>​
 +
 +  * Varianta 3 - un container de tip ''​LinearLayout''​ vertical care include un control grafic de tip ''​Button''​ și un container ''​GridLayout'',​ cu 2 linii și 2 coloane; pe linia 0 se vor găsi cele 2 câmpuri text editabile, a căror lungime trebuie să fie specificată explicit iar pe linia 1 cele două butoane, a căror aliniere (centrată pe orizontală raportat la celula din care fac parte) trebuie să fie precizată
 +
 +<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="​match_parent"​
 +  android:​paddingBottom="​@dimen/​activity_vertical_margin"​
 +  android:​paddingLeft="​@dimen/​activity_horizontal_margin"​
 +  android:​paddingRight="​@dimen/​activity_horizontal_margin"​
 +  android:​paddingTop="​@dimen/​activity_vertical_margin"​
 +  android:​orientation="​vertical"​
 +  tools:​context="​ro.pub.cs.systems.eim.practicaltest01.PracticalTest01MainActivity"​ >
 +    ​
 +  <Button
 +    android:​id="​@+id/​navigate_to_secondary_activity_button"​
 +    android:​layout_width="​wrap_content"​
 +    android:​layout_height="​wrap_content"​
 +    android:​text="​@string/​navigate_to_secondary_activity"/>​
 +    ​
 +    <​GridLayout
 +      android:​layout_width="​match_parent"​
 +      android:​layout_height="​wrap_content"​
 +      android:​rowCount="​2"​
 +      android:​columnCount="​2">​
 +        ​
 +      <​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="​6"​
 + android:​layout_row="​0"​
 + android:​layout_column="​0"​
 + android:​layout_gravity="​center"​
 + 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="​6"​
 + android:​layout_row="​0"​
 + android:​layout_column="​1"​
 + android:​layout_gravity="​center"​
 + android:​gravity="​center"​ />
 +
 +      <Button
 + android:​id="​@+id/​left_button"​
 + android:​layout_width="​wrap_content"​
 + android:​layout_height="​wrap_content"​
 + android:​layout_row="​1"​
 + android:​layout_column="​0"​
 + android:​layout_gravity="​center"​
 + android:​text="​@string/​press_me"​ />
 +
 +      <Button
 + android:​id="​@+id/​right_button"​
 + android:​layout_width="​wrap_content"​
 + android:​layout_height="​wrap_content"​
 + android:​layout_row="​1"​
 + android:​layout_column="​1"​
 + android:​layout_gravity="​center"​
 + android:​text="​@string/​press_me_too"​ />
 +
 +  </​GridLayout>​
 +
 </​LinearLayout>​ </​LinearLayout>​
 </​file>​ </​file>​
Line 146: Line 285:
  
 <file java PracticalTest01Activity.java>​ <file java PracticalTest01Activity.java>​
-package ro.pub.cs.systems.pdsd.practicaltest01;​+package ro.pub.cs.systems.eim.practicaltest01;​
    
 import android.app.Activity;​ import android.app.Activity;​
Line 159: Line 298:
    
 public class PracticalTest01MainActivity extends Activity { public class PracticalTest01MainActivity extends Activity {
 +
 +  private EditText leftEditText = null;
 +  private EditText rightEditText = null;
 +  private Button leftButton = null;
 +  private Button rightButton = null;
    
   @Override   @Override
Line 165: Line 309:
     setContentView(R.layout.activity_practical_test01_main);​     setContentView(R.layout.activity_practical_test01_main);​
                    
-    ​EditText ​leftEditText = (EditText)findViewById(R.id.left_edit_text);​ +    leftEditText = (EditText)findViewById(R.id.left_edit_text);​ 
-    ​EditText ​rightEditText = (EditText)findViewById(R.id.right_edit_text);​ +    rightEditText = (EditText)findViewById(R.id.right_edit_text);​
-         +
     leftEditText.setText(String.valueOf(0));​     leftEditText.setText(String.valueOf(0));​
-    rightEditText.setText(String.valueOf(0)); ​    ​+    rightEditText.setText(String.valueOf(0));​ 
 +     
 +    leftButton = (Button)findViewById(R.id.left_button);​ 
 +    rightButton = (Button)findViewById(R.id.right_button);​
   }   }
       ​       ​
Line 188: Line 334:
 } }
 </​file>​ </​file>​
 +
 +În mediul integrat de dezvoltare Eclipse, completarea automată a import-urilor necesare este realizată prin //​Ctrl+Shift+O//​.
 +
 +În mediul integrat de dezvoltare Android Studio, completarea automată a import-urilor necesare este realizată prin //​Alt+Enter//​.
  
 **B.1.** Pentru procesarea evenimentelor legate de interacțiunea de utilizator este necesară: **B.1.** Pentru procesarea evenimentelor legate de interacțiunea de utilizator este necesară:
Line 201: Line 351:
 <code java> <code java>
 public class PracticalTest01MainActivity extends Activity { public class PracticalTest01MainActivity extends Activity {
-  private ButtonClickListener buttonClickListener = new ButtonClickListener();​ 
  
-  private class ButtonClickListener implements ​Button.OnClickListener { +  ​private ButtonClickListener buttonClickListener = new ButtonClickListener();​ 
-         +  ​private class ButtonClickListener implements ​View.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 rightEditText = (EditText)PracticalTest01MainActivity.this.findViewById(R.id.right_edit_text);​ 
-      int leftButtonClickedNumber = Integer.parseInt(leftEditText.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++; +          ​int leftNumberOfClicks = Integer.parseInt(leftEditText.getText().toString());​ 
-          leftEditText.setText(String.valueOf(leftButtonClickedNumber));+          leftNumberOfClicks++; 
 +          leftEditText.setText(String.valueOf(leftNumberOfClicks));
           break;           break;
         case R.id.right_button:​         case R.id.right_button:​
-          ​rightButtonClickedNumber++; +          ​int rightNumberOfClicks = Integer.parseInt(rightEditText.getText().toString());​ 
-          rightEditText.setText(String.valueOf(rightButtonClickedNumber));+          rightNumberOfClicks++; 
 +          rightEditText.setText(String.valueOf(rightNumberOfClicks));
           break;           break;
       }       }
     }     }
-  } +  }
     ​     ​
   @Override   @Override
Line 231: Line 377:
     // ...     // ...
  
-    Button leftButton = (Button)findViewById(R.id.left_button);​ 
     leftButton.setOnClickListener(buttonClickListener);​     leftButton.setOnClickListener(buttonClickListener);​
-    Button rightButton = (Button)findViewById(R.id.right_button);​ 
     rightButton.setOnClickListener(buttonClickListener); ​           rightButton.setOnClickListener(buttonClickListener); ​      
   }   }
Line 274: Line 418:
  
 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ă). 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ă).
 +
 +<note tip>Se recomandă ca restaurarea stării să fie realizată pe metoda ''​onRestoreInstanceState()''​ în detrimentul metodei ''​onCreate()''​ pentru că în acest fel nu trebuie să se verifice starea obiectului de tip ''​Bundle'',​ iar procesările în urma cărora este creată o instanță a activității sunt mai rapide.</​note>​
  
 <code java> <code java>
Line 285: Line 431:
  
     if (savedInstanceState != null) {     if (savedInstanceState != null) {
-      ​String leftCount = savedInstanceState.getString("​leftCount"​); +      ​if (savedInstanceState.containsKey("​leftCount"​)) { 
-      if (leftCount != null) { +        leftEditText.setText(savedInstanceState.getString("​leftCount"));
-        leftEditText.setText(leftCount);​+
       } else {       } else {
         leftEditText.setText(String.valueOf(0));​         leftEditText.setText(String.valueOf(0));​
       }       }
-      ​String rightCount = savedInstanceState.getString("​rightCount"​); +      ​if (savedInstanceState.containsKey("​rightCount"​)) { 
-      if (rightCount != null) { +        rightEditText.setText(savedInstanceState.getString("​rightCount"));
-        rightEditText.setText(rightCount);​+
       } else {       } else {
         rightEditText.setText(String.valueOf(0));​         rightEditText.setText(String.valueOf(0));​
Line 305: Line 449:
   @Override   @Override
   protected void onSaveInstanceState(Bundle savedInstanceState) {   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("​leftCount",​ leftEditText.getText().toString());​
     savedInstanceState.putString("​rightCount",​ rightEditText.getText().toString());​     savedInstanceState.putString("​rightCount",​ rightEditText.getText().toString());​
 +  }
 +  ​
 +  @Override
 +  protected void onRestoreInstanceState(Bundle savedInstanceState) {
 +    if (savedInstanceState.containsKey("​leftCount"​)) {
 +      leftEditText.setText(savedInstanceState.getString("​leftCount"​));​
 +    } else {
 +      leftEditText.setText(String.valueOf(0));​
 +    }
 +    if (savedInstanceState.containsKey("​rightCount"​)) {
 +      rightEditText.setText(savedInstanceState.getString("​rightCount"​));​
 +    } else {
 +      rightEditText.setText(String.valueOf(0));​
 +    }
   }   }
   ​   ​
Line 317: Line 473:
 **c)** Pentru a simula faptul că sistemul de operare Android distruge activitatea pentru asigurarea necesarului de resurse, se poate proceda astfel: **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()'';​   - 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 }}+  - în Eclipse, se deschide Dalvik Debug Monitor System ​(DDMS), se identifică procesul corespunzător activății respective și se oprește forțat (prin intermediul butonului //​Stop//​);​\\ {{ :​colocvii:​colocviu01:​dalvik_debug_monitor_system.png?​nolink&​700 }} 
 +  - în Android Studio, în secțiunea //​AndroidMonitor//,​ se oprește aplicația Android prin intermediul butonului //Terminate Application//:​ \\ {{ :​colocvii:​colocviu01:​android_monitor.png?​nolink&​900 }}
   - se (re)pornește activitatea din meniul dispozitivului mobil, astfel încât să  se apeleze metodele ''​onCreate()'',​ respectiv ''​onStart()''​ și ''​onResume()''​ (și, implicit, ''​onRestoreInstanceState()''​).   - se (re)pornește activitatea din meniul dispozitivului mobil, astfel încât să  se apeleze metodele ''​onCreate()'',​ respectiv ''​onStart()''​ și ''​onResume()''​ (și, implicit, ''​onRestoreInstanceState()''​).
 +
 +<note tip>
 +În mediul integrat de dezvoltare Eclipse, DDMS (Dalvik Debug Monitor System) este pornit din //Window// → //Open Perspective//​ → //Other// → //DDMS//.
 +
 +În mediul integrat de dezvoltare Android Studio, AMS (Android Device Monitor) este pornit din //Tools// → //Android// → //Android Device Monitor//.
 +</​note>​
  
 **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. **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.
Line 329: Line 492:
   * 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.   * 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//​).+În mediul integrat de dezvoltare Eclipse, crearea ​acestor resurse este realizată în mod automat î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_activity01.png?​nolink&​500 }}
Line 338: Line 501:
  
 {{ :​colocvii:​colocviu01:​eclipse_activity04.png?​nolink&​500 }} {{ :​colocvii:​colocviu01:​eclipse_activity04.png?​nolink&​500 }}
 +
 +În mediul integrat de dezvoltare Android Studio, crearea acestor resurse este realizată în mod automat în momentul în care se solicită definirea unei resurse de tip //Android Activity// (//File// → //New// → //​Activity//​ → //Blank Activity//​).
 +
 +{{ :​colocvii:​colocviu01:​androidstudio_activity.png?​nolink&​600 }}
  
 **a)** În fișierul ''​AndroidManifest.xml''​ se specifică activitatea printr-o element de tip ''<​activity>''​ în cadrul etichetei ''<​application>''​ pentru care se definesc: **a)** În fișierul ''​AndroidManifest.xml''​ se specifică activitatea printr-o element de tip ''<​activity>''​ în cadrul etichetei ''<​application>''​ pentru care se definesc:
Line 355: Line 522:
       android:​label="​@string/​title_activity_practical_test01_secondary"​ >       android:​label="​@string/​title_activity_practical_test01_secondary"​ >
       <​intent-filter>​       <​intent-filter>​
-        <action android:​name="​ro.pub.cs.systems.pdsd.intent.action.PracticalTest01SecondaryActivity"​ />+        <action android:​name="​ro.pub.cs.systems.eim.intent.action.PracticalTest01SecondaryActivity"​ />
         <​category android:​name="​android.intent.category.DEFAULT"​ />         <​category android:​name="​android.intent.category.DEFAULT"​ />
       </​intent-filter>​       </​intent-filter>​
Line 371: Line 538:
   android:​layout_height="​match_parent"​   android:​layout_height="​match_parent"​
   android:​orientation="​vertical"​   android:​orientation="​vertical"​
-  tools:​context="​ro.pub.cs.systems.pdsd.practicaltest01.PracticalTest01SecondaryActivity"​ >+  tools:​context="​ro.pub.cs.systems.eim.practicaltest01.PracticalTest01SecondaryActivity"​ >
    
   <​TextView   <​TextView
Line 412: Line 579:
  
 <file java PracticalTest01SecondaryActivity.java>​ <file java PracticalTest01SecondaryActivity.java>​
-package ro.pub.cs.systems.pdsd.practicaltest01;​+package ro.pub.cs.systems.eim.practicaltest01;​
    
 import android.app.Activity;​ import android.app.Activity;​
Line 424: Line 591:
    
 public class PracticalTest01SecondaryActivity extends Activity { public class PracticalTest01SecondaryActivity extends Activity {
-     +  
 +  private TextView numberOfClicksTextView = null; 
 +  private Button okButton = null; 
 +  private Button cancelButton = null; 
 +
   private ButtonClickListener buttonClickListener = new ButtonClickListener();​   private ButtonClickListener buttonClickListener = new ButtonClickListener();​
-      +  ​private class ButtonClickListener implements ​View.OnClickListener {
-  ​private class ButtonClickListener implements ​Button.OnClickListener { +
-         +
     @Override     @Override
     public void onClick(View view) {     public void onClick(View view) {
       switch(view.getId()) {       switch(view.getId()) {
         case R.id.ok_button:​         case R.id.ok_button:​
-          setResult(RESULT_OK, ​new Intent());​ +          setResult(RESULT_OK, ​null);
-          finish();+
           break;           break;
         case R.id.cancel_button:​         case R.id.cancel_button:​
-          setResult(RESULT_CANCELED, ​new Intent());​ +          setResult(RESULT_CANCELED, ​null);
-          finish();+
           break;           break;
       }       }
 +      finish();
     }     }
-  }   +  } 
- +  
   @Override   @Override
   protected void onCreate(Bundle savedInstanceState) {   protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);​     super.onCreate(savedInstanceState);​
     setContentView(R.layout.activity_practical_test01_secondary);​     setContentView(R.layout.activity_practical_test01_secondary);​
-          
-    TextView numberOfClicksTextView = (TextView)findViewById(R.id.number_of_clicks_text_view);​ 
     ​     ​
 +    numberOfClicksTextView = (TextView)findViewById(R.id.number_of_clicks_text_view);​
     Intent intent = getIntent();​     Intent intent = getIntent();​
-    if (intent != null) { +    if (intent != null && intent.getExtras().containsKey("​numberOfClicks"​)) { 
-      ​String ​numberOfClicks = intent.getStringExtra("number_of_clicks"); +      ​int numberOfClicks = intent.getIntExtra("numberOfClicks", -1); 
-      ​if (numberOfClicks != null) { +      numberOfClicksTextView.setText(String.valueOf(numberOfClicks));​
-        ​numberOfClicksTextView.setText(getResources().getString(R.string.number_of_clicks).replace("???", ​numberOfClicks));​ +
-      }+
     }     }
-          +    ​ 
-    ​Button buttonOk ​= (Button)findViewById(R.id.ok_button);​ +    ​okButton ​= (Button)findViewById(R.id.ok_button);​ 
-    ​buttonOk.setOnClickListener(buttonClickListener);​ +    ​okButton.setOnClickListener(buttonClickListener);​ 
-    ​Button buttonCancel ​= (Button)findViewById(R.id.cancel_button);​ +    ​cancelButton ​= (Button)findViewById(R.id.cancel_button);​ 
-    ​buttonCancel.setOnClickListener(buttonClickListener); ​     +    ​cancelButton.setOnClickListener(buttonClickListener);​
   }   }
    
Line 491: Line 656:
   android:​layout_height="​wrap_content"​   android:​layout_height="​wrap_content"​
   android:​orientation="​vertical"​   android:​orientation="​vertical"​
-  tools:​context="​ro.pub.cs.systems.pdsd.practicaltest01.PracticalTest01MainActivity"​ >+  tools:​context="​ro.pub.cs.systems.eim.practicaltest01.PracticalTest01MainActivity"​ >
    
   <Button   <Button
Line 505: Line 670:
 </​code>​ </​code>​
  
-  ​- în codul sursă corespunzător clasei care gestionează activitatea respectivă:​+  ​* în codul sursă corespunzător clasei care gestionează activitatea respectivă:​
     - pe metoda ''​onCreate()'':​     - 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ă obțină o referință către controlul grafic prin intermediul căruia va fi lansată în execuție o altă activitate;
Line 524: Line 689:
            
   private final static int SECONDARY_ACTIVITY_REQUEST_CODE = 1;   private final static int SECONDARY_ACTIVITY_REQUEST_CODE = 1;
 +  ​
 +  private Button navigateToSecondaryActivityButton = null;
   ​   ​
   private ButtonClickListener buttonClickListener = new ButtonClickListener();​   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 rightEditText = (EditText)PracticalTest01MainActivity.this.findViewById(R.id.right_edit_text);​ 
       switch(view.getId()) {       switch(view.getId()) {
         case R.id.navigate_to_secondary_activity_button:​         case R.id.navigate_to_secondary_activity_button:​
-          Intent intent = new Intent("ro.pub.cs.systems.pdsd.intent.action.PracticalTest01SecondaryActivity"​); +          Intent intent = new Intent(getApplicationContext(),​ PracticalTest01SecondaryActivity.class); 
-          ​intent.putExtra("​number_of_clicks",​ +   int numberOfClicks = Integer.parseInt(leftEditText.getText().toString()) ​+  
-            String.valueOf( +                               ​Integer.parseInt(rightEditText.getText().toString()); 
-              ​Integer.parseInt(leftEditText.getText().toString()) +          ​intent.putExtra("​numberOfClicks",​ numberOfClicks);
-              ​+ ​Integer.parseInt(rightEditText.getText().toString()) +
-            ));+
           startActivityForResult(intent,​ SECONDARY_ACTIVITY_REQUEST_CODE);​           startActivityForResult(intent,​ SECONDARY_ACTIVITY_REQUEST_CODE);​
           break;           break;
Line 554: Line 716:
     // ...     // ...
                    
-    ​Button ​navigateToSecondaryActivityButton = (Button)findViewById(R.id.navigate_to_secondary_activity_button);​+    navigateToSecondaryActivityButton = (Button)findViewById(R.id.navigate_to_secondary_activity_button);​
     navigateToSecondaryActivityButton.setOnClickListener(buttonClickListener); ​         navigateToSecondaryActivityButton.setOnClickListener(buttonClickListener); ​    
   }   }
   ​   ​
   @Override   @Override
-  ​public ​void onActivityResult(int requestCode,​ int resultCode, Intent intent) { +  ​protected ​void onActivityResult(int requestCode,​ int resultCode, Intent intent) { 
-    Toast.makeText(this,​ "The activity returned with result "​+resultCode,​ Toast.LENGTH_LONG).show();​+    ​if (requestCode == SECONDARY_ACTIVITY_REQUEST_CODE) { 
 +      ​Toast.makeText(this,​ "The activity returned with result " + resultCode, Toast.LENGTH_LONG).show();​ 
 +    }
   }   }
   ​   ​
Line 568: Line 732:
 </​code>​ </​code>​
  
-**C.3.** Pentru încărcarea codului în contextul depozitului din cadrul contului Github personal:+**D.1.** **a)** Pentru a putea fi utilizat, serviciul trebuie să fie declarat în fișierul ''​AndroidManifest.xml''​. Este obligatoriu să se definească proprietatea ''​android:​name''​ care desemnează clasa care gestionează serviciul. 
 + 
 +Opțional, pot fi precizate și atributele:​ 
 +  * ''​android:​enabled'',​ care indică posibilitatea ca sistemul de operare Android să instanțieze serviciul;​ 
 +  * ''​android:​exported'',​ prin care se oferă posibilitatea ca serviciul să poată fi invocat și din contextul altei aplicații Android decât cea din care face parte acesta; 
 +  * ''​android:​permission'',​ care limitează posibilitatea ca serviciul respectiv să fie lansat în execuție exclusiv de componentele care dețin permisiunea specificată. 
 + 
 +<file xml AndroidManifest.xml>​ 
 +<?xml version="​1.0"​ encoding="​utf-8"?>​ 
 +<​manifest ... > 
 +  <​application ...> 
 +    <!-- other components --> 
 +    <service  
 +      android:​name="​ro.pub.cs.systems.eim.PracticalTest01Service"​ 
 +      android:​enabled="​true"​ 
 +      android:​exported="​false"​ /> 
 +  </​application>​ 
 +</​manifest>​ 
 +</​file>​ 
 + 
 +Clasa Java care gestionează serviciul trebuie să fie derivată din clasa ''​android.app.Service''​. 
 + 
 +Fiind un serviciu de tip started, trebuie supraîncărcate metodele de callback: 
 +  * ''​onStartCommand(intent,​ flags, id)'',​ apelat în mod automat în momentul în care componenta Android lansează serviciul în execuție printr-o invocare a metodei ''​startService()'';​ 
 +  * ''​onBind(intent)''​ care va furniza un rezultat ''​null'',​ întrucât nu este necesară o interfață prin care componenta Android să interacționeze cu serviciul. 
 + 
 +<file java PracticalTest01Service.java>​ 
 +import android.app.Service;​ 
 +import android.content.Intent;​ 
 +import android.os.IBinder;​ 
 + 
 +public class PracticalTest01Service extends Service { 
 + 
 +  private ProcessingThread processingThread = null; 
 + 
 +  @Override 
 +  public int onStartCommand(Intent intent, int flags, int startId) { 
 +    int firstNumber = intent.getIntExtra("​firstNumber",​ -1); 
 +    int secondNumber = intent.getIntExtra("​secondNumber",​ -1); 
 +    processingThread = new ProcessingThread(this,​ firstNumber,​ secondNumber);​ 
 +    processingThread.start();​ 
 +    return Service.START_REDELIVER_INTENT;​ 
 +  } 
 +   
 +  @Override 
 +  public IBinder onBind(Intent intent) { 
 +    return null; 
 +  } 
 +   
 +  @Override 
 +  public void onDestroy() { 
 +    processingThread.stopThread();​ 
 +  } 
 + 
 +} 
 +</​file>​ 
 + 
 +Întrucât procesarea realizată în cadrul serviciului ar ocupa timp de procesor, putând avea un impact asupra responsivității aplicației Android în privința interacțiunii cu utilizatorul,​ operațiile respective vor fi realizate pe un fir de execuție dedicat. Argumentele care vor fi transmise firului de execuție dedicat sunt **contextul**,​ întrucât pe baza acestuia se vor transmite intențiile cu difuzare, precum și cele două numere din cadrul interfeței grafice, transmise prin intermediul intenției, ca valori asociate cheilor ''​firstNumber'',​ respectiv ''​secondNumber''​. Valoarea pe care o furnizează metoda ''​onStartCommand()''​ este ''​Service.START_REDELIVER_INTENT'',​ ceea ce indică sistemului de operare Android faptul că serviciul trebuie repornit în situația în care este distrus pentru a se recupera resursele pe care acesta le utilizează,​ în caz de nevoie. De asemenea, va fi retransmisă și intenția utilizată pentru a invoca serviciul respectiv. 
 + 
 +<file java ProcessingThread.java>​ 
 +import java.util.Date;​ 
 +import java.util.Random;​ 
 + 
 +import android.content.Context;​ 
 +import android.content.Intent;​ 
 +import android.util.Log;​ 
 + 
 +public class ProcessingThread extends Thread { 
 + 
 +  private Context context = null; 
 +  private boolean isRunning = true; 
 +  
 +  private Random random = new Random(); 
 +  
 +  private double arithmeticMean;​ 
 +  private double geometricMean;​ 
 +  
 +  public ProcessingThread(Context context, int firstNumber,​ int secondNumber) { 
 +    this.context = context; 
 +     
 +    arithmeticMean = (firstNumber + secondNumber) / 2; 
 +    geometricMean = Math.sqrt(firstNumber * secondNumber);​ 
 +  } 
 +   
 +  @Override 
 +  public void run() { 
 +    Log.d("​[ProcessingThread]",​ "​Thread has started!"​);​ 
 +    while (isRunning) { 
 +      sendMessage();​ 
 +      sleep(); 
 +    } 
 +    Log.d("​[ProcessingThread]",​ "​Thread has stopped!"​);​ 
 +  } 
 +   
 +  private void sendMessage() { 
 +    Intent intent = new Intent(); 
 +    intent.setAction(Constants.actionTypes[random.nextInt(Constants.actionTypes.length)]);​ 
 +    intent.putExtra("​message",​ new Date(System.currentTimeMillis()) + " " + arithmeticMean + " " + geometricMean);​ 
 +    context.sendBroadcast(intent);​ 
 +  } 
 +   
 +  private void sleep() { 
 +    try { 
 +      Thread.sleep(10000);​ 
 +    } catch (InterruptedException interruptedException) { 
 +      interruptedException.printStackTrace();​ 
 +    } 
 +  } 
 + 
 +  public void stopThread() { 
 +    isRunning = false; 
 +  } 
 +} 
 +</​file>​ 
 + 
 +În contextul firului de execuție dedicat, se calculează inițial valorile necesare (media aritmetică și media geometrică). 
 + 
 +Rutina asociată firului de execuție implică următoarele operații:​ 
 +  - propagarea unei intenții cu difuzare la nivelul sistemului de operare Android; 
 +    - se creează un obiect de tip ''​Intent''​ care reprezintă intenția cu difuzare care va fi propagată;​ 
 +      - acțiunea asociată intenției este aleasă în mod aleator dintr-o colecție de tipuri de intenții definite de utilizator;​ 
 +      - informația conținută de intenția cu difuzare este plasată în câmpul ''​extra'',​ valoarea (șirul de caractere obținut prin concatenarea datei și orei curente cu media aritmetică și cu media geometrică) fiind asociată cheii ''​message'';​ 
 +    - se transmite intenția cu difuzare la nivelul sistemului de operare Android prin invocarea metodei ''​sendBroadcast()''​ (definită în clasa ''​Context''​);​ 
 +  - așteptarea unui interval de timp (10.000 ms) până la următoarea iterație, prin intermediul unui apel ''​Thread.sleep()''​. 
 +Trebuie implementată și o metodă pentru oprirea rulării firului de execuție în situația în care serviciul asociat este distrus. 
 + 
 +**b)** În clasa ''​PracticalTest01Acivity'',​ sunt plasate operațiile de pornire și de oprire a serviciului. 
 + 
 +Verificarea momentului în care trebuie pornit serviciul este realizată pe metoda ascultător a evenimentului de apăsare a unui buton. Se realizează suma dintre valorile conținute în cele două câmpuri text editabile și, în situația în care aceasta depășește pragul minim stabilit și dacă serviciul se găsește în starea oprit, atunci poate fi invocată metoda ''​startService()''​. Aceasta primește ca argument un obiect de tip ''​Intent''​ (explicit, instanțiat cu contextul și cu clasa aferentă serviciului) în care sunt plasate, în câmpul ''​extra'',​ valorile din câmpurile text editabile sub cheile ''​firstNumber''​ și ''​secondNumber''​. 
 + 
 +<code java> 
 +private class ButtonClickListener implements View.OnClickListener {  
 +  @Override 
 +  public void onClick(View view) { 
 +    int leftNumberOfClicks = Integer.parseInt(leftEditText.getText().toString());​ 
 +    int rightNumberOfClicks = Integer.parseInt(rightEditText.getText().toString());​ 
 + 
 +    // ... 
 +     
 +    if (leftNumberOfClicks + rightNumberOfClicks > Constants.NUMBER_OF_CLICKS_THRESHOLD 
 +        && serviceStatus == Constants.SERVICE_STOPPED) { 
 +      Intent intent = new Intent(getApplicationContext(),​ PracticalTest01Service.class);​ 
 +      intent.putExtra("​firstNumber",​ leftNumberOfClicks);​ 
 +      intent.putExtra("​secondNumber",​ rightNumberOfClicks);​ 
 +      getApplicationContext().startService(intent);​ 
 +      serviceStatus = Constants.SERVICE_STARTED;​ 
 +    } 
 +  } 
 +} 
 +</​code>​ 
 + 
 +Momentul la care este oprit serviciul coincide cu distrugerea activității,​ așadar pe metoda de callback ''​onDestroy()''​. Similar, această operație poate fi realizată și pe metoda de callback ''​onStop()''​. Metoda ''​stopService()''​ primește ca argument tot un obiect de tip ''​Intent''​ construit explicit, cu numele clasei care deservește serviciul. 
 + 
 +<code java> 
 +@Override 
 +protected void onDestroy() { 
 +  Intent intent = new Intent(this,​ PracticalTest01Service.class);​ 
 +  stopService(intent);​ 
 +  super.onDestroy();​ 
 +} 
 +</​code>​ 
 + 
 +Dacă serviciul este oprit, el va fi distrus de sistemul de operare Android (deși ''​stopService()''​ nu implică invocarea unei metode de callback la nivelul serviciului,​ totuși acesta va fi oprit și ulterior distrus). Pe metoda ''​onDestroy()''​ a serviciului,​ trebuie să se aibă grijă ca rutina din cadrul firului de execuție asociat să se termine. 
 + 
 +**D.2.** Un ascultător pentru intenții cu difuzare este o clasă derivată din ''​android.content.BroadcastReceiver''​. Acesta poate fi declarat în fișierul ''​AndroidManifest.xml'',​ dacă se dorește ca acesta să fie invocat în mod automat chiar dacă aplicația Android din care face parte nu este instanțiată sau poate fi înregistrat / deînregistrat pe metodele de callback ''​onResume()''​ / ''​onPause()''​ dacă se dorește ca funcționarea sa să fie limitată la perioada în care activitatea este disponibilă pe suprafața de afișare a dispozitivului mobil. 
 + 
 +În momentul în care o intenție cu difuzare are aceeași acțiune ca cea indicată în filtrul de intenții asociat ascultătorului respectiv, este apelată în mod automat metoda de callback ''​onReceive(context,​ intent)''​. Aceasta va fi responsabilă exclusiv cu jurnalizarea valorii asociate cheii ''​message''​ din câmpul ''​extra''​ asociat intenției cu difuzare respective. 
 + 
 +<code java> 
 +private MessageBroadcastReceiver messageBroadcastReceiver = new MessageBroadcastReceiver();​ 
 +private class MessageBroadcastReceiver extends BroadcastReceiver { 
 +  @Override 
 +  public void onReceive(Context context, Intent intent) { 
 +    Log.d("​[Message]",​ intent.getStringExtra("​message"​));​ 
 +  } 
 +} 
 +</​code>​ 
 + 
 +Un ascultător pentru intenții cu difuzare trebuie să aibă asociat și un filtru de intenții. Acesta conține acțiunile asociate intențiilor cu difuzare, pe care ascultătorul respectiv trebuie să le proceseze. 
 + 
 +<code java> 
 +public class PracticalTest01MainActivity extends Activity { 
 + 
 +  // ... 
 +   
 +  private IntentFilter intentFilter = new IntentFilter();​ 
 + 
 +  @Override 
 +  protected void onCreate(Bundle savedInstanceState) { 
 +    super.onCreate(savedInstanceState);​ 
 +    setContentView(R.layout.activity_practical_test01_main);​ 
 + 
 +    for (int index = 0; index < Constants.actionTypes.length;​ index++) { 
 +      intentFilter.addAction(Constants.actionTypes[index]);​ 
 +    } 
 +  } 
 +} 
 +</​code>​ 
 + 
 +Operațiile de activare, respectiv de dezactivare a ascultătorului pentru intenții cu difuzare, sunt realizate pe metodele de callback ale activității ''​onResume()'',​ respectiv ''​onPause()''​. În acest fel, se asigură faptul că ascultătorul pentru intenții cu difuzare nu va procesa decât mesajele transmise în perioada în care activitatea este afișată pe suprafața de afișare a dispozitivului mobil. 
 + 
 +<code java> 
 +public class PracticalTest01MainActivity extends Activity { 
 + 
 +  // ... 
 + 
 +  @Override 
 +  protected void onResume() { 
 +    super.onResume();​ 
 +    registerReceiver(messageBroadcastReceiver,​ intentFilter);​ 
 +  } 
 +   
 +  @Override 
 +  protected void onPause() { 
 +    unregisterReceiver(messageBroadcastReceiver);​ 
 +    super.onPause();​ 
 +  } 
 +} 
 +</​code>​ 
 + 
 +**D.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 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 consemnează modificările din zona de așteptare în directorul Git prin intermediul comenzii ''​git commit -m'',​ precizându-se și un mesaj sugestiv:
Line 576: Line 960:
  
 <​code>​ <​code>​
-student@pdsd2015:​~/​PracticalTest01$ git add * +student@eim2016:​~/​PracticalTest01$ git add * 
-student@pdsd2015:​~/​PracticalTest01$ git commit -m "​finished tasks for PracticalTest01"​ +student@eim2016:​~/​PracticalTest01$ git commit -m "​finished tasks for PracticalTest01"​ 
-student@pdsd2015:​~/​PracticalTest01$ git push origin master+student@eim2016:​~/​PracticalTest01$ git push origin master
 </​code>​ </​code>​
  
Line 584: Line 968:
  
 <​code>​ <​code>​
-student@pdsd2015:​~/​PracticalTest01$ git config --global user.name "​Perfect Student"​ +student@eim2016:​~/​PracticalTest01$ git config --global user.name "​Perfect Student"​ 
-student@pdsd2015:​~/​PracticalTest01$ git config --global user.email perfectstudent@cs.pub.ro+student@eim2016:​~/​PracticalTest01$ git config --global user.email perfectstudent@cs.pub.ro
 </​code>​ </​code>​
colocvii/colocviu01.1427561395.txt.gz · Last modified: 2017/02/20 20:42 (external edit)
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0