Servizi in Android

Le basi
Per creare un servizio, devi creare una sottoclasse di Service o utilizzare una delle sue sottoclassi esistenti. Nella tua implementazione, devi sovrascrivere alcuni metodi di callback che gestiscono aspetti chiave del ciclo di vita del servizio e fornire un meccanismo che consenta ai componenti di associarsi al servizio, se appropriato. Questi sono i metodi di callback più importanti che dovresti sovrascrivere:

onStartCommand()
Il sistema richiama questo metodo chiamando startService() quando un altro componente (come un’attività) richiede l’avvio del servizio. Quando questo metodo viene eseguito, il servizio viene avviato e può essere eseguito in background a tempo indeterminato. Se lo implementi, è tua responsabilità interrompere il servizio quando il suo lavoro è completo chiamando stopSelf() o stopService(). Se si desidera fornire solo l’associazione, non è necessario implementare questo metodo.

onBind()
Il sistema richiama questo metodo chiamando bindService() quando un altro componente desidera eseguire il binding con il servizio (ad esempio per eseguire RPC). Nell’implementazione di questo metodo, devi fornire un’interfaccia che i client utilizzano per comunicare con il servizio restituendo un IBinder. Devi sempre implementare questo metodo; tuttavia, se non si desidera consentire l’associazione, è necessario restituire null.

onCreate()
Il sistema richiama questo metodo per eseguire procedure di installazione una tantum quando il servizio viene creato inizialmente (prima di chiamare onStartCommand() o onBind()). Se il servizio è già in esecuzione, questo metodo non viene chiamato.

onDestroy()
Il sistema richiama questo metodo quando il servizio non viene più utilizzato e viene distrutto. Il tuo servizio dovrebbe implementarlo per ripulire tutte le risorse come thread, listener registrati o ricevitori. Questa è l’ultima chiamata ricevuta dal servizio.”

Esempio di servizio in Android :

public class HelloService extends Service {
  private Looper serviceLooper;
  private ServiceHandler serviceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              // Restore interrupt status.
              Thread.currentThread().interrupt();
          }
          // Stop the service using the startId, so that we don't stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service. Note that we create a
    // separate thread because the service normally runs in the process's
    // main thread, which we don't want to block. We also make it
    // background priority so CPU-intensive work doesn't disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread's Looper and use it for our Handler
    serviceLooper = thread.getLooper();
    serviceHandler = new ServiceHandler(serviceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we're stopping when we finish the job
      Message msg = serviceHandler.obtainMessage();
      msg.arg1 = startId;
      serviceHandler.sendMessage(msg);

      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don't provide binding, so return null
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

Articolo completo :
https://developer.android.com/guide/components/services#java

Socket in Android

Una App android, come tutte le App ed i programmi, può accedere alle porte di comunicazione della rete a cui è connesso il dispositivo.
Le porte sono un oggetto molto importante per tutti i dispositivi connessi in rete di cui è bene avere una conoscenza minima.
Basti dire che chiunque voglia collegarsi al vostro dispositivo, anche a vostra insaputa, lo deve fare attraverso le porte (Socket).

Il flusso dei dati nelle comunicazioni attraverso web avviene solo ed esclusivamente tramite le porte attraverso il protocolli TCPIP/UDP, inizialmente ideati per scopi esclusivamente militari. Dal vostro dispositivo, (PC/TABLET/SMARTPHONE…), il flusso attraverso una porta passa per il vostro modem/router, fornito e gestito dal vostro provider internet, e via via raggiunge la destinazione. Ogni punto della rete che il vostro flusso incontra, deve fare i conti con la politica di gestione delle porte di quel punto…

Per fare un esempio, il protocollo http, (quello che utilizzate per navigare), viaggia sulla porta 80, se non diversamente specificato.

Di seguito vi fornisco il link alla documentazione della classe Android Socket :
Documentazione Classe Socket

Concetto di Attività in Android

“Un’attività fornisce la finestra in cui l’app disegna la sua interfaccia utente. Questa finestra in genere riempie lo schermo, ma può essere più piccola dello schermo e fluttuare sopra altre finestre. In genere, un’attività implementa una schermata in un’app. Ad esempio, una delle attività di un’app può implementare una schermata Preferenze, mentre un’altra attività implementa una schermata Seleziona foto.

La maggior parte delle app contiene più schermi, il che significa che comprendono più attività. In genere, un’attività in un’app viene specificata come attività principale, ovvero la prima schermata visualizzata quando l’utente avvia l’app. Ogni attività può quindi avviare un’altra attività per eseguire azioni diverse. Ad esempio, l’attività principale in una semplice app di posta elettronica può fornire la schermata che mostra una casella di posta in arrivo. Da lì, l’attività principale potrebbe avviare altre attività che forniscono schermate per attività come la scrittura di e-mail e l’apertura di singole e-mail.

Sebbene le attività lavorino insieme per formare un’esperienza utente coesa in un’app, ogni attività è solo vagamente legata alle altre attività; in genere ci sono dipendenze minime tra le attività in un’app. In effetti, le attività spesso avviano attività appartenenti ad altre app. Ad esempio, un’app browser potrebbe avviare l’attività Condividi di un’app di social media.

Per utilizzare le attività nella tua app, devi registrare le informazioni su di esse nel manifest dell’app e devi gestire i cicli di vita delle attività in modo appropriato. Il resto di questo documento introduce questi argomenti.”

from developer.android.com, articolo completo : Activities
per iniziare : Android Documentation

I puntatori

Nel c/c++ esiste una entità nota come puntatore. Il puntatore è una peculiarità del linguaggio c/c++ che lo rende molto potente (e pericoloso…).

Per esempio, l’istruzione :

a = 10;

assegna il valore 10 alla variabile a. Ma che cosa è una variabile ? Nient’altro che una cella della vostra memoria di lavoro (RAM).

Per prelevare l’indirizzo di questa cella di memoria utilizziamo l’operatore & (address). In questo modo la seguente istruzione :

pointer = &a;

non farà altro che assegnare alla variabile pointer l’indirizzo in memoria della variabile a.

In questo modo le ultime due istruzioni seguenti sono del tutto equivalenti.

int a;
int *pointer;

pointer=&a;

a = 5;
*pointer = 5;

Infatti entrambe le istruzioni assegnano alla variabile a il valore 5.

Esempio:

int a;
int *pointer;

pointer=&a;

*pointer = 5;

*pointer = *pointer + a;
// Dopo questa istruzione a vale 10

Andrew’s genetic algorithm

In questo articolo vi presento un possibile algoritmo genetico da me implementato in C++ per questioni di velocità di calcolo (e non solo…).

L’algoritmo è molto semplice e compatto, ma vi assicuro che funziona benissimo! Come esempio di problema da risolvere ho adottato il subset sum problem.

//==========================================================================
// Name        : aga.cpp
// Author      : Andrea Bianchini (2021)
// Version     : 1.0.0
// Copyright   : SOME RIGHT RESERVED CREATIVE COMMONS BY 4.0
// License     : https://creativecommons.org/licenses/by/4.0/
// Description : AGA - Andrew's Genetic Algorithm
// Use         : AGA p = AGA(PSIZE,ISIZE,RMIN,RMAX,IMAX,PCROSS,PMUT);
//             : p.evolve();
// Where       : PSIZE = Population size (number of individuals)
//             : ISIZE = Individual size (number of variables)
//             : RMIN  = Individual variables min value
//             : RMAX  = Individual variables max value
//             : IMAX  = Max number of iteration
//             : PCROSS= Crossover probability
//             : PMUT  = Mutation probability
// Example     : AGA p = AGA(500,20,0,1,10,0.5,0.3);
//             : p.evolve();
//             :
//             : Personalize your objective into evalIndividual().
//             : This file is personalized to solve subset sum problem.
//==========================================================================
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <math.h>
#include <time.h>


class AGA
{
protected:
	int POP_SIZE = 500;
	int IND_SIZE = 20;
	int RANGE_MIN = 0;
	int RANGE_MAX = 1;
	int MAXITER = 10;
	float PCROSS = 0.5;
	float PMUT = 0.3;
	int **pop;
	int first=1;
	int solfound;
	int niter;

public:
	int *w;
	int *bestIndividual;
	int c = 400;

	void initSSP()
	{
		w=new int [IND_SIZE];
		for(int i=0;i<IND_SIZE;i++)
		w[i]=c*0.1+(int)(rand()%(int)(c*0.3-c*0.1+1));

	}
	AGA(int pops, int inds, int rmin, int rmax, int maxiter, float pcross, float pmute)
		{
			solfound=0;
			niter=0;
			first=1;
			POP_SIZE=pops;
			IND_SIZE=inds;
			RANGE_MIN=rmin;
			RANGE_MAX=rmax;
			MAXITER = maxiter;
			PCROSS = pcross;
			PMUT = pmute;
			pop = new int* [POP_SIZE];
			int i;
			for(i=0;i<POP_SIZE;i++)
			{
				pop[i] = new int [IND_SIZE+1]; // +1 for fit
				pop[i][IND_SIZE]=0;
			}
			bestIndividual=new int [IND_SIZE+1];
			bestIndividual[IND_SIZE]=0;
			initSSP();
		}

	~AGA()
	{
		for(int i=0;i<POP_SIZE;i++)
			delete[] pop[i];
		delete[] pop;
		delete[] bestIndividual;
		delete[] w;
	}

	int * individual(int i)
	{
		return pop[i];
	}

	void populate()
	{
		int ind;
		for(ind=0;ind<POP_SIZE-1;ind++)
			for(int k=ind+1;k<POP_SIZE;k++)
				if (abs(individual(ind)[IND_SIZE]-c)>abs(individual(k)[IND_SIZE]-c))
				{
					int *p=individual(ind);
					pop[ind]=pop[k];
					pop[k]=p;
				}
		//..........
		if (first==1)
		{
			for(ind=0;ind<POP_SIZE;ind++)
			{
				int *in;
				in = individual(ind);
				for(int j=0;j<IND_SIZE;j++)
				{
					in[j] = rndInRange();
				}
				in[IND_SIZE]=0; // fit
			}
			first=0;
		}
		else
		{
			int p2=POP_SIZE*PCROSS+1;
			int p1=0;
			while(p2<POP_SIZE && p1<POP_SIZE*PCROSS+1)
			{
				Cross(p1,p2);
				if (p2<POP_SIZE*PMUT)
					Mutate(p2);
				p1++;
				p2++;
			}
			while (p2<POP_SIZE)
			{
				int *in;
				in = individual(p2);
				for(int j=0;j<IND_SIZE;j++)
				{
					in[j] = rndInRange();
				}
				in[IND_SIZE]=0; // fit
				p2++;
			}
		}
	}

	void Cross(int p1, int p2)
	{
		int *c1,*c2,*c3;

		c1=individual(p1);
		c2=individual(p1+1);
		c3=individual(p2);

		for(int i=0;i<IND_SIZE/2;i++)
		{
			c3[i]=c1[i];
		}
		for(int i=IND_SIZE/2;i<IND_SIZE;i++)
		{
			c3[i]=c2[i];
		}
		c3[IND_SIZE]=0;
	}

	void Mutate(int p2)
	{
		int c = rand() % IND_SIZE;
		int *d=individual(p2);
		d[c] = rndInRange();
	}

	int rndInRange()
	{
		int a = RANGE_MIN+(int)(rand()%(RANGE_MAX-RANGE_MIN+1));
		if (a>RANGE_MAX)
			a=RANGE_MAX;
		//printf("%d\n\r",a);
		return a;
	}

	void evalPopulation()
	{
		for(int i=0;i<POP_SIZE;i++)
		{
			evalIndividual(i);
		}

	}

	void evalIndividual(int i)
	{
		int z=0;
		int *p = individual(i);
		for(int j=0;j<IND_SIZE;j++)
			z+=w[j]*p[j];
		//if (z<c)
			p[IND_SIZE]=z;
		//else
			//p[IND_SIZE]=0;
		if (z<=c && z>bestIndividual[IND_SIZE])
		{
			for(int j=0;j<IND_SIZE;j++)
				bestIndividual[j]=p[j];
			bestIndividual[IND_SIZE]=z;
			printf("Best Fit=%d\r",z);
			if (z==c)
			{
				solfound=1;
				printf("Optimal Solution z=%d found!\r",z);
			}
		}
	
	}
	
	void evolve()
	{
		niter=0;
		while(niter<MAXITER && solfound==0)
		{
			printf("--------------------\rGenerazione n.%d\r",niter);
			populate();
			evalPopulation();
			int ind;
			int tot=0;
			for(ind=0;ind<POP_SIZE-1;ind++)
			{
				tot+=individual(ind)[IND_SIZE];
				for(int k=ind+1;k<POP_SIZE;k++)
					if (individual(ind)[IND_SIZE]<individual(k)[IND_SIZE])
					{
						int *p=individual(ind);
						pop[ind]=pop[k];
						pop[k]=p;
					}
			}
			tot+=individual(POP_SIZE-1)[IND_SIZE];
			tot/=POP_SIZE;
			printf("MAX=%d   AVG=%d   MIN=%d\r",pop[0][IND_SIZE],tot,pop[POP_SIZE-1][IND_SIZE]);
			niter++;
		}
	}
};

int main() {
	int POP_SIZE=500;
	int IND_SIZE=20;
	int RANGE_MIN=0;
	int RANGE_MAX=1;
	int MAXITER = 10;
	float PCROSS = 0.5;
	float PMUT = 0.3;

	AGA p = AGA(POP_SIZE,IND_SIZE,RANGE_MIN,RANGE_MAX,MAXITER,PCROSS,PMUT);
	p.c=600;
	p.initSSP();
	clock_t tStart = clock();
	p.evolve();
	printf("\rTempo di esecuzione: %.4fs\r", (double)(clock() - tStart)/CLOCKS_PER_SEC);

	printf("\r---------------\rSoluzione: %d\r",p.bestIndividual[IND_SIZE]);
	printf("Items:\r[");
	for(int i=0;i<IND_SIZE;i++)
		printf("%d ",p.w[i]);
	printf("]\r");
	printf("Items soluzione:\r[");
	for(int i=0;i<IND_SIZE;i++)
		printf("%d ",p.w[i]*p.bestIndividual[i]);
	printf("]\r");
	return 0;
}

Esempio di output:

--------------------
Generazione n.0
Best Fit=524
Best Fit=548
Best Fit=579
MAX=1833   AVG=382   MIN=339
--------------------
Generazione n.1
Best Fit=593
MAX=1689   AVG=333   MIN=283
--------------------
Generazione n.2
Best Fit=598
MAX=1189   AVG=351   MIN=283
--------------------
Generazione n.3
Best Fit=600
Optimal Solution z=600 found!
MAX=1189   AVG=406   MIN=203

Tempo di esecuzione: 0.0267s

---------------
Soluzione: 600
Items:
[92 123 109 82 174 110 148 147 96 136 169 67 114 129 100 124 122 101 62 81 ]
Items soluzione:
[92 0 0 0 0 0 0 0 0 136 0 67 0 0 100 124 0 0 0 81 ]

Lettura del flusso MIDI di uno strumento

# mido_test.py
#
# Questo programma dimostra l'utilizzo della libreria MIDO 
# per la gestione dei dispositivi MIDI.
# In particolare, questo programma cattura e stampa il flusso midi
# prodotto da una tastiera elettronica.
# Dopo aver selezionato il dispositivo tra quelli disponibili,
# viene effettuato un ciclo di lettura continua sino all'interruzione
# tramite tasto CTRL-C.
#
# by Andrea Bianchini (2021)
#


import mido

o=mido.get_output_names()

for i in range(len(o)):
    print(str(i)+"-"+o[i])

print()
k=int(input("Seleziona il numero corrispondente al dispositivo di interesse:"))
print()

port = mido.open_input(o[k])

try:
    while True:
        for msg in port.iter_pending():
            if  msg.type!="clock":
                print(msg)
except KeyboardInterrupt:
    print("Interrupted by user")

port.close()

Esempio:

0-Midi Through:Midi Through Port-0 14:0
1-Digital Keyboard:Digital Keyboard MIDI 1 20:0
2-Midi Through:Midi Through Port-0 14:0
3-Digital Keyboard:Digital Keyboard MIDI 1 20:0

Seleziona il numero corrispondente al dispositivo di interesse:1

start time=0
control_change channel=3 control=120 value=0 time=0
control_change channel=7 control=120 value=0 time=0
control_change channel=5 control=120 value=0 time=0
control_change channel=3 control=7 value=122 time=0
note_on channel=3 note=67 velocity=40 time=0
note_on channel=3 note=48 velocity=39 time=0
note_on channel=3 note=69 velocity=48 time=0
note_off channel=3 note=67 velocity=0 time=0
note_on channel=3 note=59 velocity=45 time=0
note_off channel=3 note=59 velocity=0 time=0
note_on channel=3 note=55 velocity=42 time=0
note_off channel=3 note=69 velocity=0 time=0
note_off channel=3 note=48 velocity=0 time=0
note_on channel=3 note=67 velocity=33 time=0
note_off channel=3 note=67 velocity=0 time=0
note_off channel=3 note=55 velocity=0 time=0
note_on channel=3 note=65 velocity=34 time=0
note_on channel=3 note=53 velocity=39 time=0
note_on channel=3 note=63 velocity=35 time=0
note_off channel=3 note=65 velocity=0 time=0
note_on channel=3 note=52 velocity=50 time=0
note_off channel=3 note=53 velocity=0 time=0
note_off channel=3 note=63 velocity=0 time=0
note_on channel=3 note=62 velocity=42 time=0
note_off channel=3 note=52 velocity=0 time=0
note_off channel=3 note=62 velocity=0 time=0
note_on channel=3 note=53 velocity=41 time=0
note_on channel=3 note=64 velocity=49 time=0

Semplice Sinth MIDI

MidiSinthDeviceService.java

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.midisynth;

import android.media.midi.MidiDeviceService;
import android.media.midi.MidiDeviceStatus;
import android.media.midi.MidiReceiver;

import com.example.android.common.midi.synth.SynthEngine;

public class MidiSynthDeviceService extends MidiDeviceService {

    private SynthEngine mSynthEngine = new SynthEngine();
    private boolean mSynthStarted = false;

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        mSynthEngine.stop();
        super.onDestroy();
    }

    @Override
    public MidiReceiver[] onGetInputPortReceivers() {
        return new MidiReceiver[]{mSynthEngine};
    }

    /**
     * This will get called when clients connect or disconnect.
     */
    @Override
    public void onDeviceStatusChanged(MidiDeviceStatus status) {
        if (status.isInputPortOpen(0) && !mSynthStarted) {
            mSynthEngine.start();
            mSynthStarted = true;
        } else if (!status.isInputPortOpen(0) && mSynthStarted) {
            mSynthEngine.stop();
            mSynthStarted = false;
        }
    }

}

MainActivity.java

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.midisynth;

import android.content.pm.PackageManager;
import android.media.midi.MidiDevice.MidiConnection;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiManager;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.Toast;

import com.example.android.common.midi.MidiOutputPortConnectionSelector;
import com.example.android.common.midi.MidiPortConnector;
import com.example.android.common.midi.MidiTools;

/**
 * Simple synthesizer as a MIDI Device.
 */
public class MainActivity extends AppCompatActivity {

    private MidiOutputPortConnectionSelector mPortSelector;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayShowTitleEnabled(false);
        }

        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_MIDI)) {
            setupMidi();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        setKeepScreenOn(menu.findItem(R.id.action_keep_screen_on).isChecked());
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_keep_screen_on:
                boolean checked = !item.isChecked();
                setKeepScreenOn(checked);
                item.setChecked(checked);
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    private void setKeepScreenOn(boolean keepScreenOn) {
        if (keepScreenOn) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        } else {
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        }
    }

    private void setupMidi() {
        // Setup MIDI
        MidiManager midiManager = (MidiManager) getSystemService(MIDI_SERVICE);

        MidiDeviceInfo synthInfo = MidiTools.findDevice(midiManager, "AndroidTest",
                "SynthExample");
        int portIndex = 0;
        mPortSelector = new MidiOutputPortConnectionSelector(midiManager, this,
                R.id.spinner_synth_sender, synthInfo, portIndex);
        mPortSelector.setConnectedListener(new MyPortsConnectedListener());
    }

    private void closeSynthResources() {
        if (mPortSelector != null) {
            mPortSelector.close();
        }
    }

    // TODO A better way would be to listen to the synth server
    // for open/close events and then disable/enable the spinner.
    private class MyPortsConnectedListener
            implements MidiPortConnector.OnPortsConnectedListener {
        @Override
        public void onPortsConnected(final MidiConnection connection) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (connection == null) {
                        Toast.makeText(MainActivity.this,
                                R.string.error_port_busy, Toast.LENGTH_SHORT)
                                .show();
                        mPortSelector.clearSelection();
                    } else {
                        Toast.makeText(MainActivity.this,
                                R.string.port_open_ok, Toast.LENGTH_SHORT)
                                .show();
                    }
                }
            });
        }
    }

    @Override
    public void onDestroy() {
        closeSynthResources();
        super.onDestroy();
    }

}

profMI

# profMI.py
#
# 
# Il professor MII insegna in una classe universitaria formata da
# ragazzi e ragazze. Viene fornita una lista contenente una lista 
# per ogni studente. Il primo numero della lista è l'idendificativo
# dello studente, il secondo numero della lista rappresenta il sesso;
# (0=MASCHIO,1=FEMMINA,2=LGBT). I restanti numeri indicano i voti
# conseguiti per quello studente.
# Il programma determina la media dei voti per genere sessuale.
#
# by Andrea Bianchini (2021)

from random import randint

N = 50
MIN = 18
MAX = 31
NVOTI = 5

#generazione casuale lista dei voti:
cl=[]
for i in range(N):
    student=[]
    student.append(i)
    student.append(randint(0,2))
    for j in range(NVOTI):
        student.append(randint(MIN,MAX))
    cl.append(student)
                   
#calcolo
mediatot=[0.0,0.0,0.0]
ng=[0,0,0]
for i in range(N):
    medias=[0.0,0.0,0.0]
    student=cl[i]
    sex = student[1]
    ng[sex]+=1
    for j in range(NVOTI):
        medias[sex]+=float(student[2+j])
    medias[sex]/=float(NVOTI)
    mediatot[sex]+=medias[sex]

mediatot[0]/=float(ng[0])
mediatot[1]/=float(ng[1])
mediatot[2]/=float(ng[2])

print("Lista studenti = ", cl)
print()
print("Media voti maschi = %.2f" %mediatot[0])
print("Media voti femmine = %.2f" %mediatot[1])
print("Media voti LGBT = %.2f" %mediatot[2])

Esempio:

Lista studenti =  [[0, 0, 23, 23, 22, 24, 28], [1, 0, 22, 18, 18, 24, 28], [2, 0, 30, 25, 28, 21, 25], [3, 1, 23, 18, 23, 24, 30], [4, 0, 23, 19, 23, 25, 30], [5, 0, 19, 24, 30, 29, 26], [6, 1, 19, 21, 21, 20, 22], [7, 1, 27, 30, 18, 26, 20], [8, 1, 30, 24, 29, 21, 23], [9, 2, 31, 19, 27, 30, 25], [10, 2, 31, 27, 21, 31, 22], [11, 1, 19, 25, 19, 31, 20], [12, 2, 29, 24, 24, 26, 29], [13, 0, 26, 23, 25, 26, 29], [14, 0, 25, 29, 23, 21, 29], [15, 0, 19, 28, 22, 20, 29], [16, 1, 28, 21, 24, 22, 18], [17, 2, 19, 22, 27, 25, 22], [18, 1, 31, 22, 18, 27, 20], [19, 2, 21, 25, 25, 19, 23], [20, 2, 27, 23, 30, 25, 21], [21, 1, 26, 29, 23, 30, 30], [22, 1, 29, 22, 18, 30, 26], [23, 0, 23, 30, 28, 20, 19], [24, 1, 27, 29, 28, 19, 29], [25, 0, 25, 27, 22, 24, 31], [26, 1, 30, 26, 28, 26, 28], [27, 0, 18, 22, 30, 27, 26], [28, 1, 27, 18, 25, 24, 18], [29, 0, 31, 23, 24, 21, 30], [30, 2, 30, 28, 19, 24, 25], [31, 2, 23, 22, 23, 22, 19], [32, 2, 29, 31, 30, 25, 29], [33, 1, 30, 21, 29, 20, 23], [34, 1, 21, 26, 27, 23, 18], [35, 1, 29, 25, 20, 29, 25], [36, 2, 18, 21, 20, 22, 31], [37, 1, 30, 20, 19, 26, 20], [38, 0, 26, 19, 22, 22, 19], [39, 0, 31, 27, 19, 29, 18], [40, 2, 26, 26, 23, 24, 21], [41, 2, 28, 26, 23, 22, 25], [42, 2, 29, 27, 29, 25, 24], [43, 1, 29, 21, 18, 31, 29], [44, 1, 24, 22, 20, 31, 21], [45, 1, 20, 21, 30, 28, 23], [46, 0, 26, 24, 29, 26, 23], [47, 1, 22, 26, 26, 31, 26], [48, 2, 18, 23, 25, 23, 21], [49, 0, 18, 22, 26, 23, 23]]

Media voti maschi = 24.43
Media voti femmine = 24.39
Media voti LGBT = 24.70
>>> 

Coppie di numeri a differenza costante

# kdiff.py
#
# 
# Questo programma risolve il seguente problema :
# Dato un insieme s di N numeri interi trovare
# tutte le coppie di interi la cui differenza è pari a K
#
# by Andrea Bianchini (2021)

from random import randint

N = 50
MIN = 1
MAX = 1000
K = randint(MIN,MAX/2)

s = [randint(MIN,MAX) for _ in range(N)]


def f(x,y):
    global K
    if abs(x-y)==K:
        return True
    else:
        return False
    
res =[]

for x in range(N-1):
    for y in range(x+1,N):
        if f(s[x],s[y]):
            res.append((s[x],s[y]))

print("s =",s)
print()
print("K = %d" %K)
print("coppie =",res)

Esempio 1:

s = [240, 662, 961, 108, 802, 232, 954, 99, 542, 775, 668, 988, 637, 96, 135, 549, 111, 678, 86, 596, 912, 13, 191, 516, 118, 88, 837, 632, 870, 843, 542, 569, 819, 579, 411, 154, 743, 89, 95, 686, 604, 503, 511, 859, 305, 671, 161, 510, 164, 906]

K = 10
coppie = [(108, 118), (99, 89), (668, 678), (96, 86), (569, 579), (154, 164)]
>>> 

Esempio 2:

s = [327, 847, 660, 722, 431, 287, 79, 542, 354, 514, 703, 522, 764, 75, 904, 789, 103, 801, 929, 884, 964, 818, 992, 458, 369, 900, 239, 671, 120, 904, 421, 342, 403, 314, 495, 794, 119, 140, 810, 237, 333, 639, 676, 705, 134, 802, 528, 20, 452, 2]

K = 105
coppie = [(239, 134), (342, 237), (810, 705)]
>>> 

A minimal App in Android

In questo post vi mostro la struttura minimale di una App Android. In realtà potrebbe essere resa ancora più semplice, ma non chiarirebbe bene quali sono le parti che costituiscono l’App.

Iniziamo con il file AndroidManifest.xml (directory app/manifests) :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.andreabianchini.simpleandroidapp">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.SimpleAndroidApp">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Passiamo al file che contiene il programma principale dell’App, MainActivity.java (directory app/java) :

package com.andreabianchini.simpleandroidapp;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

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

Al programma (Activity) principale sopra riportato viene associato un file di risorse, activity_main.xml, (directory app/res/layout), che serve a definire l’aspetto ed i contenuti grafici della schermata associata all’attività principale :

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

In questo caso la nostra App Android minimale visualizzerà una schermata con la scritta : ‘Hello World!’.

Con l’ambiente di sviluppo ‘Android Studio’ potete generare automaticamente questa applicazione in un minuto.

Ecco il risultato:

App Android minimale