0

This is my situation: I have a GridLayout (wich has some textviews in some cells of it right at the begining of the activity, but i will change it to generate those textviews dynamically later) and I want to place some textViews in a few cells of it.

The problem: I don't know how many textViews I will need. It depends of the information of the database. Besides, I don't know how to add the textViews generated to the gridLayout from an AsyncTask.

So, i've been looking for some answers but I couldn't make it work. I tried something like this, but is not exactly what i'm looking for (i create a new TextView, but can't add it to the gridLayout from that thread). This is the workflow of my app:

1º I start the activity with the gridLayout. It has some textViews: image

This is the main Activity:

public class MostrarProyectos extends AppCompatActivity {

private final String TAG = "MostrarProyectos";

//Para obtener de un hilo no principal los proyectos:
public static ArrayList<Proyecto> listaDeProyectos = new ArrayList<>();

public GridLayout grid;

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

        grid = (GridLayout) findViewById(R.id.grid);

        EstrategiaObtenerObjetoDB e = FabricaEstrategiaObtenerDB.getInstance().construirEstrategia("proyecto", this); //This is a Fabric, wich obtains a Strategy
        e.execute(this.getApplicationContext(), "proyecto", this, this.grid);//I sended a lot of things to test if something gives result
    }
}

2º In that main class, I started a new Thread with AsyncTask, to get data from a SQLite DB. This is the Fabric:

public class FabricaEstrategiaObtenerDB {
    private static final FabricaEstrategiaObtenerDB ourInstance = new FabricaEstrategiaObtenerDB();

    public static FabricaEstrategiaObtenerDB getInstance() {
        return ourInstance;
    }

    private FabricaEstrategiaObtenerDB() {}

    public EstrategiaObtenerObjetoDB construirEstrategia(String tabla, Activity acti){
        switch(tabla){
//Some other cases
        case "proyecto":
            EstrategiaObtenerObjetoDBProyecto p = new EstrategiaObtenerObjetoDBProyecto(acti, new onTextViewCreatedListener() {
                @Override
                public void onTextViewCreated(TextView tv) {
                //I don't know what to do here
                }
            }); //This code I tried from the other stackOverflow answer
            return p;
        default:
            return null;
    }
}
}

This an abstract class to obtain objects from the DB:

public abstract class EstrategiaObtenerObjetoDB extends AsyncTask<Object, Void, ArrayList<Object>> {

protected onTextViewCreatedListener onTextViewCreatedListener; //part of the code from the other StackOverflow user.
Activity miActividad;

public EstrategiaObtenerObjetoDB(Activity act, onTextViewCreatedListener onTextViewCreatedListener){
    this.onTextViewCreatedListener = onTextViewCreatedListener; //This is too code from the other user.
    this.miActividad = act;
}

@Override
protected ArrayList<Object> doInBackground(Object... params) {
    AppDbHelper mDbHelper = new AppDbHelper(miActividad.getApplicationContext()); 
    SQLiteDatabase db = mDbHelper.getReadableDatabase();

    String[] projection = obtenerSelect();

    Cursor c = armarQuery(db, (String)params[1], projection); //params[1] is the name of the table in the DB
    ArrayList<Object> arrayDeObjetos = new ArrayList<>();

    try{
        arrayDeObjetos.add(miActividad.getApplicationContext());//add the context
        arrayDeObjetos.add(miActividad.findViewById(R.id.grid));//add the grid
        armarObjetos(c);
        return arrayDeObjetos;
    }catch (Exception e){
        String b = e.getMessage();
        return null;
    }
}


@Override
protected abstract void onPostExecute(ArrayList<Object> objects);

protected abstract String[] obtenerSelect();

protected abstract Cursor armarQuery(SQLiteDatabase db, String tabla, String[] projection);

protected abstract void armarObjetos(Cursor c);

}

And this is the specific Strategy:

public class EstrategiaObtenerObjetoDBProyecto extends EstrategiaObtenerObjetoDB {

public EstrategiaObtenerObjetoDBProyecto(Activity act,onTextViewCreatedListener onTextViewCreatedListener) {
    super(act,onTextViewCreatedListener);
}

@Override
protected String[] obtenerSelect() {
    String[] projection = {
            AppContract.Proyecto._ID,
            AppContract.Proyecto.COLUMN_NOMBRE,
            AppContract.Proyecto.COLUMN_DESCRIPCION,
            AppContract.Proyecto.COLUMN_PRIORIDAD,
            AppContract.Proyecto.COLUMN_ANIO,
            AppContract.Proyecto.COLUMN_MES,
            AppContract.Proyecto.COLUMN_SEMANA,
            AppContract.Proyecto.COLUMN_DURACION,
    };
    return projection;
}

@Override
protected Cursor armarQuery(SQLiteDatabase db, String tabla, String[] projection) {
    Cursor cursor = db.query(
            tabla,
            projection,
            null,
            null,
            null,
            null,
            null
    );
    return cursor;
}

@Override
protected void armarObjetos(Cursor c) {
    c.moveToFirst();

    ArrayList<Object> proyectos = new ArrayList<>();
    do {
        try{
            String nombre = c.getString(c.getColumnIndex(AppContract.Proyecto.COLUMN_NOMBRE));
            String descripcion = c.getString(c.getColumnIndex(AppContract.Proyecto.COLUMN_DESCRIPCION));
            String prioridad = c.getString(c.getColumnIndex(AppContract.Proyecto.COLUMN_PRIORIDAD));
            String anio = c.getString(c.getColumnIndex(AppContract.Proyecto.COLUMN_ANIO));
            String mes = c.getString(c.getColumnIndex(AppContract.Proyecto.COLUMN_MES));
            String semana = c.getString(c.getColumnIndex(AppContract.Proyecto.COLUMN_SEMANA));
            String duracion = c.getString(c.getColumnIndex(AppContract.Proyecto.COLUMN_DURACION));
            Proyecto p = new Proyecto(nombre,descripcion, prioridad, anio, mes, semana, duracion);
            MostrarProyectos.listaDeProyectos.add(p);
            proyectos.add(p);
        }catch(Exception e){
            Log.d("EstrategiaObtenerPr",e.getMessage());
        }
    } while (c.moveToNext());

}

@Override
protected void onPostExecute(ArrayList<Object> objects) {
    MostrarProyectos.listaDeProyectos.add((Proyecto)objects.get(i));

    GridLayout grid = (GridLayout) miActividad.findViewById(R.id.grid);
    if(!MostrarProyectos.listaDeProyectos.isEmpty()){
        for(int numeroTemporal = 0; numeroTemporal<MostrarProyectos.listaDeProyectos.size();numeroTemporal++){
            Proyecto j = MostrarProyectos.listaDeProyectos.get(numeroTemporal);
            TextView text = new TextView(miActividad.getApplicationContext());
            text.setText(j.getNombre());
            int numFila = MostrarProyectos.contarFilas(j.getMes(), j.getSemana());
            GridLayout.LayoutParams params3 = new GridLayout.LayoutParams();
            params3.rowSpec = GridLayout.spec(numFila);//,Integer.parseInt(j.getDuracion())
            Log.d("MostrarProyecto", numFila+","+Integer.parseInt(j.getDuracion()));
            params3.columnSpec = GridLayout.spec(3);
            text.setLayoutParams(params3);

            try{
                if(onTextViewCreatedListener!=null){
                   onTextViewCreatedListener.onTextViewCreated(text);//from the other user

                }
            }catch (Exception excepcion){
                Log.d("MostrarProyecto", excepcion.getMessage());
            }
        }
    }
    else{
        Toast.makeText(miActividad.getApplicationContext(),"No hay proyectos",Toast.LENGTH_LONG);
    }
    MostrarProyectos.terminoCargaDatos = true;
}
}

3º After I get the data, I want to generate as many TextViews as objects i've got from the DB, so I use a 'for' to see how many objects i have inside a temporal list i created. For heach object, I want to create a TextView, and add it to the gridLayout (that is on the main thread).

And finally, an interface from the other answer:

public interface onTextViewCreatedListener {
    public void onTextViewCreated(TextView tv);
}

I hope you can help me. Thank you.

EDIT_1: I need to use other thread different from the UI thread because i need to search in the DB the data.

  • maybe you can return just the texts from the async task and create the textviews ... or you can use runOnuiThread() method explained here: https://stackoverflow.com/questions/12850143/android-basics-running-code-in-the-ui-thread – reinaldomoreira May 30 '17 at 17:25
  • Just include the list-view -> text-view. Based on the size of the array-list text-view is created dynamically. – sivaprakash May 30 '17 at 17:37
  • In place of grid view try to use either a recycler view or an expandable list view with adapters. – Susheel Tickoo May 30 '17 at 17:38
  • @ViperAlpha how can I send anything from an AsyncTask to the main thread? because the main thread won't wait for the other thread to finish. – Bruno Fernandez Ellerbach May 30 '17 at 17:57
  • @BrunoFernandez you can call RunOnUiThread method from Activity Class, this way, the Android will run it in the Main Thread, see the link I posted. You just need a Context object. – reinaldomoreira May 30 '17 at 17:58

1 Answers1

0

You have to split your logic, search data in the DB in AsyncTask or simple new Thread() and then create UI elements and attach them in UI thread.

mActivity
       .runOnUiThread(
               new Runnable() {

                    @Override
                    public void run() {
                        //create a TextView, and add it to the gridLayout
                    }
                });
Jon
  • 9,156
  • 9
  • 56
  • 73
Oleg Sokolov
  • 1,134
  • 1
  • 12
  • 19