java - 使用 Fragment 类中的数据库填充 android ListView 时发生意外错误

标签 java android sqlite listview android-fragments

我正在尝试从数据库填充 ListView,因为我正在使用抽屉导航,所以我需要使用 fragment 来显示我的 View 而不是 Activity 。一切都很好,但是当我运行我的应用程序时,它显示了一个错误,即 column _id does not exits 但我的查询是 SELECT city_name, country_name, favorite FROM city;。我的数据库表是。

enter image description here

我的 Android 应用程序屏幕是:

enter image description here

当我单击所有城市(位置=3)时,我想用数据库中的 city_name 和 country_name 填充我的列表。但它显示错误 column _id does not exits 但在我的查询中没有使用 _id 而且我的表包含 _id。那么为什么会出现这个错误呢?

我的代码部分如下:

MyActivity.java 类中的 selectItem() 方法,当我选择 All City position=3

private void selectItem(int position) {
    if (position == 0) {
        MyFragment fragment = new MyFragment();
        Bundle args = new Bundle();
        args.putInt(MyFragment.ARG_OS, position);
        fragment.setArguments(args);
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.content_frame, fragment).commit();
        mDrawerList.setItemChecked(position, true);
        getSupportActionBar().setTitle((navMenuTitles[position]));
        mDrawerLayout.closeDrawer(mDrawerList);
    } else if (position == 3) {

        AllCityListFragment myfragment = new AllCityListFragment();
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.content_frame, myfragment).commit();
        mDrawerList.setItemChecked(position, true);
        getSupportActionBar().setTitle((navMenuTitles[position]));
        mDrawerLayout.closeDrawer(mDrawerList);

    }
}

DatabaseHelper.java:工作正常,在这个问题中我需要 createdatabase()、opendatabase() 和 getResult() 方法 getResult 返回一个 Cursor。

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;

import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;

public class DatabaseHelper extends SQLiteOpenHelper {

    private static String PACKAGE_NAME;

    private static String DB_PATH;

    private static String DB_NAME = "weatherbd.db";

    private SQLiteDatabase myDataBase;

    private final Context myContext;

    public DatabaseHelper(Context context) {

        super(context, DB_NAME, null, 1);
        this.myContext = context;
        PACKAGE_NAME = myContext.getPackageName();
        DB_PATH = "/data/data/" + PACKAGE_NAME + "/databases/";
    }

    public void createDataBase() throws IOException {

        boolean dbExist = checkDataBase();

        if (dbExist) {
            // do nothing - database already exist
        } else {

            // By calling this method and empty database will be created into
            // the default system path
            // of your application so we are gonna be able to overwrite that
            // database with our database.
            this.getReadableDatabase();

            try {

                copyDataBase();

            } catch (IOException e) {

                throw new Error("Error copying database");

            }
        }

    }

    private boolean checkDataBase() {

        SQLiteDatabase checkDB = null;

        try {
            String myPath = DB_PATH + DB_NAME;
            checkDB = SQLiteDatabase.openDatabase(myPath, null,
                    SQLiteDatabase.OPEN_READWRITE);

        } catch (SQLiteException e) {

            // database does't exist yet.

        }

        if (checkDB != null) {

            checkDB.close();

        }

        return checkDB != null ? true : false;
    }

    private void copyDataBase() throws IOException {

        // Open your local db as the input stream
        InputStream myInput = myContext.getAssets().open(DB_NAME);

        // Path to the just created empty db
        String outFileName = DB_PATH + DB_NAME;

        // Open the empty db as the output stream
        OutputStream myOutput = new FileOutputStream(outFileName);

        // transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[1024];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }

        // Close the streams
        myOutput.flush();
        myOutput.close();
        myInput.close();

    }

    public void openDataBase() throws SQLException {

        // Open the database
        String myPath = DB_PATH + DB_NAME;
        myDataBase = SQLiteDatabase.openDatabase(myPath, null,
                SQLiteDatabase.OPEN_READONLY);

    }

    @Override
    public synchronized void close() {

        if (myDataBase != null)
            myDataBase.close();

        super.close();

    }

    @Override
    public void onCreate(SQLiteDatabase db) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    public Cursor getResult(String sql) {

        Cursor c = myDataBase.rawQuery(sql, null);

        return c;
    }

}

AllListFragment.java 显示来自数据库的填充列表的类,这里的错误来自于查询 SELECT city_name, country_name, favorite FROM city;

import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;

public class AllCityListFragment extends Fragment {
    private CustomList customAdapter;
    private DatabaseHelper databaseHelper;

    ListView list;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.all_city_layout, null);

        databaseHelper = new DatabaseHelper(view.getContext());

        try {
            databaseHelper.createDataBase();
            Toast.makeText(view.getContext(), "Database Created",
                    Toast.LENGTH_LONG).show();
            databaseHelper.openDataBase();
            Toast.makeText(view.getContext(), "Database Opened",
                    Toast.LENGTH_LONG).show();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Toast.makeText(view.getContext(), "Error: " + e.getMessage(),
                    Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }

        list = (ListView) view.findViewById(R.id.citylist);
        list.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                Toast.makeText(view.getContext(),
                        "Cliked on item: " + position, Toast.LENGTH_LONG)
                        .show();
            }
        });

        new Handler().post(new Runnable() {
            @Override
            public void run() {
                    customAdapter = new CustomList(
                            view.getContext(),
                            databaseHelper
                                    .getResult("SELECT city_name, country_name, favorite FROM city;"));
                    list.setAdapter(customAdapter);

            }
        });
        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }
}

CustomList.java 类扩展了 CursorAdapter

import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CursorAdapter;
import android.widget.TextView;

public class CustomList extends CursorAdapter {

    @SuppressWarnings("deprecation")
    public CustomList(Context context, Cursor c) {
        super(context, c);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {

        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View retView = inflater.inflate(R.layout.all_city_list, parent, false);

        return retView;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {

        TextView cityName = (TextView) view.findViewById(R.id.cityName);
        cityName.setText(cursor.getString(cursor.getColumnIndex("city_name")));

        TextView countryName = (TextView) view.findViewById(R.id.countryName);
        countryName.setText(cursor.getString(cursor.getColumnIndex("country_name")));

        CheckBox favoriteBox = (CheckBox) view
                .findViewById(R.id.favoriteCheckBox);
        if (cursor.getInt(cursor.getColumnIndex("favorite")) == 0) {
            favoriteBox.setSelected(false);
        } else {
            favoriteBox.setSelected(true);
        }

    }
}

日志:

enter image description here

我重新启动了我的 Eclipse IDE,但我仍然遇到这个问题。

最佳答案

当与 CursorAdapter 一起使用时,游标必须包含 _id 列。将 _id 列添加到您的查询中。来自文档:

Adapter that exposes data from a Cursor to a ListView widget. The Cursor must include a column named "_id" or this class will not work.

关于java - 使用 Fragment 类中的数据库填充 android ListView 时发生意外错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29645867/

相关文章:

java - 如何在easymock中模拟一个返回其参数之一的方法?

java - Android中半透明导航栏的问题

javascript - 在 Thunderbird 中查询 SQLite 数据库

ios - NSCoding 与 Sqlite

python - 如何将我的 Flask 应用程序连接到我的 SQLite3 数据库?

java - 使用 Dropzone.js 在 Struts2 中上传多个文件

java - Tomcat 添加 context-path 到 urls

java - 在 Java Selenium 中鼠标移动后单击元素

java - Intellij Idea lib文件夹导出

android - iOS开发中的Android权限相当于什么?