sqlite 行 ID 与列表视图不匹配 - ANDROID

Posted

技术标签:

【中文标题】sqlite 行 ID 与列表视图不匹配 - ANDROID【英文标题】:sqlite row ids not matching listview - ANDROID 【发布时间】:2015-03-08 07:18:38 【问题描述】:

这可能是一个蹩脚的问题,但我是初学者,似乎不了解我的应用程序的行为。

我有一个 SQLite 数据库,并且在主要活动中有一个列表视图。 在列表视图中,我显示列表编号(行 ID)和其他详细信息。 按下列表项后,会打开一个新活动,在文本视图中显示详细信息,并有 2 个用于删除和同步的图像按钮。

在我删除任何条目之前,该应用程序运行良好。

一旦我删除任何条目,列表视图上的行 ID 似乎不会更新行号。 (如果我删除第一行,顶部的行显示 2(应该是 1,因为它是新的第一行)。

但是,当我显示记录的详细信息时,它是正确的。 (列表中的第二项显示第 2 行)

此外,当我按下列表视图中的位置与我之前删除的位置相同的项目时,应用程序崩溃(假设我删除第一个条目,之后每当我单击列表视图上的第一个项目时显示它应用程序崩溃)

我在应用程序崩溃时遇到错误:

java.lang.RuntimeException: Unable to start activity ComponentInfocom.example.aakashmaroti.fillup/com.example.aakashmaroti.fillup.DisplayDetails: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0

我的主要活动

package com.example.aakashmaroti.fillup;

import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;


public class StartScreen extends ActionBarActivity implements View.OnClickListener 


    FavoriteList favList = new FavoriteList();

    TextView rid,ts,sd;
    ListView lv;
    Context context=this;
    Find db=new Find(this);
    List<FavoriteList> favoriteList;
    LinearLayout layout;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_start_screen);
        Button b = (Button) findViewById(R.id.AddButton);
        b.setOnClickListener(this);
        lv = (ListView) findViewById(R.id.listview);
        try
        
            populateListViewFromDatabase();
         catch (Exception e)
        
            Toast.makeText(getApplicationContext(), "Oops there has been an error "+e.toString()+"", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener()
        
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id)
            
                showsDialog(position);
            
        );


    


    @Override
    public void onResume()
    
        super.onResume();
        try
        
            populateListViewFromDatabase();
         catch (Exception e)
        
            Toast.makeText(getApplicationContext(), "Oops there has been an error "+e.toString()+"", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        

    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_start_screen, menu);
        return true;
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) 
            return true;
        

        return super.onOptionsItemSelected(item);
    

    @Override
    public void onClick(View v) 

        switch (v.getId())
        
            case R.id.AddButton:
                startActivity(new Intent(this,Form.class));
                break;

            default: break;
        
    

    public void populateListViewFromDatabase()throws Exception
    
        Find info=new Find(this);
        try
        
            info.open();
            SimpleCursorAdapter myCursorAdapter;
            myCursorAdapter = info.listUp();
            lv.setAdapter(myCursorAdapter);
            info.close();

         catch (SQLException e)
        
            e.printStackTrace();
            Toast.makeText(getApplicationContext(), "Oops there has been an error "+e.toString()+"", Toast.LENGTH_LONG).show();
        
    
    public void showsDialog(int pos)
    

        pos++;
        String s = "";
        s += pos;
        Intent i = new Intent(getApplicationContext(), DisplayDetails.class);
        i.putExtra("position", s);
        startActivity(i);

        try
        
            populateListViewFromDatabase();
         catch (Exception e)
        
            e.printStackTrace();
        
    


sqlite数据库管理类

package com.example.aakashmaroti.fillup;

import android.app.Dialog;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Aakash Maroti on 28-Dec-14.
 */
public class Find

    public static final String KEY_ROWID = "_id";
    public static final String KEY_TIMESTAMP= "time_stamp";
    public static final String KEY_IS_SYNCED = "sync";
    public static final String KEY_NameOfCompany="name_of_company";



    private static final String DATABASE_NAME = "FillUpFormsDB";
    private static final String DATABASE_TABLE = "FillUpFormsTable";
    private static final int DATABASE_VERSION = 1;

    private DbHelper ourHelper;
    private final Context ourContext;
    private SQLiteDatabase ourDatabase;




    private static class DbHelper extends SQLiteOpenHelper
    

        public DbHelper(Context context)
        
            super(context,DATABASE_NAME,null,DATABASE_VERSION);
        



        @Override
        public void onCreate(SQLiteDatabase db)
        
            db.execSQL("CREATE TABLE " + DATABASE_TABLE + " (" +
                    KEY_ROWID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
                            KEY_IS_SYNCED +" TEXT NOT NULL, " +
                            KEY_TIMESTAMP +" TEXT NOT NULL, " +
                            KEY_NameOfCompany+" TEXT NOT NULL);"
            );
        

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
        
            db.execSQL("DROP TABLE IF EXISTS "+DATABASE_TABLE);
            onCreate(db);
             

      


    public Find(Context c)
    
        ourContext = c;
    

    public Find open()throws SQLException
    
        ourHelper = new DbHelper(ourContext);
        ourDatabase=ourHelper.getWritableDatabase();
        return this;
    

    public void close()
    
        ourHelper.close();
    


    public long createEntry(String isSynced, String timeStamp, String nameOfCompany)
    
        ContentValues cv=new ContentValues();
        cv.put(KEY_IS_SYNCED,isSynced);
        cv.put(KEY_TIMESTAMP,timeStamp);
        cv.put(KEY_NameOfCompany,nameOfCompany);        

        return ourDatabase.insert(DATABASE_TABLE,null,cv);

    

    public SimpleCursorAdapter listUp()
    

        String columns[]=new String[]KEY_ROWID,KEY_TIMESTAMP,KEY_IS_SYNCED;
        Cursor c= ourDatabase.query(DATABASE_TABLE,columns,null,null,null,null,null);
        int toViewIDs[] = new int[]R.id.rowno,R.id.timestamp,R.id.syncdetails;
        SimpleCursorAdapter CursorAdapter;
        CursorAdapter = new SimpleCursorAdapter(ourContext,R.layout.design_row,c,columns,toViewIDs,0);
        return CursorAdapter;
    

    public String getDetails(long row)
    
        String columns[]=new String[] KEY_ROWID, KEY_IS_SYNCED, KEY_TIMESTAMP,KEY_NameOfCompany;
        String result="";        
        Cursor c= ourDatabase.query(DATABASE_TABLE,columns,KEY_ROWID+"="+row,null,null,null,null);
        if(c!=null)
        
            String r;
            c.moveToFirst();
            r="\nRecord No. : "+c.getString(0)+"\n\nSync Status:"+c.getString(1)+"\n\nTime of Creation:\n"+c.getString(2)+"\n\nName of Company:\n"+c.getString(3);
            return r;
        

        return result;
    

    public void DeleteRow(int pos)
    
        ourDatabase.delete(DATABASE_TABLE,KEY_ROWID+"="+pos,null);
    

显示结果的新活动的类。

package com.example.aakashmaroti.fillup;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import java.sql.SQLException;


public class DisplayDetails extends ActionBarActivity implements View.OnClickListener



    ImageButton ibSync;
    ImageButton ibDelete;
    TextView DispDetails;
    int pos;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    
        super.onCreate(savedInstanceState);
        Bundle extras = getIntent().getExtras();

        String value="1";
        if (extras != null) 
           value = extras.getString("position");
        
        pos=Integer.parseInt(value);
        setContentView(R.layout.activity_display_details);
        ibSync=(ImageButton)findViewById(R.id.imageButtonSync);
        ibDelete=(ImageButton)findViewById(R.id.imageButtonDelete);
        DispDetails = (TextView)findViewById(R.id.textViewDisplayDetails);
        String s="";

        ibSync.setOnClickListener(this);
        ibDelete.setOnClickListener(this);

        Find info1=new Find(this);
        try
        
            info1.open();
            s=info1.getDetails(pos);
            info1.close();

         catch (SQLException e)
        
            e.printStackTrace();
            Toast.makeText(getApplicationContext(), "Oops there has been an error "+e.toString()+"", Toast.LENGTH_LONG).show();
        
        DispDetails.setText(s);

    


    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_display_details, menu);
        return true;
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings)
        
            return true;
        

        return super.onOptionsItemSelected(item);
    

    @Override
    public void onClick(View v)
    
        if(v.getId()==R.id.imageButtonSync)
        
            Toast.makeText(getApplicationContext(), "This functionality has not yet been added", Toast.LENGTH_LONG).show();
        
        if(v.getId()==R.id.imageButtonDelete)
           Find info1=new Find(this);
            try
            
                info1.open();
                info1.DeleteRow(pos);
                info1.close();

             catch (SQLException e)
            
                e.printStackTrace();
                Toast.makeText(getApplicationContext(), "Oops there has been an error "+e.toString()+"", Toast.LENGTH_LONG).show();
            


            Toast.makeText(getApplicationContext(), "This record has been successfully deleted", Toast.LENGTH_LONG).show();
            cancel();
        
    

    public void cancel()
    
        this.finish();
        return;
    

列表视图中单行的xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_
              android:layout_>


    <TextView
        android:layout_
        android:layout_
        android:text=""
        android:textStyle="bold"
        android:clickable="true"
        android:id="@+id/rowno"/>   

    <TextView
        android:layout_
        android:layout_
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text=""
        android:clickable="true"
        android:id="@+id/timestamp"/>

    <TextView
        android:layout_
        android:layout_
        android:textStyle="bold"
        android:text=""
        android:clickable="true"
        android:id="@+id/syncdetails"/>

</LinearLayout>

任何帮助将不胜感激。

提前致谢。

【问题讨论】:

【参考方案1】:

因为你传递的是列表视图项的位置,它应该是数据库行id。

改变

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

    showsDialog(position);

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

    TextView pos = (TextView) view.findViewById(R.id.rowno);
    showsDialog(pos.getText().toString());

你也说过

Once I delete any entry the row id on the listview doesn't seem to update the row number. (if i delete the first row, the row on top shows 2(should be 1, as it is the new first row)).

但它不会因为这是数据库行 id 而不是列表视图位置。

【讨论】:

非常感谢!它就像一个魅力!还有一种方法可以显示项目位置而不是行 id 吗?因为删除行 id 会产生错误。再次感谢! 如果你想显示列表视图项的位置而不是行 ID,那么我猜你将不得不使用自定义适配器。【参考方案2】:

您只能在 onResume 或 onCreate 中获取您的光标。因此,尽管数据发生了变化,但您的光标保持不变。查看 LoaderManager 类。

【讨论】:

以上是关于sqlite 行 ID 与列表视图不匹配 - ANDROID的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Sqlite 数据库中的特定数据上更改 Listview 中的行颜色

从 ListView(SQLite 数据库)中长按行删除

将保存在数据库 sqlite 中的列表视图中的一行发送到另一个列表视图,并使其与第一个列表视图中的行相同

Android:如何在列表视图中自动显示带有复选框的 Sqlite 数据库

获取与 SQL 查询中的列表匹配的所有行

“如何删除 sqlite 数据库中正确的列表视图项