I make a dictionary program from Russian to English and vice versa.

There is a form with Spinner , where the direction of transfer is chosen. There is a text field txtSearch for searching words and there is a ListView where words from database tables are output depending on the direction of translation. The words from the tables in the ListView displayed via my adapter based on SimpleCursorAdapter .

This is the adapter code:

 public class MyCursorAdapter extends SimpleCursorAdapter { private int layout; DBHeler db; Context ctx; MyCursorAdapter(Context ctx, int layout, Cursor cursor, String[] from, int[] to, DBHeler db) { super(ctx, layout, cursor, from, to); this.layout = layout; this.db = db; this.ctx = ctx; } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(layout, parent, false); return view; } @Override public void bindView(View view, Context context, Cursor cursor) { String bukva = cursor.getString(cursor.getColumnIndex(Contract.Entry.COLUMN_SLOVO)).substring(0, 1).toUpperCase(); final String slovo = cursor.getString(cursor.getColumnIndex(Contract.Entry.COLUMN_SLOVO)); final String izbrannoe = cursor.getString(cursor.getColumnIndex(Contract.Entry.COLUMN_IZBRANNOE)); TextView txtBukva = (TextView) view.findViewById(R.id.txtBukva); TextView txtSlovo = (TextView) view.findViewById(R.id.txtSlovo); final ImageButton btnIzbrannoe = (ImageButton) view.findViewById(R.id.btnIzbrannoe); txtBukva.setText(bukva); txtSlovo.setText(slovo); btnIzbrannoe.setFocusable(false); if (izbrannoe.equals("1")) { btnIzbrannoe.setImageResource(R.drawable.icon_star_yellow); } else if (izbrannoe.equals("0")) { btnIzbrannoe.setImageResource(R.drawable.icon_star_outline_black); } btnIzbrannoe.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (izbrannoe.equals("1")) { ContentValues values = new ContentValues(); values.put(Contract.Entry.COLUMN_IZBRANNOE, "0"); long newRowId = db.database.update(Contract.Entry.TABLE_RUEN, values, Contract.Entry.COLUMN_SLOVO + "= ?", new String[]{slovo}); if (newRowId == -1) { Toast.makeText(ctx, "Ошибка", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(ctx, "Удалено из избранное", Toast.LENGTH_SHORT).show(); btnIzbrannoe.setImageResource(R.drawable.icon_star_outline_black); } } else if (izbrannoe.equals("0")) { ContentValues values = new ContentValues(); values.put(Contract.Entry.COLUMN_IZBRANNOE, "1"); long newRowId = db.database.update(Contract.Entry.TABLE_RUEN, values, Contract.Entry.COLUMN_SLOVO + "= ?", new String[]{slovo}); if (newRowId == -1) { Toast.makeText(ctx, "Ошибка", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(ctx, "Добавлено в избранное", Toast.LENGTH_SHORT).show(); btnIzbrannoe.setImageResource(R.drawable.icon_star_yellow); } } } }); } } 

This is the main MainActivity code:

 public class MainActivity extends AppCompatActivity { private AutoCompleteTextView txtSearch; private Spinner spinner; private ListView list; private ImageButton btnClear; DBHeler db; private MyCursorAdapter myCursorAdapter; private Cursor cursor; String[] from; int[] to; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); db = new DBHeler(this); try { db.createDataBase(); db.openDataBase(); } catch (IOException ex) { ex.printStackTrace(); } spinner = (Spinner) findViewById(R.id.spinner); // Настраиваем адаптер ArrayAdapter<?> adapter = ArrayAdapter.createFromResource(this, R.array.types, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // Вызываем адаптер spinner.setAdapter(adapter); txtSearch = (AutoCompleteTextView) findViewById(R.id.txtSearch); list = (ListView) findViewById(R.id.list); btnClear = (ImageButton) findViewById(R.id.btnClear); /*Выводим в список все слова, при запуске программы*/ String selectedItem = spinner.getSelectedItem().toString(); if (selectedItem.equals("С русского на английский")) { cursor = db.getRuWords(); from = new String[] {Contract.Entry.COLUMN_SLOVO, Contract.Entry.COLUMN_SLOVO, Contract.Entry.COLUMN_IZBRANNOE}; to = new int[] {R.id.txtBukva, R.id.txtSlovo, R.id.btnIzbrannoe}; myCursorAdapter = new MyCursorAdapter(this, R.layout.item, cursor, from, to, db); list.setAdapter(myCursorAdapter); } else if (selectedItem.equals("С английского на русский")) { cursor = db.getEnWords(); from = new String[] {Contract.Entry.COLUMN_SLOVO, Contract.Entry.COLUMN_SLOVO, Contract.Entry.COLUMN_IZBRANNOE}; to = new int[] {R.id.txtBukva, R.id.txtSlovo, R.id.btnIzbrannoe}; myCursorAdapter = new MyCursorAdapter(this, R.layout.item, cursor, from, to, db); list.setAdapter(myCursorAdapter); } } @Override protected void onResume() { super.onResume(); txtSearch.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View view, boolean b) { if (b && txtSearch.getText().toString().length() > 0) btnClear.setVisibility(View.VISIBLE); else btnClear.setVisibility(View.INVISIBLE); } }); list.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { Intent intent = new Intent(MainActivity.this, SlovoActivity.class); CharSequence strCharSequence = ((TextView)view.findViewById(R.id.txtSlovo)).getText(); String str = strCharSequence.toString().toLowerCase().trim(); String selectedItem = spinner.getSelectedItem().toString(); if (selectedItem.equals("С русского на английский")) { intent.putExtra("slovo", str); intent.putExtra("type", "RU"); startActivity(intent); } else if (selectedItem.equals("С английского на русский")) { intent.putExtra("slovo", str); intent.putExtra("type", "EN"); startActivity(intent); } } }); spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) { txtSearch.setText(""); String str = adapterView.getItemAtPosition(i).toString(); if (str.equals("С русского на английский")) { cursor = db.getRuWords(); myCursorAdapter = new MyCursorAdapter(MainActivity.this, R.layout.item, cursor, from, to, db); list.setAdapter(myCursorAdapter); } else if (str.equals("С английского на русский")) { cursor = db.getEnWords(); myCursorAdapter = new MyCursorAdapter(MainActivity.this, R.layout.item, cursor, from, to, db); list.setAdapter(myCursorAdapter); } } @Override public void onNothingSelected(AdapterView<?> adapterView) { } }); } } 

Here is the code of classes for connecting to the database, querying data in cursors, etc .:

 public class Contract { private Contract() { }; public static final class Entry implements BaseColumns { public final static String TABLE_RUEN = "ruen"; public final static String TABLE_ENRU = "enru"; public final static String _ID = BaseColumns._ID; public final static String COLUMN_SLOVO = "slovo"; public final static String COLUMN_PEREVOD = "perevod"; public final static String COLUMN_IZBRANNOE = "izbrannoe"; } } 

DBHelper class:

 public class DBHeler extends SQLiteOpenHelper { //Пусть к БД private static String DB_PATH = "/data/data/tests.mytest/databases/"; //Имя файла базы данных private static final String DATABASE_NAME = "dbase.db"; //Версия базы данных. При изменении схемы увеличить на единицу private static final int DATABASE_VERSION = 1; //Объектная переменная типа SQLiteDatabase public SQLiteDatabase database; private Context myContext; final String ruQuery = "SELECT * " + " FROM " + Contract.Entry.TABLE_RUEN; //запрос, позволяет вывести все слова из колонки word final String enQuery = "SELECT * " + " FROM " + Contract.Entry.TABLE_ENRU; //Конструктор //Третий параметр null в суперклассе используется для работы с курсорами. Сейчас их не используем, поэтому оставим в покое. public DBHeler(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); this.myContext = context; } public Cursor getRuWords() { return database.rawQuery(ruQuery, null); //в курсор выбираем все слова из запроса } public Cursor getEnWords() { return database.rawQuery(enQuery, null); //в курсор выбираем все слова из запроса } public void createDataBase() throws IOException { boolean dbExist = checkDataBase(); if(dbExist){ //ничего не делать - база уже есть }else{ //вызывая этот метод создаем пустую базу, позже она будет перезаписана this.getReadableDatabase(); try { copyDataBase(); } catch (IOException e) { throw new Error("Error copying database"); } } } private boolean checkDataBase(){ SQLiteDatabase checkDB = null; try { String myPath = DB_PATH + DATABASE_NAME; checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); } catch(SQLiteException e){ //база еще не существует } if(checkDB != null){ checkDB.close(); } return checkDB != null ? true : false; } private void copyDataBase() throws IOException{ //Открываем локальную БД как входящий поток InputStream myInput = myContext.getAssets().open(DATABASE_NAME); //Путь ко вновь созданной БД String outFileName = DB_PATH + DATABASE_NAME; //Открываем пустую базу данных как исходящий поток OutputStream myOutput = new FileOutputStream(outFileName); //перемещаем байты из входящего файла в исходящий byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer))>0){ myOutput.write(buffer, 0, length); } //закрываем потоки myOutput.flush(); myOutput.close(); myInput.close(); } public void openDataBase() throws SQLException { //открываем БД String myPath = DB_PATH + DATABASE_NAME; //database = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); database = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE); } @Override public synchronized void close() { if(database != null) database.close(); super.close(); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } 

Problem:

With the btnIzbrannoe.setOnClickListener(new View.OnClickListener() method, adding to favorites has turned out, but when I click btnIzbrannoe second time to remove from favorites, it does not work. That is, it does not remove from favorites. The icon of the button changes, but not really removes from favorites.

  • Comments are not intended for extended discussion; conversation moved to chat . - Nick Volynkin

2 answers 2

The problem is due to the fact that you make changes to the database, and the value of the cursor on which you navigate when processing a click remains with old data. As a solution, you can use an array — a local variable that will store the current status of the selected in the current session:

 public class MyCursorAdapter extends SimpleCursorAdapter { private int layout; DBHeler db; Context ctx; boolean[] favorite; MyCursorAdapter(Context ctx, int layout, Cursor cursor, String[] from, int[] to, DBHeler db) { super(ctx, layout, cursor, from, to); this.layout = layout; this.db = db; this.ctx = ctx; favorite = new boolean[cursor.getCount()]; // заполняем первоначальные состояния избранного из БД int i = 0; while (cursor.moveToNext() ) { String fav = cursor.getString(cursor.getColumnIndex(Contract.Entry.COLUMN_IZBRANNOE)); favorite[i] = (fav.equals("1")) ? true: false; i = i++; } // восстанавливаем позицию курсора после итерации cursor.moveToPosition(-1); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(context.LAYOUT_INFLATER_SERVICE); View view = inflater.inflate(layout, parent, false); return view; } @Override public void bindView(View view, Context context, Cursor cursor) { String bukva = cursor.getString(cursor.getColumnIndex(Contract.Entry.COLUMN_SLOVO)).substring(0, 1).toUpperCase(); final String slovo = cursor.getString(cursor.getColumnIndex(Contract.Entry.COLUMN_SLOVO)); // текущая позиция в курсоре final int pos = cursor.getPosition(); TextView txtBukva = (TextView) view.findViewById(R.id.txtBukva); TextView txtSlovo = (TextView) view.findViewById(R.id.txtSlovo); final ImageButton btnIzbrannoe = (ImageButton) view.findViewById(R.id.btnIzbrannoe); txtBukva.setText(bukva); txtSlovo.setText(slovo); btnIzbrannoe.setFocusable(false); if (favorite[pos]) { btnIzbrannoe.setImageResource(R.drawable.icon_star_yellow); } else { btnIzbrannoe.setImageResource(R.drawable.icon_star_outline_black); } btnIzbrannoe.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (favorite[pos]) { ContentValues values = new ContentValues(); values.put(Contract.Entry.COLUMN_IZBRANNOE, "0"); long newRowId = db.database.update(Contract.Entry.TABLE_RUEN, values, Contract.Entry.COLUMN_SLOVO + "= ?", new String[]{slovo}); if (newRowId == -1) { Toast.makeText(ctx, "Ошибка", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(ctx, "Удалено из избранное", Toast.LENGTH_SHORT).show(); btnIzbrannoe.setImageResource(R.drawable.icon_star_outline_black); } } else { ContentValues values = new ContentValues(); values.put(Contract.Entry.COLUMN_IZBRANNOE, "1"); long newRowId = db.database.update(Contract.Entry.TABLE_RUEN, values, Contract.Entry.COLUMN_SLOVO + "= ?", new String[]{slovo}); if (newRowId == -1) { Toast.makeText(ctx, "Ошибка", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(ctx, "Добавлено в избранное", Toast.LENGTH_SHORT).show(); btnIzbrannoe.setImageResource(R.drawable.icon_star_yellow); } } // инвертируем значение в вспомогательном массиве favorite[pos] = !favorite[pos]; } }); } } 

wrote "on the knee", minor tweaks are possible, but I think the general algorithm is clear

BUT! I would have done something completely different, but this is a lot of work. Firstly, it used the CursorLoader class to load data from the database into the list, it solves several serious problems, such as the relevance of the cursor, timely closing and saving when the state changes, asynchronous work that does not slow down the UI. All the control logic of the chosen one was taken out from the adapter to the activation (processing of a click on the favorites button), this will allow to get rid of the fixed cursor.

  • Thank. I'll try first then read about the cursoradapter - Veronica
  • @ Veronica CursorLoader apparently, not CursorAdapter - pavlofff
  • Yes, messed up) - Veronika
  • I try as here startandroid.ru/ru/uroki/vse-uroki-spiskom/… to do everything through CursorLoader. But the program immediately crashes. Here’s what E / AndroidRuntime logs in: FATAL EXCEPTION: ModernAsyncTask # 1 Process: tests.mytest2, PID: 4155 java.lang.RuntimeException: at android.support.v4.content.ModernAsyncTask $ 3. done (ModernAsyncTask.java:161), etc. - Veronika
  • @ Veronica Create a new question with this problem - pavlofff

This is changed in the MainActivity

 from = new String[] {Contract.Entry._ID, Contract.Entry.COLUMN_SLOVO, Contract.Entry.COLUMN_SLOVO, Contract.Entry.COLUMN_IZBRANNOE}; 

Also at the beginning of the bindView in the adapter about

 String bukva = cursor.getString(cursor.getColumnIndex(Contract.Entry.COLUMN_SLOVO)).substring(0, 1).toUpperCase(); final String slovo = cursor.getString(cursor.getColumnIndex(Contract.Entry.COLUMN_SLOVO)); final String izbrannoe = cursor.getString(cursor.getColumnIndex(Contract.Entry.COLUMN_IZBRANNOE)); 

add

 int _ID = cursor.getInt(cursor.getColumnIndex(Contract.Entry._ID)); 

then after btnIzbrannoe initialization add:

 btnIzbrannoe.setTag(_ID); 

and Listener:

 btnIzbrannoe.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { String id = String.valueOf(view.getTag()); Cursor getFav = db.rawQuery("SELECT * FROM " + Contract.Entry.TABLE_RUEN + " WHERE " + Contract.Entry._ID + " = " + id, null); if(getFav != null && getFav.moveToFirst()){ String izbrannoe = getFav.getString(getFav.getColumnIndex(Contract.Entry.COLUMN_IZBRANNOE)); if (izbrannoe.equals("1")) { ContentValues values = new ContentValues(); values.put(Contract.Entry.COLUMN_IZBRANNOE, "0"); long newRowId = db.database.update(Contract.Entry.TABLE_RUEN, values, Contract.Entry.COLUMN_SLOVO + "= ?", new String[]{slovo}); if (newRowId == -1) { Toast.makeText(ctx, "Ошибка", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(ctx, "Удалено из избранное", Toast.LENGTH_SHORT).show(); btnIzbrannoe.setImageResource(R.drawable.icon_star_outline_black); } } else if (izbrannoe.equals("0")) { ContentValues values = new ContentValues(); values.put(Contract.Entry.COLUMN_IZBRANNOE, "1"); long newRowId = db.database.update(Contract.Entry.TABLE_ENRU, values, Contract.Entry.COLUMN_SLOVO + "= ?", new String[]{slovo}); if (newRowId == -1) { Toast.makeText(ctx, "Ошибка", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(ctx, "Добавлено в избранное", Toast.LENGTH_SHORT).show(); btnIzbrannoe.setImageResource(R.drawable.icon_star_yellow); } } if(!getFav.isClosed()){ getFav.close(); } } } }); 
  • I tried. Add it turns out, then when I want to delete again writes added to favorites. - Veronica
  • @ Veronica updated the answer, try it - Iman
  • can you give an example? How is this solved? If the second check is removed then how to add words to favorites? - Veronica
  • therefore, I say that the simple option is to store your favorites in SharedPreferences so as not to access the database, it’s easier to contact SP - Iman
  • let me ask so :) there is my database structure, there is a listView with two TextView and Imagebutton. Data is displayed. How would you add / remove from favorites? Without SharedPreferences and other stuff :) - Veronica