I have a problem that I am sitting on for 3 days and I can't think of anything. Namely, I am writing an app for a restaurant where I have a SaladMeterialFragment
activity that displays a CardView
in a RecyclerView
. Everything works as it should when I use the Salad class and extract data from it. However, I need to rewrite my SaladMaterialFragment
to work on data retrieved from DatabaseHelper
. The whole problem is that I do not quite know how these downloaded data attach to my adapter that was prepared under RecyclerView
. How can I retrieve data from cursors and save them in a String []
array because I need it for just the RecyclerView
adapter?
SaladMaterialFragment
activates the SaladDetailFragment
activity, where I was able to fire up the database and everything works as it should. But I have no idea what it should look like with RecyclerView
views? I am a beginner developer and just learning databases, so please be patient and explain the matter. Thank you in advance for your help.
RecyclerAdapter
//I must have a STRING[]
and INT[]
, but cursor return String or int, so how to get data from database in this format: String[] ; int[] ?
// Must I change anything in my adapter class, in here? If I want to use a Database?
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
class RecyclerAdapter extends RecyclerView.Adapter<CaptionedImagesAdapter.ViewHolder> {
private String[] captions;
private int[] imageIds;
private Listener listener;
public static interface Listener {
public void onClick(int position);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private CardView cardView;
public ViewHolder(CardView v) {
super(v);
cardView=v;
}
}
public RecyclerAdapter(String[] captions, int[] imageIds){
this.captions = captions;
this.imageIds = imageIds;
}
public void setListener(Listener listener) {
this.listener = listener;
}
@Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
CardView cv = (CardView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_captioned_image, parent, false);
return new ViewHolder(cv);
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
CardView cardView = holder.cardView;
ImageView imageView = (ImageView)cardView.findViewById(R.id.info_image);
Drawable drawable = cardView.getResources().getDrawable(imageIds[position]);
imageView.setImageDrawable(drawable);
imageView.setContentDescription(captions[position]);
TextView textView = (TextView)cardView.findViewById(R.id.info_text);
textView.setText(captions[position]);
cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener != null) {
listener.onClick(position);
}
}
});
}
@Override
public int getItemCount() {
return captions.length;
}
}
DatabaseHelper
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "miodzio";
private static final int DB_VERSION = 1;
public MiodzioDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE SALAD (_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "NAME TEXT, "
+ "IMAGE_RESOURCE_ID INTEGER, "
+ "FAVORITE INTEGER);");
insertSalad(db, "Sałatka grecka", R.drawable.salatka_grecka, 0);
insertSalatki(db, "Sałatka z grillowanym kurczakiem", R.drawable.salatka_z_kurczakiem, 0);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
private static void insertSalad(SQLiteDatabase db, String name, int resourceId, int favorite){
ContentValues saladValues = new ContentValues();
saladValues.put("NAME", name);
saladValues.put("IMAGE_RESOURCE_ID", resourceId);
saladValues.put("Favorite", favorite);
db.insert("SALAD", null, saladValues);
}
}
Salad.java
// Currently, data for the SaladMaterialFragment is retrieved from this class and everything works // public class Salad {
private String name;
private int imageResourceId;
public static final Salads[] salad = {
new Salatki("Sałatka grecka", R.drawable.salatka_grecka),
new Salatki("Sałatka z grillowanym kurczakiem", R.drawable.salatka_z_kurczakiem)
};
private Salatki(String name, int imageResourceId) {
this.name = name;
this.imageResourceId = imageResourceId;
}
public String getName() {
return name;
}
public int getImageResourceId() {
return imageResourceId;
}
}
SaladDeteilActivity
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.ShareActionProvider;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class SaladDetailActivity extends AppCompatActivity {
public static final String EXTRA_SALATKI = "salatki";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_salatki_detail);
int salatki = (Integer) getIntent().getExtras().get(EXTRA_SALATKI);
/*
The old way of retrieving data is class Salad
*/
/* String salatkiName = Salatki.salatka[salatki].getName();
TextView textView = (TextView) findViewById(R.id.salatki_text);
textView.setText(salatkiName);
int salatkiImage = Salatki.salatka[salatki].getImageResourceId();
ImageView imageView = (ImageView) findViewById(R.id.salatki_image);
imageView.setImageDrawable(getResources().getDrawable(salatkiImage));
imageView.setContentDescription(salatkiName);*/
//We retrieve data from the database, everything works in this class!
try {
SQLiteOpenHelper databaseHelper = new DatabaseHelper(this);
SQLiteDatabase db = databaseHelper.getReadableDatabase();
Cursor cursor = db.query("SALAD",
new String[]{"NAME", "IMAGE_RESOURCE_ID", "FAVORITE"},
"_id = ?",
new String[]{Integer.toString(salatki)},
null, null, null);
if(cursor.moveToNext()) {
String nameText = cursor.getString(0);
int photoId = cursor.getInt(1);
boolean isFavorite = (cursor.getInt(2) == 1);
//Display name salad
TextView name = (TextView) findViewById(R.id.salatki_text);
name.setText(nameText);
//Display photo salad
ImageView photo = (ImageView) findViewById(R.id.salatki_image);
photo.setImageResource(photoId);
photo.setContentDescription(nameText);
//Check it for the favorite
CheckBox favorite = (CheckBox) findViewById(R.id.favorite);
favorite.setChecked(isFavorite);
}
cursor.close();
db.close();
}catch (SQLiteException e){
Toast.makeText(this, "Baza danych niedostępna!", Toast.LENGTH_SHORT).show();
}
// getSupportActionBar().setDisplayHomeAsUpEnabled(true); //przycisk w górę!
Toolbar myChildToolbarZupy = (Toolbar) findViewById(R.id.my_child_toolbar_salatki_detail);
setSupportActionBar(myChildToolbarZupy);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
}
public void onFavoriteClicked(View view) {
int salatki = (Integer) getIntent().getExtras().get(EXTRA_SALATKI);
CheckBox favorite = (CheckBox) findViewById(R.id.favorite);
ContentValues salatkiValues = new ContentValues();
salatkiValues.put("FAVORITE", favorite.isChecked());
SQLiteOpenHelper databaseHelper = new DatabaseHelper(this);
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.update("SALAD", salatkiValues,
"_id = ?", new String[]{Integer.toString(salatki)});
db.close();
}
}
SaladMaterialFragment
*
In this class, there is a problem and my question is how to extract data from the database to display a name and a photo if I am using an adapter and a RecyclerView view. Does it matter?
I need to convert data from the cursor to String []
and int []
, but the cursor does not return these types.*
import android.app.Fragment;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class SalatkiMaterialFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RecyclerView salatkaRecyler = (RecyclerView) inflater.inflate(R.layout.fragment_salatki_material, container, false);
/*
At the moment data is retrieved from the Salad class, I care to be retrieved from DatabaseHelper.
*/
String[] salatkaName = new String[Salatki.salatka.length];
for(int i=0; i<salatkaName.length; i++) {
salatkaName[i] = Salatki.salatka[i].getName();
}
int[] salatkaImage = new int[Salatki.salatka.length];
for(int i=0; i<salatkaImage.length; i++) {
salatkaImage[i] = Salatki.salatka[i].getImageResourceId();
}
//This adapter adopts in the constructor type: String [] and int []
RecyclerAdapter adapter = new RecyclerAdapter(salatkaName, salatkaImage);
salatkaRecyler.setAdapter(adapter);
LinearLayoutManager manager = new LinearLayoutManager(inflater.getContext(), LinearLayoutManager.VERTICAL, false);
salatkaRecyler.setLayoutManager(manager);
adapter.setListener(new CaptionedImagesAdapter.Listener() {
@Override
public void onClick(int position) {
Intent intent = new Intent(getActivity(), SalatkiDetailActivity.class);
intent.putExtra(SalatkiDetailActivity.EXTRA_SALATKI, position);
getActivity().startActivity(intent);
/*
Here I will write my code, which I tried to prick. Of course he does not work, but maybe it will serve to better focus on what exactly I mean.
*/
/*
try {
SQLiteOpenHelper databaseHelper = new DatabaseHelper(inflater.getContext());
SQLiteDatabase db = databaseHelper.getRedableDatabase();
Cursor cursor = db.query("SALAD",
new String[] {"NAME", "IMAGE_RESOURCE_ID"},
null, null, null, null, null);
if(cursor.moveToNext()) {
String name = cursor.getString(0); //But I must have a String[] for RecyclerAdapter?
int photo = cursor.getString(0); ////But I must have a int[] for RecyclerAdapter?
}
db.close();
cursor.close();
}catch(SQLiteException e){
Toast.makeText(inflater.getContext(), "Database does not work!", Toast.LENGTHS_SHORT).show();
}
RecyclerAdapter adapter = new RecyclerAdapter(name, photo); //Here I must have String[] - name AND int[] - resource photo id?
salatkaRecyler.setAdapter(adapter);
LinearLayoutManager manager = new LinearLayoutManager(inflater.getContext(), LinearLayoutManager.VERTICAL, false);
salatkaRecyler.setLayoutManager(manager);
adapter.setListener(new CaptionedImagesAdapter.Listener() {
@Override
public void onClick(int position) {
Intent intent = new Intent(getActivity(), SalatkiDetailActivity.class);
intent.putExtra(SalatkiDetailActivity.EXTRA_SALATKI, position);
getActivity().startActivity(intent);
*/
}
});
return salatkaRecyler;
}
}
first of all it's better to create a Salad class to store your salad data in so the rest of your application won't have to deal with raw string and int data
second you are getting Int and String and not array of those two because the database cursor is reading one line at a time. this is where i suggest u create salad objects and return an array of em
List<Salad> salads = new ArrayList<>();
while(cursor.moveToNext()){
String name = cursor.getString(0);
int photo = cursor.getInt(1);
boolean isFavorite = (cursor.getInt(2) == 1);
Salad salad = new Salad(name,photo,isFavorite);
salads.add(salad);
}
and the recyclerview is ought to be displaying an array of salad rather than an array of strings and ints this way u won't have to rework it should you need to load salad data from other sources