JavascriptProva

sabato 8 aprile 2017

Aggiunta ed eliminazione di una libreria aar da un progetto Android

Importazione di una libreria esterna (aar).
Intanto con New -> New Module ho modificato setting.gradle in questo modo:
include ':app', ':mylibrary-release'


e ho visto apparire il modulo mylibrary-release nella directory principale del mio progetto.

Quindi con New -> Import module, importo il modulo mylibrary che ora mi appare anch'esso nella directory.
Quindi devo risistemare il build.gradle di app aggiungendo l'ultima riga:
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
    compile project(":mylibrary")
}
Ora faccio la verifica: in questa libreria c'è una classe chiamata semplicemente Classe. Vedo se viene riconosciuta.
Ma prima devo sincronizzare Gradle!

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Classe classe=new Classe();
        classe.setNumero(123);
        System.out.println(classe.getNumero());

    }
}
Non ho ottenuto messaggi di errore. Ciò significa che la classe è stata riconosciuta.
Ora eseguo:
04-06 21:19:37.172 11679-11679/? I/System.out: 123


Perfetto!
Ora sarà più difficile togliere questa libreria, perché non so se ricordo bene la procedura...

Sono andato su File -> Project Structure e, andando su app, ho eliminato mylibrary.
Come risultato, build.gradle di app si è modificato con la sparizione della riga che avevo aggiunto a dependencies:
dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
}
Persiste nel setting.gradle questo:
include ':app', ':mylibrary-release', ':mylibrary'


Nel riquadro a sinistra permangono sia mylibrary sia mylibrary-release.

Torno su Project Structure ed elimino a sinistra sia library sia library-release...

Permangono nel riquadro a sinistra i due moduli, mentre setting.gradle si è modificato così:
include ':app'


Proviamo se il progetto "vuoto" gira normalmente...

Sembra di sì. Sia pure ancora in modo parzialmente empirico, sono riuscito ad eliminare la libreria aggiunta.

mercoledì 5 aprile 2017

Creazione di librerie in Android Studio

Ora provo passo passo a creare una libreria.

File -> New Module -> Android Library
Scelta del nome dell'applicazione e del nome del modulo.

Android Studio elabora...

E' apparsa la cartella mylibrary (nome scelto per il modulo).


Ora devo agire su Gradle.
Apro Settings.Gradle e mi appare questo:
include ':app', ':mylibrary'




Quindi apro build.gradle(Module app).
E mi appare questo:
apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.3"
    defaultConfig {
        applicationId "com.antonello.laboratoriolibrerie"
        minSdkVersion 18
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'
}
e vi devo aggiungere la riga:
....

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    testCompile 'junit:junit:4.12'

compile project (":mylibrary")
}
e quindi clicco Sync Now sulla barra di Gradle.
Bene, ora ho una libreria senza libri!
Provo ad eseguire...

Non succede nulla, ovviamente.
Ora provo a istanziare una fantomatica classe...
public class MainActivity extends AppCompatActivity {

    Classe classe;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        classe=new Classe();
    }
}
Ottengo messaggi di errore.

Quindi prendo mylibrary - java - com.antonello.mylibrary e ci aggiungo una classe chiamata Classe con il seguente codice:
public class Classe {
    private int numero;
    
    public void setNumero(int n){
        numero=n;
    }
    
    public int getNumero(){
        return numero;
    }
}
Ora torno su MainActivity e riprovo a istanziare la classe Classe:
public class MainActivity extends AppCompatActivity {
    
    Classe classe;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        classe = new Classe();
        classe.setNumero(246);
        System.out.println(classe.getNumero());
    }
}
Non ottengo messaggi di errore.
Eseguo:
04-05 21:59:26.757 9815-9815/? I/System.out: 246



Ecco, dopo vari problemi e distrazioni (mancanza di spazio sull'emulatore, collegamento erroneo del cellulare reale al computer...) alla fine la cosa è riuscita!

sabato 18 febbraio 2017

Esercizio di conversione di indirizzi di memoria in immagini, array di bytes e stringhe.

Ripasso tutte le conversioni di immagini.
  • Uri a Path
  • da Path a Bitmap
  • da Bitmap a byte array (salvabile come blob)
  • da Bitmap a byte array e quindi a stringa (salvabile come stringa e con possibilità di interazione con il database online.

Da Uri a Path:
public class MainActivity extends AppCompatActivity {

    Button button;
    ImageView imageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView=(ImageView)findViewById(R.id.imageView);
        button=(Button)findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                Intent intent=new Intent();
                intent.setData(Uri.parse("content://media/external/images/media"));
                intent.setAction(Intent.ACTION_PICK);
                startActivityForResult(intent,0);

            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
        if(resultCode==RESULT_OK){
            System.out.println(UriToPath(data.getData()));


        }
    }

    private String UriToPath(Uri uri){
        Cursor crs=getContentResolver().query(uri,null,null,null,null);
        crs.moveToFirst();
        int indice=crs.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
        String s =crs.getString(indice);
        return s;
    }
02-18 23:15:29.203 4670-4670/? I/System.out: /storage/sdcard/DCIM/facciadaculo.jpeg


Da Path a Bitmap:
public class MainActivity extends AppCompatActivity {

    Button button;
    ImageView imageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView=(ImageView)findViewById(R.id.imageView);
        button=(Button)findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                Intent intent=new Intent();
                intent.setData(Uri.parse("content://media/external/images/media"));
                intent.setAction(Intent.ACTION_PICK);
                startActivityForResult(intent,0);

            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
        if(resultCode==RESULT_OK){
            String s=UriToPath(data.getData());
            Bitmap b=PathToBitmap(s,300);
            imageView.setImageBitmap(b);


        }
    }

    private String UriToPath(Uri uri){
        Cursor crs=getContentResolver().query(uri,null,null,null,null);
        crs.moveToFirst();
        int indice=crs.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
        String s =crs.getString(indice);
        return s;
    }

    private Bitmap PathToBitmap(String path, int dimensioni){
        BitmapFactory.Options opzioni=new BitmapFactory.Options();
        opzioni.inJustDecodeBounds=true;
        BitmapFactory.decodeFile(path);
        int fattore=1;
        while(opzioni.outWidth/fattore>dimensioni && opzioni.outHeight/fattore>dimensioni){
            fattore*=2;
        }
        opzioni.inSampleSize=fattore;
        opzioni.inJustDecodeBounds=false;
        Bitmap bmp=BitmapFactory.decodeFile(path,opzioni);
        return bmp;
    }
}
E funziona anche questa.
Da Bitmap a byte array:
public class MainActivity extends AppCompatActivity {

    Button button;
    ImageView imageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView=(ImageView)findViewById(R.id.imageView);
        button=(Button)findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                Intent intent=new Intent();
                intent.setData(Uri.parse("content://media/external/images/media"));
                intent.setAction(Intent.ACTION_PICK);
                startActivityForResult(intent,0);

            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
        if(resultCode==RESULT_OK){
            String s=UriToPath(data.getData());
            Bitmap b=PathToBitmap(s,300);
            byte[] bt=BitmapToByteArray(b);
            System.out.println(bt);


        }
    }

    private String UriToPath(Uri uri){
        Cursor crs=getContentResolver().query(uri,null,null,null,null);
        crs.moveToFirst();
        int indice=crs.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
        String s =crs.getString(indice);
        return s;
    }

    private Bitmap PathToBitmap(String path, int dimensioni){
        BitmapFactory.Options opzioni=new BitmapFactory.Options();
        opzioni.inJustDecodeBounds=true;
        BitmapFactory.decodeFile(path);
        int fattore=1;
        while(opzioni.outWidth/fattore>dimensioni && opzioni.outHeight/fattore>dimensioni){
            fattore*=2;
        }
        opzioni.inSampleSize=fattore;
        opzioni.inJustDecodeBounds=false;
        Bitmap bmp=BitmapFactory.decodeFile(path,opzioni);
        return bmp;
    }

    private byte[] BitmapToByteArray(Bitmap bmp){
        ByteArrayOutputStream stream=new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG,80,stream);
        byte[] b=stream.toByteArray();
        return b;
    }


}
02-18 23:25:30.707 4855-4855/? I/System.out: [B@1a6afe00

(questa non la capisco... forse si tratta perlopiù di numeri non traducibili in caratteri)
Da bitmap a stringa:
public class MainActivity extends AppCompatActivity {

    Button button;
    ImageView imageView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageView=(ImageView)findViewById(R.id.imageView);
        button=(Button)findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View v) {
                Intent intent=new Intent();
                intent.setData(Uri.parse("content://media/external/images/media"));
                intent.setAction(Intent.ACTION_PICK);
                startActivityForResult(intent,0);

            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data){
        if(resultCode==RESULT_OK){
            String s=UriToPath(data.getData());
            Bitmap b=PathToBitmap(s,300);
            String stringa=BitmapToString(b);
            System.out.println(stringa);


        }
    }

    private String UriToPath(Uri uri){
        Cursor crs=getContentResolver().query(uri,null,null,null,null);
        crs.moveToFirst();
        int indice=crs.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
        String s =crs.getString(indice);
        return s;
    }

    private Bitmap PathToBitmap(String path, int dimensioni){
        BitmapFactory.Options opzioni=new BitmapFactory.Options();
        opzioni.inJustDecodeBounds=true;
        BitmapFactory.decodeFile(path);
        int fattore=1;
        while(opzioni.outWidth/fattore>dimensioni && opzioni.outHeight/fattore>dimensioni){
            fattore*=2;
        }
        opzioni.inSampleSize=fattore;
        opzioni.inJustDecodeBounds=false;
        Bitmap bmp=BitmapFactory.decodeFile(path,opzioni);
        return bmp;
    }

    private byte[] BitmapToByteArray(Bitmap bmp){
        ByteArrayOutputStream stream=new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG,80,stream);
        byte[] b=stream.toByteArray();
        return b;
    }
    private String BitmapToString(Bitmap bmp){
        ByteArrayOutputStream stream=new ByteArrayOutputStream();
        bmp.compress(Bitmap.CompressFormat.JPEG,80,stream);
        byte[] b=stream.toByteArray();
        String s= Base64.encodeToString(b,Base64.DEFAULT);
        return s;
    }


}
02-18 23:30:24.629 4970-4970/? I/System.out: /9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcU
02-18 23:30:24.629 4970-4970/? I/System.out: FhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgo
02-18 23:30:24.629 4970-4970/? I/System.out: KCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAFAAUADASIA
02-18 23:30:24.629 4970-4970/? I/System.out: AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
02-18 23:30:24.629 4970-4970/? I/System.out: AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3

.....

...che sarebbe una minima parte della stringa che rappresenterebbe la mia faccia.

giovedì 19 gennaio 2017

Salvataggio di date come Long in un database e rilevarne valori minimo e massimo.

Se io devo impostare una data, cosa mi conviene, usare Date o Calendar?
E come si fa?

Prima modalità:
        Date data1=new Date("5/09/1961");
        Date data2=new Date("13/06/1962");
        System.out.println(data1);
Ottengo:
01-19 00:48:04.397 28832-28832/? I/System.out: Tue May 09 00:00:00 GMT+00:00 1961
In questo modo (deprecato) bisogna ordinare mese e giorno secondo la notazione anglosassone, però.

Un'altra modalità sarebbe convertire la stringa in Date:
        Date data1=new Date();
        String strDat="5/9/1961";
        SimpleDateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");
        try {
            data1=sdf.parse(strDat);
            System.out.println(data1);
        } catch (ParseException e) {
            e.printStackTrace();
        }
01-19 00:58:48.387 31082-31082/? I/System.out: Tue Sep 05 00:00:00 GMT+00:00 1961
Queste modalità creano un tipo Date (ovviamente contenente una data) a partire da una data specifica, espressa come stringa.


Per riportare il tipo Date a stringa, si usa sempre SimpleDateFormat con l'istruzione format.

Ora metto diverse date in ordine sparso nel database e poi le ordino con ORDER BY.
Queste sono le date ordinate, ottenute creando tipi Date con la stringa della data come parametro nel costruttore, i quali vengono memorizzati mediante la funzione Date.getTime().
Vengono ripresi dal database creando un Date avente nel costruttore il Long.
        Date data1=new Date("09/05/1961");
        Date data2=new Date("01/10/2003");
        Date data3=new Date("06/13/1962");

        helper.save(data1.getTime());
        helper.save(data2.getTime());
        helper.save(data3.getTime());
,,,

            public void onClick(View v) {
                Cursor crs=helper.query();
                do {
                    System.out.println(new Date(crs.getLong(crs.getColumnIndex("millidat"))));
                }while(crs.moveToNext());
            }
Ora invece di Date uso Calendar:
        Calendar data1=Calendar.getInstance();
        data1.set(Calendar.YEAR,1961);
        data1.set(Calendar.MONTH,8);
        data1.set(Calendar.DAY_OF_MONTH,5);
        
Questo porta via molto tempo e codice: c'è un modo più facile di creare un Calendar impostando una data?
Sì, c'è:
        Calendar cal1=Calendar.getInstance();
        Calendar cal2=Calendar.getInstance();
        Calendar cal3=Calendar.getInstance();
        cal1.set(1961,8,5);
        cal2.set(2003,0,10);
        cal3.set(1962,5,13);

        helper.save(cal1.getTimeInMillis());
        helper.save(cal2.getTimeInMillis());
        helper.save(cal3.getTimeInMillis());

Salvati i dati nel database, ho trovato come estrapolarne il minimo e il massimo:
    public Cursor query(){
        SQLiteDatabase db=this.getWritableDatabase();
        Cursor c=db.rawQuery("select min(millidat) as millidat from tabella",null);
        c.moveToFirst();
        return c;
    }
    public Cursor query(){
        SQLiteDatabase db=this.getWritableDatabase();
        Cursor c=db.rawQuery("select max(millidat) as millidat from tabella",null);
        c.moveToFirst();
        return c;
    }

CalendarPickerView: parametri di init e range.

Questo datepicker prende due parametri di data.
Nominiamoli "primadata" e "secondadata" o qualcosa di simile.
Ora faccio che primadata è oggi, e secondadata è pure oggi.
Metto da parte il codice per l'evento di selezione delle date sul datePicker.
        pickerView.setOnDateSelectedListener(new CalendarPickerView.OnDateSelectedListener() {

            @Override
            public void onDateSelected(Date date) {
                ArrayList range = (ArrayList) pickerView.getSelectedDates();
            }

            @Override
            public void onDateUnselected(Date date) {

            }

        });


Ora cancello e procedo...
public class MainActivity extends AppCompatActivity {

    Calendar primaData;
    Calendar secondaData;


    CalendarPickerView pickerView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        pickerView = (CalendarPickerView) findViewById(R.id.calendar_view);

        primaData = Calendar.getInstance();
        secondaData=Calendar.getInstance();



        pickerView.init(primaData.getTime(), secondaData.getTime())
                .withSelectedDate(primaData.getTime())
                .inMode(CalendarPickerView.SelectionMode.RANGE);
    }
}
Errore perché la data selezionata deve essere fra la prima e l'ultima.
Provo ad aumentare la seconda di un giorno, ma non so come si fa.
Fatto, ora me l'accetta.
Ecco, quindi i due parametri di init definiscono il periodo in cui si può selezionare il range.
withSelectedDate esprime la data selezionata di base, che può anche mancare.

martedì 17 gennaio 2017

Regole per il parsing di y in SimpleDateFormat

Ho trovato un costruttore di SimpleDateFormat che non ha parametri. Forse per il parse, ossia la conversione di una stringa in tipo Date, è sufficiente questo costruttore. Sperimentiamo...

No.
E' necessario però imparare le regole, e ce ne sono sia per il parsing sia per il formatting.
PARSING: REGOLE PER YEAR:
Se le y sono fino a 2, l'anno viene interpretato come troncato delle prime due cifre: 61 viene inteso come '61 ovvero 1961;
Se le y sono più di 2, l'anno viene interpretato in senso letterale: 61 viene inteso come 61 dopo Cristo.
        String strData="5/9/61";
        Date dat;
        SimpleDateFormat sdf=new SimpleDateFormat("d/M/y");
        try {
            dat=sdf.parse(strData);
            System.out.println(dat);
        } catch (ParseException e) {
            System.out.println("errore");
        }
01-17 17:20:49.099 5729-5729/? I/System.out: Tue Sep 05 00:00:00 GMT+00:00 1961


        String strData="5/9/61";
        Date dat;
        SimpleDateFormat sdf=new SimpleDateFormat("d/M/yy");
        try {
            dat=sdf.parse(strData);
            System.out.println(dat);
        } catch (ParseException e) {
            System.out.println("errore");
        }
01-17 17:21:57.209 5812-5812/? I/System.out: Tue Sep 05 00:00:00 GMT+00:00 1961


        String strData="5/9/61";
        Date dat;
        SimpleDateFormat sdf=new SimpleDateFormat("d/M/yyy");
        try {
            dat=sdf.parse(strData);
            System.out.println(dat);
        } catch (ParseException e) {
            System.out.println("errore");
        }
01-17 17:38:03.107 5937-5937/? I/System.out: Sat Sep 05 00:00:00 GMT+00:00 61

Ripasso Date e SimpleDateFormat

Studio del Calendar.
Mi ricordo che avevo già avuto a che fare con le date e il Calendar. Vediamo di ritrovare i miei appunti. In fondo è per questo, fra l'altro, che tengo un blog.

Link di riferimento
La base di tutto è il SimpleDateFormat.
Se ricordo bene, si crea una variabile di tipo SimpleDateFormat, che si istanzia come?
Semplicemente con new SimpleDateFormat avente per parametro una stringa con il formato in formato stringa.
Ci proviamo.

Scrivo una data in formato stringa, quindi creo un SimpleDateFormat, quindi vedrò come convertirlo in oggetto tipo Date.
        String strData="5/9/1961";
        
        SimpleDateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");
Si converte con il metodo parse di SimpleDateFormat.
        String strData="5/9/1961";

        SimpleDateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");

        try {
            Date dat=sdf.parse(strData);
            System.out.println(dat);
        } catch (ParseException e) {
            e.printStackTrace();
        }
E così funziona:
01-17 16:45:44.392 4692-4692/? I/System.out: Tue Sep 05 00:00:00 GMT+00:00 1961
Quindi è parse. Ho qualche perplessità sul parametro di SimpleDateFormat, che vedrò dopo per evitare di impelagarmi.
Vediamo l'operazione inversa, che si dovrebbe fare con format.
Mi predispongo un tipo Date ben individuato. Quindi lo converto in stringa mediante format.
        Date dat=new Date();
        String strDate;

        SimpleDateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");
        strDate=sdf.format(dat);
        System.out.println(strDate);
E funziona:
01-17 16:57:59.640 4841-4841/? I/System.out: 17/01/2017