JavascriptProva

sabato 5 novembre 2016

Ripasso del delete di un record dal database, requery per refreshare la listView costruita con il CursorAdapter

Ripasso la cancellazione di un record di database.
Ho ripreso il codice di J-Communicator:
 public void cancella(String etichetta, String categoria){
  SQLiteDatabase db=this.getWritableDatabase();
  db.delete("tabella", "etichetta = '"+etichetta+"' and categoria='"+categoria+"'", null);
 }
Ecco: dopo la "rituale" apertura del database, si usa il metodo delete che prende come parametri la tabella e i criteri del record da cancellare, quindi il null che probabilmente è riferito a un array di strings.
Vediamo la documentazione...

int delete (String table, 
                String whereClause, 
                String[] whereArgs)
Sì, è la whereClause, ossia le clausole per il record da cancellare.


Ora provo ad aggiungere a bindView l'aggiunta di un listener al button.
Ho terminato tutto il lavoro su bindView, e mi devo concentrare un po' su di essa.
        @Override
        public void bindView(View view, Context context, Cursor cursor) {

            TextView textView=(TextView)view.findViewById(R.id.textView);
            final TextView textView2=(TextView)view.findViewById(R.id.textView2);
            Button button=(Button)view.findViewById(R.id.button2);
            textView.setText(cursor.getString(cursor.getColumnIndexOrThrow("voce")));
            textView2.setText(""+cursor.getInt(cursor.getColumnIndexOrThrow("_id")));
            button.setOnClickListener(new View.OnClickListener(){

                @Override
                public void onClick(View v) {
                    helper.cancella(Integer.parseInt(textView2.getText().toString()));
                    myCursorAdapter.getCursor().requery();
                }
            });
        }
L'aggiunta di un listener va per il meglio. Ho creato anche il codice che cancella un record in relazione all'id.
Ho avuto un po' di difficoltà per il refresh della listView, ma con il requery() ho risolto.

Ripasso del CursorAdapter per collegare una ListView a una tabella di database.

Il CursorAdapter avrebbe un metodo newView che non sarebbe altro che l'inflatazione del nuovo Layout, come ArrayAdapter.
La differenza potrebbe stare nel fatto che mentre nell'ArrayAdapter il metodo getView fa tutto lui, nel CursorAdapter la view viene inflatata da newView e poi in essa vengono messi i dati tramite bindView.
Vediamo un po' i parametri dei due metodi.

Sì, credo di essere in grado di provare...

Iniziamo estendendo CursorAdapter.
    class MyCursorAdapter extends CursorAdapter {

        Context context;
        public MyCursorAdapter(Context context, Cursor c) {
            super(context, c);
            this.context=context;
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            LayoutInflater layoutInflater=(LayoutInflater)context.getSystemService(LAYOUT_INFLATER_SERVICE);
            return layoutInflater.inflate(R.layout.row,null);
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {

            TextView textView=(TextView)view.findViewById(R.id.textView);
            Button button=(Button)view.findViewById(R.id.button2);
            textView.setText(cursor.getString(cursor.getColumnIndexOrThrow("voce")));
        }
    }
E l'ho sperimentato: ecco tutto il codice:
public class Lista extends AppCompatActivity {

    Helper helper;
    MyCursorAdapter myCursorAdapter;
    ListView listView;

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

        helper=new Helper(this);
        Cursor crs=helper.query();
        myCursorAdapter=new MyCursorAdapter(this,crs);
        listView=(ListView)findViewById(R.id.listView);
        listView.setAdapter(myCursorAdapter);





    }

    @Override
    protected void onStop(){
        super.onStop();

        Intent intent=new Intent(Lista.this,Lista.class);
        PendingIntent pendingIntent=PendingIntent.getActivity(getApplicationContext(),0,intent,0);
        AlarmManager alarmManager=(AlarmManager) getApplicationContext().getSystemService(ALARM_SERVICE);
        alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime()+5*1000,pendingIntent);

    }

    class MyCursorAdapter extends CursorAdapter {

        Context context;
        public MyCursorAdapter(Context context, Cursor c) {
            super(context, c);
            this.context=context;
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            LayoutInflater layoutInflater=(LayoutInflater)context.getSystemService(LAYOUT_INFLATER_SERVICE);
            return layoutInflater.inflate(R.layout.row,null);
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {

            TextView textView=(TextView)view.findViewById(R.id.textView);
            Button button=(Button)view.findViewById(R.id.button2);
            textView.setText(cursor.getString(cursor.getColumnIndexOrThrow("voce")));
        }
    }



}
Funziona perfettamente!

Aggiunta di eventi nel CustomAdapter

Ho modificato il CustomAdapter in modo da aggiungere un listener al button in ogni layout inflatato nella ListView.
    class CustomAdapter extends ArrayAdapter{

        Context context;
        int resource;
        ArrayList arrayList;
        public CustomAdapter(Context context, int resource, ArrayList objects) {
            super(context, resource, objects);
            this.context=context;
            this.resource=resource;
            this.arrayList=(ArrayList)objects;
        }

        @Override
        public View getView(int position,View convertView,ViewGroup group){
            LayoutInflater layoutInflater=(LayoutInflater)context.getSystemService(LAYOUT_INFLATER_SERVICE);
            convertView=layoutInflater.inflate(this.resource,null);
            final TextView textView=(TextView)convertView.findViewById(R.id.textView);
            Button button=(Button)convertView.findViewById(R.id.button2);
            textView.setText(arrayList.get(position).testoText);
            button.setText(arrayList.get(position).testoButton);
            button.setOnClickListener(new View.OnClickListener(){

                @Override
                public void onClick(View v) {
                    textView.setText("OKAY");
                }
            });
            return convertView;
        }
    }
Funziona.

Ripasso di CustomAdapter che estende ArrayAdapter

ArrayAdapter ha diversi tipi di costruttori. Mi sono rinfrescate le idee su cose viste, peraltro, anche abbastanza recentemente, ma che scordo con estrema facilità.
Ecco qui l'elenco delle firme dei costruttori:
Context, int
Context, int, int
Context, int, T[]
Context, int, int, T[]
Context, int, List
Context, int, int, List
In particolare, quello che ho usato prima è un costruttore a quattro parametri, precisamente l'ultimo in quanto ho usato una classe che eredita da List.
A quattro parametri posso usare anche il terzultimo, che invece di una classe di tipo List usa un semplice Array.
Poi si può usare a tre parametri, senza selezionare la view del layout.
La creazione di un CustomView estende ArrayAdapter e ne usa il costruttore a tre parametri context, layout e array, ossia il penultimo, Context, int, List
Provo a estendermi ArrayAdapter per crearmi un adapter personalizzato. Mi creo un tipo con due membri:
    class Tipo{
        public String testoText;
        public String testoButton;
    }
Di questo tipo creerò diverse istanze, che collocherò in un'arrayList.

Ora provo a estendere ArrayAdapter:
    class CustomAdapter extends ArrayAdapter{

        Context context;
        int resource;
        ArrayList<Tipo> arrayList;
        public CustomAdapter(Context context, int resource, ArrayList<Tipo> objects) {
            super(context, resource, objects);
            this.context=context;
            this.resource=resource;
            this.arrayList=(ArrayList)objects;
        }

        @Override
        public View getView(int position,View convertView,ViewGroup group){
            LayoutInflater layoutInflater=(LayoutInflater)context.getSystemService(LAYOUT_INFLATER_SERVICE);
            convertView=layoutInflater.inflate(this.resource,null);
            TextView textView=(TextView)convertView.findViewById(R.id.textView);
            Button button=(Button)convertView.findViewById(R.id.button2);
            textView.setText(arrayList.get(position).testoText);
            button.setText(arrayList.get(position).testoButton);
            return convertView;
        }
    } 
Creo diverse istanze di Tipo, le metto in un arrayList e do l'arrayList in pasto a una istanza di CustomAdapter.
        Tipo tipo=new Tipo();
        tipo.testoButton="Bottone";
        tipo.testoText="Testo";
        
        Tipo tipo1=new Tipo();
        tipo1.testoButton="Bottone secondo";
        tipo1.testoText="Testo secondo";
        
        Tipo tipo2=new Tipo();
        tipo2.testoButton="Altro bottone";
        tipo2.testoText="Altro testo";

        arrayList=new ArrayList<Tipo>();
        arrayList.add(tipo);
        arrayList.add(tipo1);
        arrayList.add(tipo2);

        customAdapter=new CustomAdapter(this,R.layout.row,arrayList);

        listView=(ListView) findViewById(R.id.listView);
        listView.setAdapter(customAdapter); 
Proviamo...



Sì, eccolo.

Nuovo ripasso dell'ArrayAdapter

Devo ripassare ancora ArrayAdapter.
Strano, ma non mi entra assolutamente in testa.

Risposta parziale:
Un ArrayAdapter usa un array di stringhe per porlo in una ListView.
Mi fabbrico un layout da inflatare con una TextView e un button.
Posso giocare a porre la stringa sia come testo della TextView sia come testo del button.
Vediamo se mi riesce...

A parte il context, l'adapter deve prendere come parametri il layout e la view specifica.
E da ultimo l'array da cui prendere gli elementi per metterli nella view specifica.
Ho realizzato un codice usando come view specifica sia la TextView sia il Button.
Con il primo codice:
public class Lista extends AppCompatActivity {

    ArrayAdapter arrayAdapter;
    ArrayList arrayList;
    ListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lista);

        arrayList=new ArrayList();
        arrayList.add("lunedi");
        arrayList.add("martedi");
        arrayList.add("mercoledi");

        arrayAdapter=new ArrayAdapter(this,R.layout.row,R.id.textView,arrayList);
        listView=(ListView) findViewById(R.id.listView);

        listView.setAdapter(arrayAdapter);
    }

...
Ho ottenuto questo:



Con questo codice, invece, che prende come view specifica il Button...
public class Lista extends AppCompatActivity {

    ArrayAdapter arrayAdapter;
    ArrayList arrayList;
    ListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lista);

        arrayList=new ArrayList();
        arrayList.add("lunedi");
        arrayList.add("martedi");
        arrayList.add("mercoledi");

        arrayAdapter=new ArrayAdapter(this,R.layout.row,R.id.button2,arrayList);
        listView=(ListView) findViewById(R.id.listView);

        listView.setAdapter(arrayAdapter);
    }

.....
ottengo questo:

mercoledì 2 novembre 2016

Prime esperienze di navigazione all'interno dell'emulatore con adb.

Un po' di adb e sintassi del Linux.
Vorrei strappare il database al cellulare non rootato, e forse mediante adb c'è modo di farlo.

Però devo imparare a usare adb.

Vediamo:
c:\Users\Antonello\AppData\Local\Android\sdk\platform-tools>adb devices
List of devices attached
emulator-5554   device


c:\Users\Antonello\AppData\Local\Android\sdk\platform-tools>
Ottengo un elenco dei dispositivi cui sono collegato. Al momento c'è solo l'emulatore. Ora attacco anche il cellulare.
c:\Users\Antonello\AppData\Local\Android\sdk\platform-tools>adb devices
List of devices attached
emulator-5554   device


c:\Users\Antonello\AppData\Local\Android\sdk\platform-tools>adb devices
List of devices attached
52036bacee7b833d        device
emulator-5554   device


c:\Users\Antonello\AppData\Local\Android\sdk\platform-tools>
Ecco prima e dopo aver attaccato il cellulare.
Vado sul cellulare
c:\Users\Antonello\AppData\Local\Android\sdk\platform-tools>adb -s 52036bacee7b833d shell
shell@a3xelte:/ $
Ora provo ad andare sull'emulatore:
c:\Users\Antonello\AppData\Local\Android\sdk\platform-tools>adb -s 52036bacee7b833d shell
shell@a3xelte:/ $ exit

c:\Users\Antonello\AppData\Local\Android\sdk\platform-tools>adb -s emulator-5554 shell
root@generic_x86_64:/ #
Sono uscito dal cellulare e sono entrato sull'emulatore.

Ora, dal momento che l'emulatore è rootato per definizione, posso aprirmi ADM (Android Device Monitor) e snavigazzare allegramente fra le directory dell'emulatore con i comandi Linux confrontando il mio percorso con il filesystem del dispositivo.

Tools->Android->Android Device Monitor

Eccolo.
Vediamo dove mi trovo...
Do il comando ls e ottengo:
127|root@generic_x86_64:/ # ls
acct
cache
charger
config
d
data
default.prop
dev
etc
file_contexts
fstab.goldfish
fstab.ranchu
init
init.environ.rc
init.goldfish.rc
init.ranchu.rc
init.rc
init.trace.rc
init.usb.rc
init.zygote32.rc
init.zygote64_32.rc
mnt
proc
property_contexts
root
sbin
sdcard
seapp_contexts
selinux_version
sepolicy
service_contexts
storage
sys
system
ueventd.goldfish.rc
ueventd.ranchu.rc
ueventd.rc
vendor
Confronto con un'immagine da ADM:



Ecco, praticamente sono qui.
Uso il comando pwd per vedere dove mi trovo:
root@generic_x86_64:/ # pwd
/
root@generic_x86_64:/ #
Sto praticamente nella directory radice. Prima avevo provato a fare qualcosa del genere con il cellulare e mi diceva che mi trovavo su sdcard... ma il cellulare non è rootato.

Ora voglio andare su sdcard. Come fare? Una mezza idea ce l'ho, vediamo se è giusta...
root@generic_x86_64:/ # cd ./sdcard/
root@generic_x86_64:/sdcard # ls
Alarms
Android
DCIM
Download
LOST.DIR
Movies
Music
Notifications
Pictures
Podcasts
Ringtones
root@generic_x86_64:/sdcard #
Confronto:



Ecco. C'è però un'anomalia.
Con ADM sdcard risulta vuota, e devo andare su storage/sdcard per ottenere l'accesso.
Lo desumo da questo:

...leggendo la dicitura a destra ->storage/sdcard.

E se provo ad andare su storage/sdcard con linux?
root@generic_x86_64:/ # cd ./storage/sdcard/
root@generic_x86_64:/storage/sdcard # ls
Alarms
Android
DCIM
Download
LOST.DIR
Movies
Music
Notifications
Pictures
Podcasts
Ringtones
root@generic_x86_64:/storage/sdcard
E' la stessa cosa.


Ora provo ad andare sulla directory del database di un'applicazione.
root@generic_x86_64:/ #
root@generic_x86_64:/ # ls
acct
cache
charger
config
d
data
default.prop
dev
etc
file_contexts
fstab.goldfish
fstab.ranchu
init
init.environ.rc
init.goldfish.rc
init.ranchu.rc
init.rc
init.trace.rc
init.usb.rc
init.zygote32.rc
init.zygote64_32.rc
mnt
proc
property_contexts
root
sbin
sdcard
seapp_contexts
selinux_version
sepolicy
service_contexts
storage
sys
system
ueventd.goldfish.rc
ueventd.ranchu.rc
ueventd.rc
vendor
root@generic_x86_64:/ #
Bene, vado in /data/:
root@generic_x86_64:/ # cd ./data/
root@generic_x86_64:/data # ls
adb
anr
app
app-asec
app-lib
app-private
backup
bugreports
dalvik-cache
data
dontpanic
drm
local
lost+found
media
mediadrm
misc
nativebenchmark
nativetest
nativetest64
property
resource-cache
security
system
tombstones
user
root@generic_x86_64:/data #
Vado nella seconda directory data e faccio la lista dei files contenuti:
root@generic_x86_64:/data # cd ./data/
127|root@generic_x86_64:/data/data # ls
com.android.backupconfirm
com.android.browser
com.android.calculator2
com.android.calendar
com.android.camera
com.android.captiveportallogin
com.android.certinstaller
com.android.contacts
com.android.customlocale2
com.android.defcontainer
com.android.deskclock
com.android.development
com.android.development_settings
com.android.dialer
com.android.documentsui
com.android.dreams.basic
com.android.email
com.android.emulator.smoketests
com.android.exchange
com.android.externalstorage
com.android.fallback
com.android.gallery
com.android.gesture.builder
com.android.htmlviewer
com.android.inputdevices
com.android.inputmethod.latin
com.android.keychain
com.android.location.fused
com.android.managedprovisioning
com.android.mms
com.android.mms.service
com.android.music
com.android.netspeed
com.android.packageinstaller
com.android.pacprocessor
com.android.phone
com.android.printspooler
com.android.protips
com.android.providers.calendar
com.android.providers.contacts
com.android.providers.downloads
com.android.providers.downloads.ui
com.android.providers.media
com.android.providers.settings
com.android.providers.telephony
com.android.providers.userdictionary
com.android.proxyhandler
com.android.sdksetup
com.android.server.telecom
com.android.settings
com.android.sharedstoragebackup
com.android.shell
com.android.smoketest
com.android.smoketest.tests
com.android.soundrecorder
com.android.speechrecorder
com.android.systemui
com.android.vending
com.android.vpndialogs
com.android.wallpaper.livepicker
com.android.webview
com.android.widgetpreview
com.example.android.apis
com.example.android.livecubes
com.example.android.softkeyboard
com.example.antonello.agendina
com.example.antonello.j_communicator
com.example.imagecom
com.google.android.apps.maps
com.google.android.gms
com.google.android.googlequicksearchbox
com.google.android.gsf
com.google.android.gsf.login
com.google.android.launcher
com.google.android.play.games
com.google.android.street
com.svox.pico
jp.co.omronsoft.openwnn
root@generic_x86_64:/data/data #
Praticamente vi sono elencati i packages.
Vado sul package che mi interessa:
root@generic_x86_64:/data/data # cd ./com.example.antonello.j_communicator/
root@generic_x86_64:/data/data/com.example.antonello.j_communicator # ls
cache
databases
lib
no_backup
shared_prefs
root@generic_x86_64:/data/data/com.example.antonello.j_communicator #
ecco la cartella dei database.
Ci vado.
1|root@generic_x86_64:/data/data/com.example.antonello.j_communicator #
cd ./databases/
root@generic_x86_64:/data/data/com.example.antonello.j_communicator/databases # ls
database.db
database.db-journal
root@generic_x86_64:/data/data/com.example.antonello.j_communicator/databases #
Ed ecco smascherato il mio file database.

E per il momento ci accontentiamo di questo.

martedì 1 novembre 2016

Gesture detection in previsione della nuova applicazione

E ora vediamo come si costruisce un GestureListener.
Vediamo dove posso recuperare la sintassi...

Quello che mi interessa è la classe GestureDetector.

Che costruttore ha la classe GestureDetector?
GestureDetector(Context context, GestureDetector.OnGestureListener listener)
Quindi si costruisce così:
private GestureDetector gestureDetector;

........

        gestureDetector = new GestureDetector(this, new GestureDetector.OnGestureListener(){

            @Override
            public boolean onDown(MotionEvent e) {
                return false;
            }

            @Override
            public void onShowPress(MotionEvent e) {

            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return false;
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                return false;
            }

            @Override
            public void onLongPress(MotionEvent e) {

            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                return false;
            }
        });
Adesso che ho istanziato GestureDetector, che faccio?
Vediamo se funziona, e come funziona.
Se do delle conseguenze a un gesto, risponderà?
Proviamo
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                System.out.println("ONSCROLL");
                return false;
            }
Ecco, risolto:
public class MainActivity extends AppCompatActivity {

    private ScrollView scrollView;

    private GestureDetector gestureDetector;

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

        gestureDetector = new GestureDetector(this, new GestureDetector.OnGestureListener(){

            @Override
            public boolean onDown(MotionEvent e) {
                return false;
            }

            @Override
            public void onShowPress(MotionEvent e) {

            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return false;
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

                return false;
            }

            @Override
            public void onLongPress(MotionEvent e) {

            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                System.out.println("ONFLING");
                scrollView.scrollBy(0,100);
                return true;
            }
        });

        scrollView=(ScrollView)findViewById(R.id.scrollView);


        scrollView.setOnTouchListener(new View.OnTouchListener(){

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                if(gestureDetector.onTouchEvent(event)) return gestureDetector.onTouchEvent(event);
                switch(event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        System.out.println("DOWN");
                        break;
                    case MotionEvent.ACTION_MOVE:
                        System.out.println("MOVE");
                        break;
                    case MotionEvent.ACTION_UP:
                        System.out.println("UP");
                        break;
                }

                return true;
            }
        });


    }

}