In one class I set the ID to my Warranty class. I added my full code so you can see where it goes wrong. I declare the class so I can call it. Set the ID on the setter and finally I retrieve it on the other class with the getter.
public class HomeActivity extends AppCompatActivity {`
DatabaseHelper db = new DatabaseHelper(this);
LinearLayout buttonViewWarrantys;
Warranty wr = new Warranty();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Display display = getWindowManager().getDefaultDisplay();
int width_display = display.getWidth();
width_display = (width_display/10) * 8;
Button addWarBtn = findViewById(R.id.add_warranty);
buttonViewWarrantys = findViewById(R.id.show_warratys);
addWarBtn.getLayoutParams().width = width_display;
addWarBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent inputScreen = new Intent(HomeActivity.this, InputScreen.class);
startActivity(inputScreen);
}
});
updateWarrantys();
}
#Override
public void onResume() {
super.onResume();
updateWarrantys();
}
void updateWarrantys(){
List<Warranty> warrantys = db.getAllContacts();
for (Warranty cn : warrantys) {
final String ID = Integer.toString(cn.getID());
String buttonName = ID + "_" + cn.getName();
String buttonText = "Name: " + cn.getName() + '\n' + " Bought on: " + cn.getStartDate() + '\n' + " Warranty stops on: " + cn.getEndDate();
Button buttons = new Button(this);
buttons.setTag(buttonName);
buttons.setText(buttonText);
buttons.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
final String warranty_name = cn.getName();
final String start_date = cn.getStartDate();
final String end_date = cn.getEndDate();
final String img_path = cn.getImgFilePath();
buttons.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
System.out.println(ID);
wr.setID(Integer.parseInt(ID));
//new Warranty(Integer.parseInt(ID), warranty_name, start_date, end_date, img_path);
Intent showWarranty = new Intent(HomeActivity.this, ShowWarranty.class);
startActivity(showWarranty);
}
});
buttonViewWarrantys.addView(buttons);
String log = "Id: " + cn.getID() + " ,Name: " + cn.getName() + " ,Startdate: " + cn.getStartDate() + " ,EndDate: " + cn.getEndDate() + " ,Path: " + cn.getImgFilePath();
System.out.println(log);
}
}
}
This is my Warranty class with my setter and getter.
public int getID() {
return ID;
}
public void setID(int ID) {
this.ID = ID;
}
After this I try to retrieve it but the result of the ID is 0 and when I set it it is 8.
public class ShowWarranty extends AppCompatActivity {`
Warranty wr = new Warranty();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_warranty);
int test = wr.getID();
System.out.println("The number is: " + test);
}
}
Why is this not possible?
You create a new instance in both the classes, meaning when you grab it in the second class you haven't set the value on the instance in that class. From what you're describing, the variable is not static, meaning the value depends on the instance. The default value for integer primitives is 0, which is the reason why it has that specific value.
Pseudocode example of what you're doing:
Warranty x = new Warranty();
x.setID(8);
Warranty y = new Warranty();
System.out.println(y.getID());//Since the ID of y isn't set, it'll print 0
As for a possible solution:
If your class is fairly basic, just make it implement Serializable and put it as an extra in the intent. And by "fairly basic" I mean a class that you actually can serialize. Classes like Context cannot be serialized, so you'd need to add a method for adding it back after it's been deserialized and mark unserializable fields as transient. Or just pass the primitives directly.
You can use parcelable instead of Serializable, but that's a matter of preference.
You add the data into the intent. See how to pass primitives. Or if you want to pass an object, you must first flatten it, and then pass the parcelable. Each intent has its own address space
Related
I am running out of ideas as to why my implementation of parcelable does throw ClassCastException. I would like to know why it does throw the exception and find ways on how to fix it.Please let me know if I'm still lacking to give information in order for you guys to help me.
IdModelDTO class
public class IdModelDTO implements Parcelable {
private String type;
private String surname;
private String givenName;
private String middleName;
private String birthDate;
protected IdModelDTO(Parcel in) {
givenName = in.readString();
middleName = in.readString();
surname = in.readString();
birthDate = in.readString();
type = in.readString();
}
public static final Creator<IdModelDTO> CREATOR = new Creator<IdModelDTO(){
#Override
public IdModelDTO createFromParcel(Parcel in) {
return new IdModelDTO(in);
}
#Override
public IdModelDTO[] newArray(int size) {
return new IdModelDTO[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(givenName);
dest.writeString(middleName);
dest.writeString(surname);
dest.writeString(birthDate);
dest.writeString(type);
}
#Override
public String toString() {
return "IdModelDTO{" + "givenName='" + givenName + '\''
+ ", middleName='" + middleName + '\'' +
"surname='" + surname + '\'' +
"birthdate=''" + birthDate + '\'' +
"type='" + type + '\'' + '}';
}
This is where I use it as a bundle. I can even log it as a bundle before sending it to the next activity:
public void checkMplusRespCodes() {
// Check if response codes are OK/Created:
if(governmentIdRespCode == null){
Log.d(TAG, "Government Id Response code: " + governmentIdRespCode );
}
if(saveSelfieResponse == null){
Log.d(TAG, "saveSelfieResponse: " + saveSelfieResponse);
}
else if(governmentIdRespCode != null && saveSelfieResponse != null){
if(governmentIdRespCode.equals("200") && saveSelfieResponse.equals("200")){
//Create bundle here, then pass it to view:
//Bundle idModelBundle = new Bundle();
//idModelBundle.putParcelable(THISIDMODEL, thisIdModel);
//viewContract.showNextActivity(idModelBundle);
Log.d(TAG, " checkMplusRespCodes: " + idModelDTO.toString());
Bundle idModelBundle = new Bundle();
idModelBundle.putParcelable(THISIDMODEL, idModelDTO);
viewContract.showDoneLoading();
viewContract.showNextActivity(idModelBundle);
}
}
Then at the nextactivity, it throws the ClassCastException:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
/* */
Intent previousIntent = getIntent();
if(previousIntent.getExtras() != null){
Bundle previousExtras = previousIntent.getExtras();
if(previousExtras != null){
IdModelDTO test = previousIntent.getParcelableExtra(THISIDMODEL);
if(test != null){
Log.d(TAG, " asd: " + test.toString());
}
/* Retrieve: */
}
}else{
//proceed.
}
Any kind of help will be much appreciated.
EDIT:
This is the log of the method whereas I set the Parcelable object as a bundle:
checkMplusRespCodes: IdModelDTO{givenName='test', middleName='asd'surname='Test'birthdate=''axx'type='asxd'}
The exception occurs at the nextActivity where it's being casted:
IdModelDTO test = previousIntent.getParcelableExtra(THISIDMODEL);
Replace your code with this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test1);
/* */
Intent previousIntent = getIntent();
if(previousIntent.getExtras() != null){
Bundle previousExtras = previousIntent.getExtras();
if(previousExtras != null){
IdModelDTO test = previousExtras.getParcelable(THISIDMODEL);
if(test != null){
Log.d(TAG, " asd: " + test.toString());
}
/* Retrieve: */
}
}else{
//proceed.
}
Okay, I solved this. I was passing casting a Bundle Object into my custom IdModelDTO as you can see in this line:
if(previousExtras != null){
IdModelDTO test = previousIntent.getParcelableExtra(THISIDMODEL);
...
I removed the Bundle part where I put my object inside the bundle, and use the putExtra in order for me to be able to retrieve the object as it's type:
Intent nextActivityIntent = new Intent(this, TestActivityX.class);
nextActivityIntent.putExtra(THISIDMODEL,idModelDTO);
Log.d(TAG, " Show next activity: " + idModelDTO.toString());
startActivity(nextActivityIntent);
Then the retrieval will work on the next activity:
Intent previousIntent = getIntent();
if (previousIntent.getExtras() != null) {
Bundle previousExtras = previousIntent.getExtras();
if (previousExtras != null) {
// Retrieve:
if (previousExtras.containsKey(THISIDMODEL)) {
// Re-instanciate new user.
IdModelDTO test = previousExtras.getParcelable(THISIDMODEL);
Log.d(TAG, " Previous Details:" + test.toString());
}
}
}
Thanks guys, I really appreciate the comments.
I think you are trying to parse date object which is not a String.
That is why you are getting this exception.
Creating an app for seeing pets in the store, where I've created a database and a table called shelter.db and pets respectively. I've created a contract class to store all the constants related to the database, a class called PetDbHelper that extends SQLiteOpenHelper. I have two activities CatalogActivity and EditorActivity. In CatalogActivity, I'm trying to read the table and here I tried to get the column indices of each column but the last column named 'weight' returns -1 which means as you may know 'no column exists' and in EditorActivity, I'm trying to insert pets in the table. I've checked everything but have no clue what's wrong with my code.
Here's the PetContract class:
package com.example.android.pets.data;
import android.provider.BaseColumns;
public final class PetsContract {
public static final class PetEntry implements BaseColumns {
// CONSTANTS FOR TABLE AND COLUMN NAMES
public static final String TABLE_NAME = "pets";
public static final String _ID = BaseColumns._ID;
public static final String COLUMN_PET_NAME = "name";
public static final String COLUMN_PET_BREED = "breed";
public static final String COLUMN_PET_GENDER = "gender";
public static final String COLUMN_PET_WEIGHT = " weight";
// CONSTANTS FOR GENDER
public static final int GENDER_UNKNOWN = 0;
public static final int GENDER_MALE = 1;
public static final int GENDER_FEMALE = 2;
}
}
Here's the PetDbHelper that extends SQLiteOpenHelper class:
package com.example.android.pets.data;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class PetDbHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "shelter.db";
private static final int DATABASE_VERSION = 1;
public PetDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_TABLE = "CREATE TABLE " + PetsContract.PetEntry.TABLE_NAME
+ " (" + PetsContract.PetEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ PetsContract.PetEntry.COLUMN_PET_NAME + " TEXT NOT NULL, "
+ PetsContract.PetEntry.COLUMN_PET_BREED + " TEXT, "
+ PetsContract.PetEntry.COLUMN_PET_GENDER + " INTEGER NOT NULL, "
+ PetsContract.PetEntry.COLUMN_PET_WEIGHT + " INTEGER NOT NULL DEFAULT 0);";
db.execSQL(CREATE_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
Here's the code of CatalogActivity.java that is related to database:
/**
* Displays list of pets that were entered and stored in the app.
*/
public class CatalogActivity extends AppCompatActivity {
private PetDbHelper mDbHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_catalog);
mDbHelper = new PetDbHelper(this);
private void displayDatabaseInfo() {
// To access our database, we instantiate our subclass of
SQLiteOpenHelper
// and pass the context, which is the current activity.
// CREATE AND/OR OPEN A DATABASE TO READ FROM IT
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// String[] projection = {PetEntry._ID, PetEntry.COLUMN_PET_NAME, PetEntry.COLUMN_PET_BREED, PetEntry.COLUMN_PET_GENDER, PetEntry.COLUMN_PET_WEIGHT};
Cursor cursor = db.query(PetEntry.TABLE_NAME, null, null, null, null, null, null);
//Cursor cursor = db.rawQuery("SELECT * FROM pets", null);
TextView displayView = (TextView) findViewById(R.id.text_view_pet);
try {
// Create a header in the Text View that looks like this:
//
// The pets table contains <number of rows in Cursor> pets.
// _id - name - breed - gender - weight
//
// In the while loop below, iterate through the rows of the cursor and display
// the information from each column in this order.
displayView.setText("The pets table contains " + cursor.getColumnCount() + " pets.\n\n");
displayView.append(PetEntry._ID + " - " +
PetEntry.COLUMN_PET_NAME + " - " +
PetEntry.COLUMN_PET_BREED + " - " +
PetEntry.COLUMN_PET_GENDER + " - " +
PetEntry.COLUMN_PET_WEIGHT );
// Figure out the index of each column
int idColumnIndex = cursor.getColumnIndex(PetEntry._ID);
int nameColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_NAME);
int breedColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_BREED);
int genderColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_GENDER);
int weightColumnIndex = cursor.getColumnIndex(PetEntry.COLUMN_PET_WEIGHT);
Toast.makeText(this,
"weight_index ?" + weightColumnIndex + "\n"
+ "id_index" + idColumnIndex + "\n"
+ "name_index" + nameColumnIndex + "\n"
+ "breed_index" + breedColumnIndex + "\n"
+ "gender_index" + genderColumnIndex , Toast.LENGTH_LONG).show();
} finally {
// Always close the cursor when you're done reading from it. This releases all its
// resources and makes it invalid.
cursor.close();
}
}
#Override
protected void onStart() {
super.onStart();
displayDatabaseInfo();
}
I know that's a lot of code, and here's the last piece of code of EditorActivity.java class: (excluded the code related to spinner object)
**
* Allows user to create a new pet or edit an existing one.
*/
public class EditorActivity extends AppCompatActivity {
/** EditText field to enter the pet's name */
private EditText mNameEditText;
/** EditText field to enter the pet's breed */
private EditText mBreedEditText;
/** EditText field to enter the pet's weight */
private EditText mWeightEditText;
/** EditText field to enter the pet's gender */
private Spinner mGenderSpinner;
/**
* Gender of the pet. The possible values are:
* 0 for unknown gender, 1 for male, 2 for female.
*/
private int mGender = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_editor);
// Find all relevant views that we will need to read user input from
mNameEditText = (EditText) findViewById(R.id.edit_pet_name);
mBreedEditText = (EditText) findViewById(R.id.edit_pet_breed);
mWeightEditText = (EditText) findViewById(R.id.edit_pet_weight);
mGenderSpinner = (Spinner) findViewById(R.id.spinner_gender);
}
private void addPet() {
String name = mNameEditText.getText().toString().trim();
String breed = mBreedEditText.getText().toString().trim();
int weight = Integer.parseInt(mWeightEditText.getText().toString().trim());
ContentValues values = new ContentValues();
values.put(COLUMN_PET_NAME, name);
values.put(COLUMN_PET_BREED, breed);
values.put(COLUMN_PET_GENDER, mGender);
values.put(COLUMN_PET_WEIGHT, weight);
PetDbHelper mDbHelper = new PetDbHelper(this);
SQLiteDatabase db = mDbHelper.getWritableDatabase();
long result = db.insert(TABLE_NAME, null, values);
if (result != -1) {
Toast.makeText(this, "Pet saved with id: " + result, Toast.LENGTH_SHORT).show();
} else {Toast.makeText(this, "Error with saving pet", Toast.LENGTH_SHORT).show();}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu options from the res/menu/menu_editor.xml file.
// This adds menu items to the app bar.
getMenuInflater().inflate(R.menu.menu_editor, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// User clicked on a menu option in the app bar overflow menu
switch (item.getItemId()) {
// Respond to a click on the "Save" menu option
case R.id.action_save:
// Save pet into the database
addPet();
// Exit the activity
finish();
return true;
// Respond to a click on the "Delete" menu option
case R.id.action_delete:
// Do nothing for now
return true;
// Respond to a click on the "Up" arrow button in the app bar
case android.R.id.home:
// Navigate back to parent activity (CatalogActivity)
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
}
Leading whitespace is ignored in SQL but it matters in map keys - column names and their indices are essentially stored in a map you can access with getColumnIndex().
public static final String COLUMN_PET_WEIGHT = " weight";
Remove the leading whitespace here.
I'm working on Android Studio Project for my university (app calendar and more), and one of the functionalities is touch in a day of a calendar (CalendarView), display a layout for add event and later the event is saved in a SQLITE, (in another activity is where the list of events is displayed) the problem is when I want to delete an event (java.lang.ArrayIndexOutOfBoundsException: length=5; index=5).
In Viewevents eliminar(String dato) is the code with error, How do I fix the issue? Thanks.
View events:
public class ViewEventsActivity extends AppCompatActivity implements AdapterView.OnItemLongClickListener {
//al mantener la wea apretada
private SQLiteDatabase db;
private ListView listView;
private ArrayAdapter<String> arrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_events);
listView=(ListView) findViewById(R.id.ltvListaEventos);
listView.setOnItemLongClickListener(this);
Bundle bundle= getIntent().getExtras();
int dia,mes,anio;
dia=mes=anio=0;
dia=bundle.getInt("dia");
mes=bundle.getInt("mes");
anio=bundle.getInt("anio");
String cadena= dia+" - "+ mes + " - "+ anio;
BDSQLite bd= new BDSQLite(getApplicationContext(), "eventos", null,1);
db= bd.getReadableDatabase();
String sql="select * from eventos where fechadesde='"+cadena+"'";
Cursor c;
String nombre,fechadesde,horadesde,fechahasta,horahasta,descripcion,ubicacion;
try {
c=db.rawQuery(sql,null);
arrayAdapter= new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1);
if(c==null||c.getCount()==0) {
Toast.makeText(getBaseContext(), "No hay eventos disponibles", Toast.LENGTH_LONG).show();
}
if(c.moveToFirst()){
do {
nombre=c.getString(1);
ubicacion=c.getString(2);
fechadesde=c.getString(3);
horadesde=c.getString(4);
fechahasta=c.getString(5);
horahasta=c.getString(6);
descripcion=c.getString(7);
arrayAdapter.add(nombre+", "+ubicacion+", "+fechadesde+", "+horadesde+", "+fechahasta+", "+horahasta+", "+descripcion);
} while(c.moveToNext());
listView.setAdapter(arrayAdapter);
}
}catch (Exception ex) {
Toast.makeText(getApplication(), "Error: "+ex.getMessage(), Toast.LENGTH_SHORT).show();
this.finish();
}
}
private void eliminar(String dato){
String []datos= dato.split(", ");
String sql="delete from eventos where nombreEvento='"+datos[0]+"' and" +
" ubicacion='"+datos[1]+"' and fechadesde='"+datos[2]+"' and " +
"horadesde='"+datos[3]+"' and fechahasta='"+datos[4]+"' and horahasta='"+datos[5]+"' and descripcion='"+datos[6];
try {
arrayAdapter.remove(dato); //eliminar del menú
listView.setAdapter(arrayAdapter);
db.execSQL(sql);
Toast.makeText(getApplication(),"Evento eliminado",Toast.LENGTH_SHORT).show();
}catch (Exception ex){
Toast.makeText(getApplication(),"Error:"+ ex.getMessage(), Toast.LENGTH_SHORT).show();
}
}
#Override
public boolean onItemLongClick(final AdapterView<?> adapterView, View view, int i, long l) {
AlertDialog.Builder builder= new AlertDialog.Builder(this);
CharSequence []items= new CharSequence[2];
items[0]="Eliminar Evento";
items[1]="Cancelar";
builder.setTitle("Eliminar evento")
.setItems(items, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int i) {
if(i==0){
//eliminar evento
eliminar(adapterView.getItemAtPosition(i).toString());
}
}
});
AlertDialog dialog= builder.create();
dialog.show();
return false;
}
}
BDSQlite:
public class BDSQLite extends SQLiteOpenHelper {
private String sql = "create table eventos(" +
"idEvento int identity,"+
"nombreEvento varchar(40)," +
"ubicacion varchar(60)," +
"fechadesde date,"+
"horadesde time,"+
"fechahasta date,"+
"horahasta time," +
"descripcion varchar(60))";
Add event activity
public class AddActivity extends AppCompatActivity implements View.OnClickListener {
private EditText nombreEvento, ubicacion, fechadesde, horadesde, fechahasta, horahasta;
private EditText descripcion;
private Button guardar, cancelar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add);
nombreEvento = (EditText) findViewById(R.id.edtNombreEvento);
ubicacion = (EditText) findViewById(R.id.edtUbicacion);
fechadesde = (EditText) findViewById(R.id.edtFechaDesde);
fechahasta = (EditText) findViewById(R.id.edtFechaHasta);
horadesde = (EditText) findViewById(R.id.edtHorainicio);
horahasta = (EditText) findViewById(R.id.edtHoraHasta);
descripcion = (EditText) findViewById(R.id.edtDescripcion);
Bundle bundle = getIntent().getExtras();
int dia = 0, mes = 0, anio = 0;
dia=bundle.getInt("dia");
mes=bundle.getInt("mes");
anio=bundle.getInt("anio");
fechadesde.setText(dia + " - " + mes + " - " + anio);
fechahasta.setText(dia + " - " + mes + " - " + anio);
guardar = (Button) findViewById(R.id.btnguardar);
cancelar = (Button) findViewById(R.id.btncancelar);
guardar.setOnClickListener(this);
cancelar.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (v.getId() == guardar.getId()) {
//guardar datos cajas de texto
BDSQLite bd = new BDSQLite(getApplication(), "eventos", null, 1);
SQLiteDatabase db = bd.getWritableDatabase();
String sql = "insert into eventos" +
"(nombreEvento, ubicacion, fechadesde, horadesde, fechahasta, horahasta," +
"descripcion) values('" +
nombreEvento.getText()+
"','"+ ubicacion.getText()+
"','" +fechadesde.getText()+
"','" + horadesde.getText()+
"','"+fechahasta.getText()+
"','"+horahasta.getText()+
"','"+descripcion.getText();
try {
db.execSQL(sql);
nombreEvento.setText("");
ubicacion.setText("");
fechadesde.setText("");
fechahasta.setText("");
horadesde.setText("");
horahasta.setText("");
descripcion.setText("");
Toast.makeText(getBaseContext(), "Evento guardado", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(getApplication(),"Error"+e.getMessage(),Toast.LENGTH_SHORT).show();
}
} else {
this.finish();
return;
}
}
}
ERROR:
java.lang.ArrayIndexOutOfBoundsException: length=5; index=5
at com.example.niikoo.fondocelular.ViewEventsActivity.eliminar(ViewEventsActivity.java:87)
at com.example.niikoo.fondocelular.ViewEventsActivity.access$000(ViewEventsActivity.java:17)
at com.example.niikoo.fondocelular.ViewEventsActivity$1.onClick(ViewEventsActivity.java:116)
EDIT: The code with the structure of sql and datos, how i fix the error:(
Exception line (java.lang.ArrayIndexOutOfBoundsException: length=5; index=5) clearly mentions that you are Trying to get index=5but the length of the dato is 5(length=5).
So, use only proper index i.e. index 0 to 4. OR Make sure that enough indexes exists to access.
Note: You have used dato.split(", ");. Try with dato.split(",");. May be the problem is with pattern of splitter.
It looks like your String dato which you are splitting by commas to an array may not be the length that you think. The error is showing 5 items in the array, so the greatest index you can access in that case would be datos[4] since arrays are 0-based.
Debug your array after you split:
String []datos= dato.split(", ");
Check the input of this method, it's not in the code.
eliminar(adapterView.getItemAtPosition(i).toString());
The error you get occurs because the array you get after splitting the String has only 5 elements (4 commas):
private void eliminar(String dato) {
String []datos= dato.split(", ");
...
But then you try to get the 6th (index 5) and 7th (index 6) elements from that array:
datos[5]+"' and descripcion='"+datos[6];
There are no such elements, therefore you get this ArrayIndexOutOfBoundsException error.
To fix, try to find the input of your adapterView.
EDIT: In this line 2 Strings appear to be empty:
arrayAdapter.add(nombre+", "+ubicacion+", "+fechadesde+", "+horadesde+", "+fechahasta+", "+horahasta+", "+descripcion);
Hence, when you get a ", , " and split it with split(", ") it doesn't count the "" String and you get less items in the resulting array, which leads to the error.
I know for sure that the updateFromDatabase() function works, I've used print statements to see that the entries put into mCoordinatesArray are there and not empty strings. However when I restart the app, the fragment never populates the list view with items in the database. I think it has something to do with the Fragment Lifecycle, but I have no idea.
Additionally, when I don't restart the app and run it for the first time the list view runs fine. When I rotate or restart the app, the list view no longer populates.
public class LocalFragment extends Fragment{
private ListView mLocalList;
private ArrayAdapter<String> adapter;
private ArrayList<String> mCoordinatesArray;
private BroadcastReceiver mBroadcastReceiver;
private LocationBaseHelper mDatabase;
private DateFormat dateFormat;
private String dateString;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.fragment_local,container,false);
// SQLite Setup
mDatabase = new LocationBaseHelper(getActivity());
mLocalList = (ListView) v.findViewById(R.id.lv_local);
mCoordinatesArray = new ArrayList<>();
adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, mCoordinatesArray);
if(!mDatabase.size().equals("0")){
updateFromDatabase();
}
mLocalList.setAdapter(adapter);
return v;
}
#Override
public void onResume() {
super.onResume();
if(mBroadcastReceiver == null){
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
dateFormat = new SimpleDateFormat("MM/dd HH:mm:ss a");
dateString = dateFormat.format(new Date());
String[] data = intent.getStringExtra("coordinates").split(" ");
mDatabase.insertEntry(dateString,data[0],data[1]);
System.out.println(mDatabase.size());
mCoordinatesArray.add(dateString + " " + data[0] + " " + data[1]);
adapter.notifyDataSetChanged();
}
};
}
getActivity().registerReceiver(mBroadcastReceiver, new IntentFilter("location_update"));
}
#Override
public void onDestroy() {
super.onDestroy();
if(mBroadcastReceiver!=null){
getActivity().unregisterReceiver(mBroadcastReceiver);
}
}
// THIS METHOD CAN BE USED TO UPDATE THE ARRAY HOLDING COORDINATES FROM THE LOCAL DATABASE
private void updateFromDatabase(){
//mCoordinatesArray.clear();
mCoordinatesArray = mDatabase.getEntireDatabase();
adapter.notifyDataSetChanged();
}
}
Here's my Helper class, just in case, but I don't think the problem is here.
public class LocationBaseHelper extends SQLiteOpenHelper {
private static final int VERSION = 1;
private static final String DATABASE_NAME = "locationBase.db";
public LocationBaseHelper(Context context) {
super(context, DATABASE_NAME, null, VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table " + LocationTable.NAME + " (" +
LocationTable.Cols.DATE_TIME + " text, " +
LocationTable.Cols.LATITUDE + " text, " +
LocationTable.Cols.LONGITUDE + " text )"
);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void insertEntry(String date_time, String latitude, String longitude){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues content = new ContentValues();
content.put(LocationTable.Cols.DATE_TIME,date_time);
content.put(LocationTable.Cols.LATITUDE,latitude);
content.put(LocationTable.Cols.LONGITUDE,longitude);
db.insert(LocationTable.NAME,null,content);
}
public ArrayList<String> getEntireDatabase(){
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM " + LocationTable.NAME,null);
cursor.moveToFirst();
ArrayList<String> values = new ArrayList<>();
do{
String value = (String) cursor.getString(cursor.getColumnIndex(LocationTable.Cols.DATE_TIME)) + " " +
(String) cursor.getString(cursor.getColumnIndex(LocationTable.Cols.LATITUDE)) + " " +
(String) cursor.getString(cursor.getColumnIndex(LocationTable.Cols.LONGITUDE));
values.add(0,value);
}while(cursor.moveToNext());
return values;
}
public String size(){
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT COUNT(*) FROM " + LocationTable.NAME,null);
cursor.moveToFirst();
return cursor.getString(0);
}
}
By calling mCoordinatesArray = mDatabase.getEntireDatabase(); you are changing the reference of mCoordinatesArray, and adapter is still holding the old reference, so it does not see any changes.
Instead of creating new instance of mCoordinateArray, you should rather just update values it contains, something like:
mCoordinateArray.clear();
mCoordinateArray.addAll(mDatabase.getData());
adapter.notifyDataSetChange();
That way you are changing the data that is referenced by adapter, instead of creating completely new set of data which the adapter is not aware of.
Try to recreate your ArrayAdapter instead of using .notifyDataSetChanged():
// update Data
mCoordinatesArray = mDatabase.getEntireDatabase();
// create new adapter with new updated array
adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, mCoordinatesArray);
// set adapter for the listview
mLocalList.setAdapter(adapter);
You can put this method in your fragment and call from activity that attach to fragment.
public void updateList(List<?> result) {
if (multimediaListRent.size()>0) {
multimediaGridView.setAdapter(gridMediaListAdapter);
multimediaListRent.clear();
}
gridMediaListAdapter.notifyDataSetChanged();
}
For my software engineering class, we have to incorporate an SQLite database into our application project.
For our application this database class has to be accessible from multiple activities. I have turned the Database class into a singleton and then call
DBInterface database = Database.getInstance(this)
to set a variable to reference the database in order to access its methods in each necessary class and it works. However, we are supposed to utilize dependency injections into our code and my professor has specifically told us that it should be possible to switch from our database class to a stub database we used in a previous iteration by only changing one line of code.
Obviously this means changing the above to
DBInterface database = StubDB.getInstance(this)
However in doing this I still have to make this change in each of the activities that uses the database methods.
So my question is this: is there a way to initialize my database in our init activity and then pass a reference to each necessary activity without the assignment code above?
Relevant Code
Singleton Database Class
public class RecipeDatabase extends Activity implements DBInterface {
private dbHelper Helper;
private static RecipeDatabase sInstance;
private static Context sContext;
public static synchronized RecipeDatabase getInstance(Context context){
if(sInstance == null){
sInstance = new RecipeDatabase(context.getApplicationContext());
}
return sInstance;
}
private RecipeDatabase(Context context){
Helper = new dbHelper(context);
sContext = context;
}
#Override
public void addRecipe(Recipe recipe)
{
String ingredients = recipe.ingredientString();
String directions = recipe.directionString();
SQLiteDatabase db = Helper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(Recipe.KEY_rID, recipe.getrID());
values.put(Recipe.KEY_mealtype, recipe.getMealType());
values.put(Recipe.KEY_mainingredient, recipe.getMainIngredient());
values.put(Recipe.KEY_description, recipe.getDescription());
values.put(Recipe.KEY_ingredients, ingredients);
values.put(Recipe.KEY_directions, directions);
values.put(Recipe.KEY_notes, recipe.getNotes());
values.put(Recipe.KEY_rating, recipe.getRating());
values.put(Recipe.KEY_cooktime, recipe.getCooktime());
db.insert(Recipe.TABLE, null, values);
db.close();
}
#Override
public void editRecipe(Recipe recipe)
{
SQLiteDatabase db = Helper.getWritableDatabase();
ContentValues values = new ContentValues();
String ingredients = recipe.ingredientString();
String directions = recipe.directionString();
values.put(Recipe.KEY_rID, recipe.getrID());
values.put(Recipe.KEY_mealtype, recipe.getMealType());
values.put(Recipe.KEY_mainingredient, recipe.getMainIngredient());
values.put(Recipe.KEY_description, recipe.getDescription());
values.put(Recipe.KEY_ingredients, ingredients);
values.put(Recipe.KEY_directions, directions);
values.put(Recipe.KEY_notes, recipe.getNotes());
values.put(Recipe.KEY_rating, recipe.getRating());
values.put(Recipe.KEY_cooktime, recipe.getCooktime());
db.update(Recipe.TABLE, values, Recipe.KEY_rID + " = ?", new String[]{String.valueOf(recipe.getrID())});
db.close();
}
#Override
public void deleteRecipe(Recipe recipe)
{
SQLiteDatabase db = Helper.getWritableDatabase();
db.delete(Recipe.TABLE, Recipe.KEY_rID + " = ", new String[]{String.valueOf(recipe.getrID())});
db.close();
}
public ArrayList<Recipe> getList()
{
ArrayList<Recipe> result = new ArrayList<>();
SQLiteDatabase db = Helper.getReadableDatabase();
String selectQuery = "SELECT " + Recipe.KEY_rID + ", " +
Recipe.KEY_name + ", " +
Recipe.KEY_mealtype + ", " +
Recipe.KEY_mainingredient + ", " +
Recipe.KEY_description + ", " +
Recipe.KEY_ingredients + ", " +
Recipe.KEY_directions + ", " +
Recipe.KEY_notes + ", " +
Recipe.KEY_rating + ", " +
Recipe.KEY_cooktime + " FROM " + Recipe.TABLE;
Cursor cursor = db.rawQuery(selectQuery, null);
if(cursor.moveToFirst()) {
do {
ArrayList<String> ingredients = new ArrayList<>(); // Temp Storage
ArrayList<String> directions = new ArrayList<>(); // Temp Storage
String tempIngredient = cursor.getString(cursor.getColumnIndex(Recipe.KEY_ingredients));
String[] temp = tempIngredient.split("- "); //Split up ingredients to individual strings
for(int x=0; x < temp.length; x++) {
ingredients.add(temp[x]);
}
String tempDirection = cursor.getString(cursor.getColumnIndex(Recipe.KEY_ingredients));
temp = tempDirection.split("- ");//split up directions into individual strings
for(int x=0; x < temp.length; x++) {
directions.add(temp[x]);
}
//Get Values for Recipe Object
int rID = cursor.getInt(cursor.getColumnIndex(Recipe.KEY_rID));
String name = cursor.getString(cursor.getColumnIndex(Recipe.KEY_name));
String mealType = cursor.getString(cursor.getColumnIndex(Recipe.KEY_mealtype));
String mainIngredient = cursor.getString(cursor.getColumnIndex(Recipe.KEY_mainingredient));
int rating = cursor.getInt(cursor.getColumnIndex(Recipe.KEY_rating));
String description = cursor.getString(cursor.getColumnIndex(Recipe.KEY_description));
int cooktime = cursor.getInt(cursor.getColumnIndex(Recipe.KEY_cooktime));
String notes = cursor.getString(cursor.getColumnIndex(Recipe.KEY_notes));
//Create new Recipe from Row
Recipe tempRecipe = new Recipe(rID, name, description, mealType, mainIngredient,
rating, cooktime, notes, ingredients, directions);
//Add the recipe to the ArrayList
result.add(tempRecipe);
}while (cursor.moveToNext());
}
//Return the populated ArrayList for use
return result;
}
}
Init Class
public class init extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_init);
//The code to change to switch from stub to database
DBInterface repository = RecipeDatabase.getInstance(this);
//DBInterface repository = new StubDB(this);
ArrayList<Recipe> recipes = repository.getList();
ArrayList<String> recipeDisplay = new ArrayList<>();
for(int i=0; i<recipes.size(); i++) {
recipeDisplay.add(recipes.get(i).getName());
}
ArrayAdapter<String> myArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, recipeDisplay);
ListView lv = this.getListView();
lv.setAdapter(myArrayAdapter);
}
#Override
protected void onListItemClick(ListView l, View v, int pos, long id){
super.onListItemClick(l, v, pos, id);
Intent myIntent = new Intent(this, Details.class);
myIntent.putExtra("recipePosition", pos);
startActivity(myIntent);
}
public void shoppingListButton(View view){
startActivity(new Intent(this, ShoppingList.class));
}
public void addRecipeButton(View view){
Intent myIntent = new Intent(this, Edit.class);
myIntent.putExtra("editType", 1); // 1 corresponds to add recipe
startActivity(myIntent);
}
}
One of the Activity Classes that needs the DB methods
public class Details extends ListActivity {
int recipePosition = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
//want to avoid this call
DBInterface repository = RecipeDatabase.getInstance(this);
recipePosition = getIntent().getIntExtra("recipePosition", 0);
Recipe clickedRecipe = repository.getList().get(recipePosition);
ArrayList<String> recipeDetails = new ArrayList<>();
recipeDetails.add(clickedRecipe.getName());
recipeDetails.add(clickedRecipe.getDescription());
recipeDetails.add("Ingredients:");
for(int i=0; i<clickedRecipe.getIngredients().size(); i++){
recipeDetails.add(clickedRecipe.getIngredients().get(i));
}
recipeDetails.add("Instructions:");
for(int i=0; i<clickedRecipe.getDirections().size(); i++){
recipeDetails.add(clickedRecipe.getDirections().get(i));
}
ArrayAdapter<String> myArrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, recipeDetails);
ListView lv = this.getListView();
lv.setAdapter(myArrayAdapter);
}
public void editButton(View view){
Intent myIntent = new Intent(this, Edit.class);
myIntent.putExtra("recipePosition", recipePosition);
myIntent.putExtra("editType", 2); // 2 corresponds to modify recipe
startActivity(myIntent);
}
}
Database Helper Class
public class dbHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "ROSE.db";
public dbHelper(Context context){
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db){
//Creates the Recipe Table which stores recipes
String CREATE_TABLE_RECIPES = "CREATE TABLE " + Recipe.TABLE +
"(" + Recipe.KEY_rID + " INTEGER PRIMARY KEY, " +
Recipe.KEY_name + " TEXT, " +
Recipe.KEY_mealtype + " TEXT, " +
Recipe.KEY_mainingredient + " TEXT, " +
Recipe.KEY_description + " TEXT, " +
Recipe.KEY_ingredients + " TEXT, " +
Recipe.KEY_directions + " TEXT, " +
Recipe.KEY_notes + " TEXT, " +
Recipe.KEY_rating + " INTEGER, " +
Recipe.KEY_cooktime + " INTEGER )";
db.execSQL(CREATE_TABLE_RECIPES);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
db.execSQL("DROP TABLE IF EXISTS recipes" );
onCreate(db);
}
}
Dagger2 is the perfect thing for you. It's really easy to use, just follow the instructions they provide in the docs and you'll love it once you figure it out.
Basically you're going to use
#Inject
DBInterface database;
In every activity, fragment, service, or anywhere you wanna use the database.
Then you will create a DatabaseModule which will have a method that provides the database for injection.
#Singleton
#Provides static DBInterface provideDatabase() {
return new WhateverDatabaseImplementsDBInterface();
}
As you can see, just adding #Singleton will make it a singleton. And now changing the database you use is truly a one line change.
Dagger2 is the greatest thing you will encounter for dependency injection for sure, just setup it correctly, write if you have any trouble (but you shouldn't, with their thorough instructions).
You can use the SQLiteOpenHelper. It will make sure all your activities access the same database. Even if you have different database helper objects in each Activity, they all access the same database.