Update in Sqlite table via ImageButtom Android Studio

1

I have a project that I'm developing in Android Studio where I use a Custom Adapter, an Employee, and a DatabaseHelper.

What happens, I use an already populated database that is in the Assets folder, which is copied to the application's Databases directory at startup.

I also have a layout where you have a field to search. When doing the search the user clicks a button and the Custom Adapter comes into action to popular the ListView.

In the ListView there is an ImageButtom where I'm trying to implement a routine where the user clicks on it so that the item in the list can be saved as a favorite. How was he doing this? by taking the sub sub-category number and the fav favorite value and passing it to the public void update (String sub, String fav) function in DatabaseHelper .

I was not able to implement the ImageButtom click, the only place I could do this was in the custom adapter.

I just can not get the data in the table to get the update, because when I click on ImageButtom the application stops working.

DatabaseHelper.java

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

public class DatabaseHelper extends SQLiteOpenHelper {

private final static String TAG = "Database";
private final Context myContext;
private static final String DATABASE_NAME = "my_db.db";
public static final String SUBCATEGORIA = "sub_categ";
public static final String FAV = "fav";
private static final int DATABASE_VERSION = 2;
private String pathToSaveDBFile;
public DatabaseHelper(Context context, String filePath) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
    this.myContext = context;
    pathToSaveDBFile = new    StringBuffer(filePath).append("/").append(DATABASE_NAME).toString();
}
public void prepareDatabase() throws IOException {
    boolean dbExist = checkDataBase();
    if(dbExist) {
        int currentDBVersion = getVersionId();
        if (DATABASE_VERSION > currentDBVersion) {
            deleteDb();
            try {
                copyDataBase();
            } catch (IOException e) {
                Log.e(TAG, e.getMessage());
            }
        }
    } else {
        try {
            copyDataBase();
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
        }
    }
}
private boolean checkDataBase() {
    boolean checkDB = false;
    try {
        File file = new File(pathToSaveDBFile);
        checkDB = file.exists();
    } catch(SQLiteException e) {
        Log.d(TAG, e.getMessage());
    }
    return checkDB;
}
private void copyDataBase() throws IOException {
    OutputStream os = new FileOutputStream(pathToSaveDBFile);
    InputStream is = myContext.getAssets().open(DATABASE_NAME);
    byte[] buffer = new byte[1024];
    int length;
    while ((length = is.read(buffer)) > 0) {
        os.write(buffer, 0, length);
    }
    is.close();
    os.flush();
    os.close();
}
public void deleteDb() {
    File file = new File(pathToSaveDBFile);
    if(file.exists()) {
        file.delete();
    }
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}

public List<Employee> getEmployees(String codigo) {
    SQLiteDatabase db = SQLiteDatabase.openDatabase(pathToSaveDBFile, null, SQLiteDatabase.OPEN_READONLY);
    String query = "SELECT sub_categ, descricao, descrabrev, fav FROM tab_mytabe WHERE TRIM(sub_categ) LIKE '%"+codigo+"%' OR TRIM(descricao) LIKE '%"+codigo+"%'";

    Cursor cursor = db.rawQuery(query, null);
    List<Employee> list = new ArrayList<>();
    while(cursor.moveToNext()) {
        Employee employee = new Employee();
        employee.setSubcategoria(cursor.getString(0));
        employee.setDescricao(cursor.getString(1));
        employee.setDescrabrev(cursor.getString(2));
        employee.setFavorito(cursor.getString(3));
        list.add(employee);
    }
    db.close();
    return list;
}
private int getVersionId() {
    SQLiteDatabase db = SQLiteDatabase.openDatabase(pathToSaveDBFile, null, SQLiteDatabase.OPEN_READONLY);
    String query = "SELECT versao FROM tab_versao";
    Cursor cursor = db.rawQuery(query, null);
    cursor.moveToFirst();
    int v =  cursor.getInt(0);
    db.close();
    return v;
}
}

CustomAdapter.java

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
import java.util.ArrayList;



public class CustomAdapter extends ArrayAdapter<Employee> implements View.OnClickListener{

Animation animText;
String sub;
String fav;


private ArrayList<Employee> dataSet;
Context mContext;

// View lookup cache
private static class ViewHolder {
    TextView subcategoria;
    TextView descricao;
    TextView descrabrev;
    ImageButton favorito;
}

public CustomAdapter(ArrayList<Employee> data, Context context) {
    super(context, R.layout.lista, data);
    this.dataSet = data;
    this.mContext=context;
}

@Override
public void onClick(View v) {
    int position=(Integer) v.getTag();
    Object object= getItem(position);
    Employee dataModel=(Employee) object;

}


private int lastPosition = -1;

@Override
public View getView(int position, View convertView, final ViewGroup parent) {
    animText = AnimationUtils.loadAnimation(mContext, R.anim.anima_text);

    final Employee dataModel = getItem(position);

    final ViewHolder viewHolder; // view lookup cache stored in tag

    final View result;

    if (convertView == null) {

        viewHolder = new ViewHolder();
        LayoutInflater inflater = LayoutInflater.from(getContext());
        convertView = inflater.inflate(R.layout.lista, parent, false);
        viewHolder.subcategoria = (TextView) convertView.findViewById(R.id.tv_subcategoria);
        viewHolder.descrabrev = (TextView) convertView.findViewById(R.id.tv_descriabreviada);
        viewHolder.descricao = (TextView) convertView.findViewById(R.id.tv_descricao);
        viewHolder.favorito = (ImageButton)convertView.findViewById(R.id.btnFav);

        result=convertView;

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
        result=convertView;
    }

    viewHolder.subcategoria.setText(dataModel.getSubcategoria());
    viewHolder.descrabrev.setText(dataModel.getDescrabrev());
    viewHolder.descricao.setText(dataModel.getDescricao());


    if (dataModel.getFavorito().equals("1")){
       viewHolder.favorito.setBackgroundResource(R.drawable.ic_fav_seleted);
    }else if (dataModel.getFavorito().equals("0")){
        viewHolder.favorito.setBackgroundResource(R.drawable.ic_fav);
    }

    viewHolder.favorito.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            sub = dataModel.getSubcategoria();
            if (dataModel.getFavorito().equals("1")){
                fav = "0";
            }else if (dataModel.getFavorito().equals("0")){
                fav = "1";
            }
            viewHolder.favorito.startAnimation(animText);
        }
    });

    return convertView;
}
}

How could I solve this?

Obs. The update routine was just below the DatabaseHelper getVersionId () function, I pulled it out because it was not working. The call to the update function was in the viewHolder.favorite.setOnClickListener of the above code.

NX thanks for the reply!

I made changes to the Custom Adapter by entering the codes. It looks like this:

...
//Ação ao clicar no ImageButtom
viewHolder.favorito.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        sub = dataModel.getSubcategoria();
        if (mOnFavoriteEmployeeListener != null) {
            boolean fav = dataModel.getFavorito().equals("1");
            mOnFavoriteEmployeeListener.onFavorite(dataModel, fav);
        }
        viewHolder.favorito.startAnimation(animText);
    }
});

return convertView;
}

//Interface criada para a ação de update do favorito
interface OnFavoriteEmployeeListener {
void onFavorite(Employee e, boolean fav);
}

private OnFavoriteEmployeeListener mOnFavoriteEmployeeListener;

public void setOnFavoriteEmployeeListener(OnFavoriteEmployeeListener l) {
mOnFavoriteEmployeeListener = l;
}

But in Activity I could not see where I put the code, because I tried to put it but this is killing the application.

import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {

private ListView lv;
Animation animText;
ImageView search;
EditText textsearch;
TextView vazio;
String codigo;


//Custom Adapter
ArrayList<Employee> dataModels;
ListView listView;
private static CustomAdapter adapter;
//Final Custom Adapter

DatabaseHelper dbHelper= null;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);


animText = AnimationUtils.loadAnimation(this, R.anim.anima_text);
search = (ImageView)findViewById(R.id.img_Search);
favoritar = (ImageButton)findViewById(R.id.btnFav);
textsearch = (EditText)findViewById(R.id.edt_Search);
vazio = (TextView)findViewById(R.id.textViewV);
vazio.setVisibility(View.INVISIBLE);
lv = (ListView) findViewById(R.id.listview);


search.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        codigo = textsearch.getText().toString();
        search.startAnimation(animText);

        if((verificaCampos(textsearch.getText().toString()) != false)) {
            dbHelper = new DatabaseHelper(MainActivity.this, getFilesDir().getAbsolutePath());
            try {
                dbHelper.prepareDatabase();
            } catch (IOException e) {
                Log.e(TAG, e.getMessage());
            }
            //Datamodels
            List<Employee> list = dbHelper.getEmployees(codigo);
            dataModels = new ArrayList<>();
            for (int i =0; i< list.size(); i++) {
                dataModels.add(list.get(i));
            }

            adapter = new CustomAdapter(dataModels, getApplicationContext());
            lv.setAdapter(adapter);

            if(adapter.isEmpty()){
                vazio.setVisibility(View.VISIBLE);
            }else{
                vazio.setVisibility(View.INVISIBLE);
            }
            //Fim Data Models
        }else{
            mensagem();
        }
    }
});
//Final Pesquisa
}


private boolean verificaCampos(String campo1){
return campo1.trim().length() != 0;
}

}

ERROR

E/AndroidRuntime: FATAL EXCEPTION: main Process: br.com.projeto, PID: 25365 Theme: themes:{default=overlay:system, iconPack:system, fontPkg:system,  com.android.systemui=overlay:system,  com.android.systemui.navbar=overlay:system} java.lang.RuntimeException:  Unable to start activity  ComponentInfo{br.com.projeto/br.com.projeto.MainActivity}:   java.lang.NullPointerException: Attempt to invoke virtual method 'void  br.com.projeto.CustomAdapter.setOnFavoriteEmployeeListener(br.com.projeto.Cus tomAdapter$OnFavoriteEmployeeListener)' on a null object reference at  android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2450) at  android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2510) at  android.app.ActivityThread.-wrap11(ActivityThread.java) at  android.app.ActivityThread$H.handleMessage(ActivityThread.java:1363) at  android.os.Handler.dispatchMessage(Handler.java:102) at  android.os.Looper.loop(Looper.java:148) at  android.app.ActivityThread.main(ActivityThread.java:5461) at  java.lang.reflect.Method.invoke(Native Method) at  com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:72 6) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) Caused by:  java.lang.NullPointerException: Attempt to invoke virtual method 'void  br.com.projeto.CustomAdapter.setOnFavoriteEmployeeListener(br.com.projeto.Cus tomAdapter$OnFavoriteEmployeeListener)' on a null object reference at  br.com.projeto.MainActivity.onCreate(MainActivity.java:118) at  android.app.Activity.performCreate(Activity.java:6251) at  android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2403)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2510)   at android.app.ActivityThread.-wrap11(ActivityThread.java)  at  android.app.ActivityThread$H.handleMessage(ActivityThread.java:1363)  at  android.os.Handler.dispatchMessage(Handler.java:102)  at  android.os.Looper.loop(Looper.java:148)  at  android.app.ActivityThread.main(ActivityThread.java:5461)  at  java.lang.reflect.Method.invoke(Native Method)  at  com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 

Where am I going wrong?

After the new changes

After the code changes, the logic looks like this:

CustomAdapter

....
 //Ação ao clicar no ImageButtom
    viewHolder.favorito.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            sub = dataModel.getSubcategoria();
            if (mOnFavoriteEmployeeListener != null) {
                boolean fav = dataModel.getFavorito().equals("1");
                mOnFavoriteEmployeeListener.onFavorite(dataModel, fav);
            }
            viewHolder.favorito.startAnimation(animText);
        }
    });

    return convertView;
}

private OnFavoriteEmployeeListener mOnFavoriteEmployeeListener;

//Interface criada para a ação de update do favorito
interface OnFavoriteEmployeeListener {
    void onFavorite(Employee e, boolean fav);
}

public void setOnFavoriteEmployeeListener(OnFavoriteEmployeeListener l) {
    mOnFavoriteEmployeeListener = l;
}

MainActivity

...
adapter = new CustomAdapter(dataModels, getApplicationContext());
                adapter.setOnFavoriteEmployeeListener(new CustomAdapter.OnFavoriteEmployeeListener() {
                    public void onFavorite(Employee e, boolean fav) {
                        dbHelper.update(e.getSubcategoria(), fav ? "1" : "0");
                    }
                });
                lv.setAdapter(adapter);

DatabaseHelper

//Faz o update da tabela ao clicar no ImageButtom
public void update(String sub,  String fav){
    SQLiteDatabase db = SQLiteDatabase.openDatabase(pathToSaveDBFile, null, SQLiteDatabase.OPEN_READWRITE);
    String query = "UPDATE tab_mytabe SET fav = '"+fav+"' WHERE sub_categ = '"+sub+"'";
    db.execSQL(query);
    db.close();
}

However, it is not performing any actions on the database and does not show any apparent errors.

Resolved bank update issue

I found out what was happening, the code part of Activity was like this:

...
dbHelper.update(e.getSubcategoria(), fav ? "1" : "0");
...

When ImageButtom was clicked the update would normally happen only if the value did not change because if the value of the field in the table was "0" when clicking ImageButtom the value would still be "0", because the value true is 1, for this did not see any change. It was just changing the numbers that worked perfectly. Then with the change it was as follows:

...
dbHelper.update(e.getSubcategoria(), fav ? "0" : "1");
...
    
asked by anonymous 30.01.2017 / 21:18

1 answer

1

No CustomAdapter create an interface that will be called when a Employee is favored or not favored:

interface OnFavoriteEmployeeListener {
    void onFavorite(Employee e, boolean fav);
}

A field and a set :

private OnFavoriteEmployeeListener mOnFavoriteEmployeeListener;

public void setOnFavoriteEmployeeListener(OnFavoriteEmployeeListener l) {
    mOnFavoriteEmployeeListener = l;
}

And change getView :

viewHolder.favorito.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if (mOnFavoriteEmployeeListener != null) {
            boolean fav = dataModel.getFavorito().equals("1");
            mOnFavoriteEmployeeListener.onFavorite(dataModel, fav);
        }
        viewHolder.favorito.startAnimation(animText);
    }
});

In the activity where you instantiate CustomAdapter :

customAdapter.setOnFavoriteEmployeeListener(new OnFavoriteEmployeeListener() {
    public void onFavorite(Employee e, boolean fav) {
        databaseHelperInstance.update(e.getSubcategoria(), fav ? "1" : "0");
    }
});

Note that this depends on an instance of DatabaseHelper that was probably created in onCreate(Bundle) to get a ArrayList of Employee .

(In response to the question of where to put the listener)

After the adapter instance:

adapter = new CustomAdapter(dataModels, getApplicationContext());
adapter.setOnFavoriteEmployeeListener(new OnFavoriteEmployeeListener() {
    public void onFavorite(Employee e, boolean fav) {
        dbHelper.update(e.getSubcategoria(), fav ? "1" : "0");
    }
});
lv.setAdapter(adapter);

You may notice that the error has a NullPointerException because adapter is null . Maybe I was setting the listener out of View.OnClickListener .

(Edition 2)

Ok, two things:

SQLiteOpenHelper is a class to help open / create / update the database. The existence checks, open data file, etc. that you did, SQLiteOpenHelper already does. Here's an alternative to SQLiteOpenHelper that takes advantage of these features by comparing with some of your lines:

public static class NXDatabaseHelper extends SQLiteOpenHelper {

    private static final String NOME_BANCO_DE_DADOS = "my_db";

    private static final int DATABASE_VERSION = 2;

    public NXDatabaseHelper(Context context) {
        // este super vai verificar se o banco de dados existe. Vai chamar o onCreate se não
        // existe. Se existir mais tem uma versão antige, vai chamar onUpgrade
        super(context, NOME_BANCO_DE_DADOS, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // onCreate só vai ser chamado quando o banco de dados não existir
        // seria o equivalente ao checkDataBase() no original

        // prepareDatabase() faz a cópia de outro banco de dados ao que parece...
        db.execSQL("CREATE TABLE tab_mytabe(" +
                "sub_categ TEXT," +
                "descricao TEXT," +
                "descrabrev TEXT," +
                "fav integer" +
                ");");
        // faça a cópia aqui, copyDataBase(), se precisar
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // if (dbExist) {
        switch (oldVersion) {
            // versões anteriores do banco de dados
            // if (DATABASE_VERSION > currentDBVersion)
            case 0:
                // o que mudou da primeira versão para a versão 2?
            case 1:
                // deleteDb();
                db.execSQL("DROP TABLE tab_mytabe;");

                // try {
                //     copyDataBase();
                // } catch (IOException e) {
                //     Log.e(TAG, e.getMessage());
                // }
                onCreate(db);
        }
        // }
    }

    public List<Employee> getEmployees(String codigo) {
        SQLiteDatabase db = getReadableDatabase();
        String query = "SELECT sub_categ, descricao, descrabrev, fav" +
                " FROM tab_mytabe" +
                " WHERE TRIM(sub_categ) LIKE '%" + codigo + "%'" +
                " OR TRIM(descricao) LIKE '%" + codigo + "%'";

        Cursor cursor = db.rawQuery(query, null);
        List<Employee> list = new ArrayList<>();

        // só para ter certeza das posições das colunas
        final int subcat = cursor.getColumnIndex("sub_categ");
        final int descricao = cursor.getColumnIndex("descricao");
        final int descrabrev = cursor.getColumnIndex("descrabrev");
        final int fav = cursor.getColumnIndex("fav");

        while (cursor.moveToNext()) {
            Employee employee = new Employee();

            employee.setSubcategoria(cursor.getString(subcat));
            employee.setDescricao(cursor.getString(descricao));
            employee.setDescrabrev(cursor.getString(descrabrev));
            employee.setFavorito(cursor.getLong(fav) != 0);

            list.add(employee);
        }

        cursor.close(); // o cursor deve ser fechado depois do uso
        db.close();

        return list;
    }

    public void update(String subCategoria, boolean fav) {
        SQLiteDatabase db = getReadableDatabase();

        ContentValues campos = new ContentValues(); // é como um Bundle

        campos.put("fav", fav ? 1 : 0);

        // Equivalente:
        // UPDATE tab_mytabe SET fav="0 ou 1" WHERE sub_categ='subcategoria';
        db.update("tab_mytabe", campos, "sub_categ='" + subCategoria + '\'', null);
    }
}

No onCreate needs to be declared out of View.OnClickListener() of search because a new instance will be created every time something is searched. The changes are few, as dbHelper is initialized outside of the listener, where OnFavoriteEmployeeListener is and others are commented out to compare with the original code:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    animText = AnimationUtils.loadAnimation(this, R.anim.anima_text);
    search = (ImageView) findViewById(R.id.img_Search);
    favoritar = (ImageButton) findViewById(R.id.btnFav);
    textsearch = (EditText) findViewById(R.id.edt_Search);
    vazio = (TextView) findViewById(R.id.textViewV);
    vazio.setVisibility(View.INVISIBLE);
    lv = (ListView) findViewById(R.id.listview);

    final NXDatabaseHelper dbHelper = new NXDatabaseHelper(MainActivity.this);

    search.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            codigo = textsearch.getText().toString();
            search.startAnimation(animText);

            //if ((verificaCampos(textsearch.getText().toString()) != false)) { // Por que?
            if (verificaCampos(textsearch.getText().toString())) {
                // não é preciso do arquivo, já que SQLiteOpenHelper cria o arquivo
                dbHelper = new NXDatabaseHelper(MainActivity.this);
                // try {
                //     dbHelper.prepareDatabase();
                // } catch (IOException e) {
                //     Log.e(TAG, e.getMessage());
                // }
                // Datamodels
                // uma lista que é copiada para a outra e descartada em seguida...
                // List<Employee> list = dbHelper.getEmployees(codigo);
                // dataModels = new ArrayList<>();
                // for (int i = 0; i < list.size(); i++) {
                //     dataModels.add(list.get(i));
                // }
                dataModels = dbHelper.getEmployees(codigo);

                adapter = new CustomAdapter(dataModels, getApplicationContext());
                adapter.setOnFavoriteEmployeeListener(new OnFavoriteEmployeeListener() {
                    public void onFavorite(Employee e, boolean fav) {
                        dbHelper.update(e.getSubcategoria(), fav);
                    }
                });
                lv.setAdapter(adapter);

                if (adapter.isEmpty()) {
                    vazio.setVisibility(View.VISIBLE);
                } else {
                    vazio.setVisibility(View.INVISIBLE);
                }
                //Fim Data Models
            } else {
                mensagem();
            }
        }
    });
    //Final Pesquisa
}

As we do not have the full code of the original DatabaseHelper , I'm assuming the columns are not being added, or something like that.

    
31.01.2017 / 02:08