2015-08-10 2 views
0

Я делаю приложение, которое хранит личную информацию в базе данных SQLite и отображает данные в формате TableLayout в действии. Чтобы реализовать идею, я создал несколько файлов до сих пор, и они выглядят следующим образом.Android: исключение IllegalException при работе с курсором

(1) AddAPersonActivity.java: Этот класс принимает входное значение, сохраняет его в базе данных SQLite и добавляет строку с данными в таблицу, которая будет отображаться в ViewGroupActivity.

(2) ViewGroupActivity.java: Этот класс показывает таблицу, в которой хранятся личные данные.

(3) SQLController.java: Этот класс определяет методы открытия и закрытия базы данных SQLite, вставки данных и чтения записи.

(4) SQLiteHandler.java: Этот класс расширяет класс SQLiteOpenHelper и занимается созданием базы данных и таблицы.

Коды следующие.

(1) AddAPersonActivity.java

public class AddAPersonActivity extends Activity implements View.OnClickListener, AdapterView.OnItemSelectedListener, RadioGroup.OnCheckedChangeListener { 
    private Button btnAdd; 
    private EditText etName; 
    private TextView tvDob; 
    private Spinner spNationality; 
    private RadioButton rbMale, rbFemale; 
    private Calendar birthday; 
    private NameValidator nameValidator; 
    private RadioGroup rgGenderGroup; 
    private TableLayout tlViewGroup; 
    private String gender = ""; 
    private SQLController sqlController; 
    private ProgressDialog progressDialog; 
    private Person person; 

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

     btnAdd = (Button) findViewById(R.id.btnAdd); 
     etName = (EditText) findViewById(R.id.etName); 
     tvDob = (TextView) findViewById(R.id.tvDob); 
     spNationality = (Spinner) findViewById(R.id.spNationality); 
     rbMale = (RadioButton) findViewById(R.id.rbMale); 
     rbFemale = (RadioButton) findViewById(R.id.rbFemale); 
     rgGenderGroup = (RadioGroup) findViewById(R.id.rgGenderGroup); 
     tlViewGroup = (TableLayout) findViewById(R.id.tlViewGroup); 

     // Build a table 
     sqlController = new SQLController(this); 
     buildTable(); 

     // Initialise the NameValidator 
     nameValidator = new NameValidator(); 

     birthday = Calendar.getInstance(); 

     // Import countries into spNationality 
     Locale[] locales = Locale.getAvailableLocales(); 
     ArrayList<String> countries = new ArrayList<>(); 
     for(Locale locale: locales) { 
      String country = locale.getDisplayCountry(); 
      if(country.trim().length() > 0 && !countries.contains(country)) { 
       countries.add(country); 
      } 
     } 

     Collections.sort(countries); 
     for(String country: countries) { 
      System.out.println(country); 
     } 

     ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, countries); 
     dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 

     spNationality.setAdapter(dataAdapter); 
     spNationality.setSelection(0); 

     spNationality.setOnItemSelectedListener(this); 
     tvDob.setOnClickListener(this); 
     rgGenderGroup.setOnCheckedChangeListener(this); 
     btnAdd.setOnClickListener(this); 
    } 

    void updateLabel() { 
     String format = "MM/dd/yy"; 
     SimpleDateFormat dateFormat = new SimpleDateFormat(format, Locale.US); 
     tvDob.setText(dateFormat.format(birthday.getTime())); 
    } 

    @Override 
    public void onClick(View v) { 
     switch(v.getId()) { 
      case R.id.btnAdd: 

       // Create an instance of a person 
       person = new Person(); 

       // set person's name 
       String name = etName.getText().toString(); 
       person.setName(name); 

       // set person's age 
       Calendar today = Calendar.getInstance(); 
       int age = today.get(Calendar.YEAR) - today.get(Calendar.YEAR); 
       if(today.get(Calendar.MONTH) < birthday.get(Calendar.MONTH)) { 
        age--; 
       } else if(today.get(Calendar.MONTH) == birthday.get(Calendar.MONTH) && today.get(Calendar.DAY_OF_MONTH) < birthday.get(Calendar.DAY_OF_MONTH)) { 
        age--; 
       } 
       person.setAge(age); 

       // set person's nationality 
       String nationality = spNationality.getSelectedItem().toString(); 
       person.setNationality(nationality); 

       // set person's created time 
       DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); 
       java.util.Date currentDate = new java.util.Date(); 
       Date currentTime = new Date(currentDate.getTime()); 
       String created_at = dateFormat.format(currentTime); 
       person.setCreated_at(created_at); 

       if(!(name.length() > 0)) { 
        Toast.makeText(this, "Please don't leave the name empty.", Toast.LENGTH_LONG).show(); 
       } else if(!(tvDob.getText().toString().length() > 0)) { 
        Toast.makeText(this, "Please set a valid birthday.", Toast.LENGTH_LONG).show(); 
       } else if(birthday.getTime().compareTo(new java.util.Date()) > 0) { 
        Toast.makeText(this, "Wrong birthday. Please set the valid birthday again.", Toast.LENGTH_LONG).show(); 
       } else if(!(rbMale.isChecked() || rbFemale.isChecked())) { 
        Toast.makeText(this, "Please choose your gender.", Toast.LENGTH_LONG).show(); 
       } else if(!nameValidator.validate(etName.getText().toString())) { 
        Toast.makeText(this, "Wrong name. Please enter a proper name.", Toast.LENGTH_LONG).show(); 
       } else { 
        Toast.makeText(this, "New person is added to the database!", Toast.LENGTH_LONG).show(); 
        new MyAsync().execute(); 
       } 
       break; 

      case R.id.tvDob: 

       // Create a DatePickerDialog and store date info into the birthday variable. 
       DatePickerDialog.OnDateSetListener date = new DatePickerDialog.OnDateSetListener() { 

        @Override 
        public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { 
         birthday.set(Calendar.YEAR, year); 
         birthday.set(Calendar.MONTH, monthOfYear); 
         birthday.set(Calendar.DAY_OF_MONTH, dayOfMonth); 
         updateLabel(); 
        } 
       }; 
       new DatePickerDialog(this, date, birthday.get(Calendar.YEAR), birthday.get(Calendar.MONTH), birthday.get(Calendar.DAY_OF_MONTH)).show(); 
       break; 
     } 
    } 

    void addDataToRow(Person person) { 

    } 

    @Override 
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 

    } 

    @Override 
    public void onNothingSelected(AdapterView<?> parent) { 

    } 

    @Override 
    public void onCheckedChanged(RadioGroup group, int checkedId) { 
     switch(checkedId) { 
      case(R.id.rbMale): 
       gender = "M"; 
       break; 
      case(R.id.rbFemale): 
       gender = "F"; 
       break; 
     } 
    } 


    void buildTable() { 
     sqlController.open(); 
     Cursor cursor = sqlController.readEntry(); 
     int rows = cursor.getCount(); 
     int columns = cursor.getCount(); 
     cursor.moveToFirst(); 

     // Outer for loop 
     for(int i=1; i<rows; i++) { 
      TableRow row = new TableRow(this); 
      row.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 

      // Inner for loop 
      for(int j=0; j<columns; j++) { 
       TextView textView = new TextView(this); 
       textView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); 
       textView.setGravity(Gravity.CENTER); 
       textView.setTextSize(10); 
       textView.setPadding(0, 5, 0, 5); 
       textView.setText(cursor.getString(j)); 
       row.addView(textView); 
      } 

      cursor.moveToNext(); 
      tlViewGroup.addView(row); 
     } 
     sqlController.close(); 
    } 


    private class MyAsync extends AsyncTask<Void, Void, Void> { 

     @Override 
     protected void onPreExecute() { 
      super.onPreExecute(); 
      tlViewGroup.removeAllViews(); 

      progressDialog = new ProgressDialog(getApplicationContext()); 
      progressDialog.setTitle("Please wait"); 
      progressDialog.setMessage("Loading"); 
      progressDialog.setCancelable(false); 
      progressDialog.show(); 
     } 

     @Override 
     protected Void doInBackground(Void... params) { 
      sqlController.open(); 
      sqlController.insertData(person); 
      return null; 
     } 

     @Override 
     protected void onPostExecute(Void result) { 
      super.onPreExecute(); 
      buildTable(); 
      progressDialog.dismiss(); 
     } 
    } 
} 

(2) ViewGroupActivity.java

public class ViewGroupActivity extends Activity implements View.OnClickListener { 
    private TableLayout tlViewGroup; 
    private TextView tvName, tvAge, tvNationality, tvGender, tvCreatedAt; 

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

     tlViewGroup = (TableLayout) findViewById(R.id.tlViewGroup); 
     tvName = (TextView) findViewById(R.id.tvName); 
     tvAge = (TextView) findViewById(R.id.tvAge); 
     tvNationality = (TextView) findViewById(R.id.tvNationality); 
     tvGender = (TextView) findViewById(R.id.tvGender); 
     tvCreatedAt = (TextView) findViewById(R.id.tvCreatedAt); 

     tvName.setOnClickListener(this); 
     tvAge.setOnClickListener(this); 
     tvNationality.setOnClickListener(this); 
     tvGender.setOnClickListener(this); 
     tvCreatedAt.setOnClickListener(this); 
    } 

    @Override 
    public void onClick(View v) { 
     switch(v.getId()) { 
      case R.id.tvName: 
       break; 
      case R.id.tvAge: 
       break; 
      case R.id.tvNationality: 
       break; 
      case R.id.tvGender: 
       break; 
      case R.id.tvCreatedAt: 
       break; 
     } 
    } 
} 

(3) SQLController.java

public class SQLController { 
    private SQLiteHandler handler; 
    private Context context; 
    private SQLiteDatabase db; 

    public SQLController(Context context) { 
     this.context = context; 
    } 

    public SQLController open() throws SQLiteException { 
     handler = new SQLiteHandler(context); 
     db = handler.getWritableDatabase(); 
     return this; 
    } 

    public void close() { 
     handler.close(); 
    } 

    public void insertData(Person person) { 
     ContentValues values = new ContentValues(); 
     values.put(SQLiteHandler.COLUMN_NAME, person.getName()); 
     values.put(SQLiteHandler.COLUMN_AGE, person.getAge()); 
     values.put(SQLiteHandler.COLUMN_NATIONALITY, person.getNationality()); 
     values.put(SQLiteHandler.COLUMN_GENDER, person.getGender()); 
     values.put(SQLiteHandler.COLUMN_CREATED_AT, person.getCreated_at()); 
     db.insert(SQLiteHandler.TABLE_NAME, null, values); 
    } 

    public Cursor readEntry() { 
     String[] allColumns = new String[] { 
       SQLiteHandler.COLUMN_NAME, SQLiteHandler.COLUMN_AGE, SQLiteHandler.COLUMN_NATIONALITY, SQLiteHandler.COLUMN_GENDER, 
       SQLiteHandler.COLUMN_CREATED_AT 
     }; 

     Cursor cursor = db.query(SQLiteHandler.TABLE_NAME, allColumns, null, null, null, null, null); 

     if(cursor != null) { 
      cursor.moveToFirst(); 
     } 
     return cursor; 
    } 
} 

(4) SQLiteHandler.java

public class SQLiteHandler extends SQLiteOpenHelper { 

    // DB information 
    static final int DB_VERSION = 1; 
    static final String DB_NAME = "sortingtester.db"; 

    // Table information 
    public static final String TABLE_NAME = "People"; 
    public static final String COLUMN_NAME = "Name"; 
    public static final String COLUMN_AGE = "Age"; 
    public static final String COLUMN_NATIONALITY = "Nationality"; 
    public static final String COLUMN_GENDER = "Gender"; 
    public static final String COLUMN_CREATED_AT = "Created_At"; 

    // Statement to create table 
    private final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + 
      COLUMN_NAME + " TEXT NOT NULL, " + COLUMN_AGE + " INT, " + COLUMN_NATIONALITY + " TEXT NOT NULL, " + 
      COLUMN_GENDER + " CHAR(1) NOT NULL, " + COLUMN_CREATED_AT + " TEXT NOT NULL);"; 

    // Statement to drop table 
    private final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLE_NAME; 

    public SQLiteHandler(Context context) { 
     super(context, DB_NAME, null, DB_VERSION); 
    } 
    @Override 
    public void onCreate(SQLiteDatabase db) { 
     db.execSQL(CREATE_TABLE); 
    } 

    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     db.execSQL(DROP_TABLE); 
     onCreate(db); 
    } 
} 

При запуске приложения и попытке запуска AddAPersonActivity я даже не смог достичь самой активности, так как приложение принудительно закрыто, показывая следующие сообщения об ошибках.

Caused by: java.lang.IllegalStateException: Couldn't read row 0, col 5 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. 
      at android.database.CursorWindow.nativeGetString(Native Method) 
      at android.database.CursorWindow.getString(CursorWindow.java:439) 
      at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51) 
      at com.marshall.dbtester.AddAPersonActivity.buildTable(AddAPersonActivity.java:221) 
      at com.marshall.dbtester.AddAPersonActivity.onCreate(AddAPersonActivity.java:68) 
      at android.app.Activity.performCreate(Activity.java:5451) 
      at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093) 
      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2377) 
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2471) 
            at android.app.ActivityThread.access$900(ActivityThread.java:175) 
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1308) 
            at android.os.Handler.dispatchMessage(Handler.java:102) 
            at android.os.Looper.loop(Looper.java:146) 
            at android.app.ActivityThread.main(ActivityThread.java:5602) 
            at java.lang.reflect.Method.invokeNative(Native Method) 
            at java.lang.reflect.Method.invoke(Method.java:515) 
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283) 
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099) 
            at dalvik.system.NativeStart.main(Native Method) 

Похоже, проблема возникает из курсора, так что я думаю, что это также связано с макетом ViewGroupActivity. Поэтому я также добавлю xml-файл ViewGroupActivity.

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:padding="30dp" 
    android:weightSum="1" 
    android:background="@color/default_background"> 

    <TextView 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_weight="0.05" 
     android:layout_marginBottom="20dp" 
     android:text="@string/group" 
     android:textSize="20dp" 
     android:textColor="@color/default_text"/> 


    <ScrollView 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:layout_weight="0.95"> 

     <TableLayout 
      android:id="@+id/tlViewGroup" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:orientation="horizontal" 
      android:shrinkColumns="*" 
      android:stretchColumns="*" 
      android:weightSum="1"> 

      <TableRow> 

       <TextView 
        android:id="@+id/tvName" 
        android:text="@string/name" 
        android:textAlignment="center" 
        android:layout_weight="0.2" 
        android:textColor="@color/default_text"/> 
       <TextView 
        android:id="@+id/tvAge" 
        android:text="@string/age" 
        android:textAlignment="center" 
        android:layout_weight="0.2" 
        android:textColor="@color/default_text"/> 
       <TextView 
        android:id="@+id/tvNationality" 
        android:text="@string/nationality" 
        android:textAlignment="center" 
        android:layout_weight="0.2" 
        android:textColor="@color/default_text"/> 
       <TextView 
        android:id="@+id/tvGender" 
        android:text="@string/gender" 
        android:textAlignment="center" 
        android:layout_weight="0.2" 
        android:textColor="@color/default_text"/> 
       <TextView 
        android:id="@+id/tvCreatedAt" 
        android:text="@string/created_at" 
        android:textAlignment="center" 
        android:layout_weight="0.2" 
        android:textColor="@color/default_text"/> 
      </TableRow> 

     </TableLayout> 

    </ScrollView> 

</LinearLayout> 

Я долгое время боролся с этой проблемой, поэтому ваш совет будет очень полезен!

ответ

0

Вы устанавливаете количество столбцов в размере курсора.

int columns = cursor.getCount();

Пользователь getColumnCount() и это, вероятно, должно работать.

Смежные вопросы