ハードウェア検索キーを使用して、コンテンツ プロバイダー経由でデータベースを検索する単純なアプリケーションがあります。提案から結果を取得し、選択肢の 1 つをクリックすると、リストビュー画面が表示され、空白になります。エラーが発生します:
E/InputQueue-JNI(1137): channel '4150a5d0 PopupWindow:412ccf98 (client)' ~ Publisher closed input channel or an error occurred. events=0x8
私はアンドロイド開発に不慣れで、いくつかの調査を行いましたが、これが何を意味するのかさえわかりません。
完全な logcat は次のとおりです。
06-24 14:54:03.154: I/TDAProvider(1137): query
06-24 14:54:03.924: I/TDAProvider(1137): query return cursor
06-24 14:54:04.014: I/TDAProvider(1137): query
06-24 14:54:04.304: I/TDAProvider(1137): query return cursor
06-24 14:54:04.754: D/dalvikvm(1137): GC_CONCURRENT freed 137K, 3% free 9374K/9607K, paused 23ms+28ms
06-24 14:54:07.154: E/InputQueue-JNI(1137): channel '4150a5d0 PopupWindow:412ccf98 (client)' ~ Publisher closed input channel or an error occurred. events=0x8
06-24 14:54:07.464: I/TDAProvider(1137): query
06-24 14:54:07.464: I/TDAProvider(1137): query return cursor
06-24 14:54:07.694: I/dalvikvm(1137): threadid=3: reacting to signal 3
06-24 14:54:07.745: I/dalvikvm(1137): Wrote stack traces to '/data/anr/traces.txt'
これを解決する方法またはデバッグする方法についての提案は大歓迎です。
ほとんどの処理は Android クラスによって行われているため、何を見ればよいかわかりません。コンテンツ プロバイダー (TDAProvider.java) から 2 つの uri の「SEARCH」と「CONTENT_URI_RULES」を使用しています。私の推測では、コンテンツ プロバイダーに問題があると思われますが、何が原因かはわかりません。
これが私のマニフェストファイルです:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".ActivityMain"
>
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="64dp"
android:layout_marginTop="22dp"
android:text="Test Search - using hardware button. Search for 'check'"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
これは、xml フォルダーに入れた searchable.xml です。
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_name"
android:searchSettingsDescription="@string/search_description"
android:searchSuggestAuthority="com.birdsall.tda.contentprovidertda"
android:searchSuggestIntentAction="android.intent.action.VIEW"
android:searchSuggestIntentData="content://com.birdsall.tda.TDAProvider/rules" >
</searchable>
検索を容易にするために使用される ActivitySearch.java は次のとおりです。
package com.birdsall.tda;
import android.app.ListActivity;
import android.app.LoaderManager;
import android.app.SearchManager;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.widget.SimpleCursorAdapter;
public class ActivitySearch extends ListActivity implements
LoaderManager.LoaderCallbacks<Cursor> {
private SimpleCursorAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a new adapter and bind it to the List View
adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1, null,
new String[] { TDAdb.COL_RULETITLE },
new int[] { android.R.id.text1 }, 0);
setListAdapter(adapter);
// Initiate the Cursor Loader
getLoaderManager().initLoader(0, null, this);
// Get the launch Intent
parseIntent(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
parseIntent(getIntent());
}
private static String QUERY_EXTRA_KEY = "QUERY_EXTRA_KEY";
private void parseIntent(Intent intent) {
// If the Activity was started to service a Search request,
// extract the search query.
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String searchQuery = intent.getStringExtra(SearchManager.QUERY);
// Perform the search, passing in the search query as an argument
// to the Cursor Loader
Bundle args = new Bundle();
args.putString(QUERY_EXTRA_KEY, searchQuery);
// Restart the Cursor Loader to execute the new query.
getLoaderManager().restartLoader(0, args, this);
}
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String query = "0";
if (args != null) {
// Extract the search query from the arguments.
query = args.getString(QUERY_EXTRA_KEY);
}
// Construct the new query in the form of a Cursor Loader.
String[] projection = { TDAdb.KEY_ROWID, TDAdb.COL_RULETITLE };
String where = TDAdb.COL_RULETITLE + " LIKE \"%" + query + "%\"";
String[] whereArgs = null;
String sortOrder = TDAdb.COL_RULETITLE;
// Create the new Cursor loader.
return new CursorLoader(this, TDAProvider.CONTENT_URI_RULES,
projection, where, whereArgs, sortOrder);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
// Replace the result Cursor displayed by the Cursor Adapter with
// the new result set.
adapter.swapCursor(cursor);
}
public void onLoaderReset(Loader<Cursor> loader) {
// Remove the existing result Cursor from the List Adapter.
adapter.swapCursor(null);
}
}
これがコンテンツ プロバイダー (TDAProvider.java) です。いくつかの生のクエリを使用しますが、この例では使用しません。
package com.birdsall.tda;
import java.util.HashMap;
import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
public class TDAProvider extends ContentProvider {
private TDAdbHelper dbHelper;
private static final String TAG = "TDAProvider";
private static final int ALL_CHAPTERS = 1;
private static final int SINGLE_CHAPTER = 2;
private static final int ALL_RULES = 3;
private static final int SINGLE_RULE = 4;
private static final int ALL_RAW_QUERY = 5;
private static final int SINGLE_RAW_QUERY = 6;
private static final int SEARCH = 7;
// authority is the symbolic name of your provider
// To avoid conflicts with other providers, you should use
// Internet domain ownership (in reverse) as the basis of your provider
// authority.
private static final String AUTHORITY = "com.birdsall.tda.contentprovidertda";
// create content URIs from the authority by appending path to database
// table
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY
+ "/chapters");
public static final Uri CONTENT_URI_RULES = Uri.parse("content://"
+ AUTHORITY + "/rules");
public static final Uri CONTENT_URI_RAWQUERY = Uri.parse("content://"
+ AUTHORITY + "/rawquery");
// a content URI pattern matches content URIs using wildcard characters:
// *: Matches a string of any valid characters of any length.
// #: Matches a string of numeric characters of any length.
private static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "chapters", ALL_CHAPTERS);
uriMatcher.addURI(AUTHORITY, "chapters/#", SINGLE_CHAPTER);
uriMatcher.addURI(AUTHORITY, "rules", ALL_RULES);
uriMatcher.addURI(AUTHORITY, "rules/#", SINGLE_RULE);
uriMatcher.addURI(AUTHORITY, "rawquery", ALL_RAW_QUERY);
uriMatcher.addURI(AUTHORITY, "rawquery/#", SINGLE_RAW_QUERY);
uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY,
SEARCH);
uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY
+ "/*", SEARCH);
uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT,
SEARCH);
uriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT
+ "/*", SEARCH);
}
// system calls onCreate() when it starts up the provider.
@Override
public boolean onCreate() {
// get access to the database helper
Log.i(TAG, "onCreate ");
dbHelper = new TDAdbHelper(getContext());
return false;
}
// Return the MIME type corresponding to a content URI
@Override
public String getType(Uri uri) {
Log.i(TAG, "getType ");
switch (uriMatcher.match(uri)) {
case ALL_CHAPTERS:
return "vnd.android.cursor.dir/vnd.com.birdsall.peter.contentprovidertda.chapters";
case SINGLE_CHAPTER:
return "vnd.android.cursor.item/vnd.com.birdsall.peter.contentprovidertda.chapters";
case ALL_RULES:
return "vnd.android.cursor.dir/vnd.com.birdsall.peter.contentprovidertda.rules";
case SINGLE_RULE:
return "vnd.android.cursor.item/vnd.com.birdsall.peter.contentprovidertda.rules";
case ALL_RAW_QUERY:
return "vnd.android.cursor.dir/vnd.com.birdsall.peter.contentprovidertda.rulesdescribed";
case SINGLE_RAW_QUERY:
return "vnd.android.cursor.item/vnd.com.birdsall.peter.contentprovidertda.rulesdescribed";
case SEARCH:
return SearchManager.SUGGEST_MIME_TYPE;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
private static final HashMap<String, String> SEARCH_PROJECTION_MAP;
static {
SEARCH_PROJECTION_MAP = new HashMap<String, String>();
SEARCH_PROJECTION_MAP.put(SearchManager.SUGGEST_COLUMN_TEXT_1,
TDAdb.COL_RULETITLE + " AS "
+ SearchManager.SUGGEST_COLUMN_TEXT_1);
SEARCH_PROJECTION_MAP.put("_id", TDAdb.KEY_ROWID + " AS " + "_id");
}
// The insert() method adds a new row to the appropriate table, using the
// values
// in the ContentValues argument. If a column name is not in the
// ContentValues argument,
// you may want to provide a default value for it either in your provider
// code or in
// your database schema.
@Override
public Uri insert(Uri uri, ContentValues values) {
Log.i(TAG, "insert ");
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case ALL_CHAPTERS:
// do nothing
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
long id = db.insert(TDAdb.CHAPTER_TABLE, null, values);
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(CONTENT_URI + "/" + id);
}
// The query() method must return a Cursor object, or if it fails,
// throw an Exception. If you are using an SQLite database as your data
// storage,
// you can simply return the Cursor returned by one of the query() methods
// of the
// SQLiteDatabase class. If the query does not match any rows, you should
// return a
// Cursor instance whose getCount() method returns 0. You should return null
// only
// if an internal error occurred during the query process.
// public Cursor query (Uri uri, String[] projection, String selection,
// String[] selectionArgs,
// String having, String groupby, String sortOrder, String limit,
// CancellationSignal cancellationSignal) {
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
String id;
Log.i(TAG, "query ");
SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// queryBuilder.setTables(TDAdb.CHAPTER_TABLE);
switch (uriMatcher.match(uri)) {
case ALL_CHAPTERS:
// do nothing
queryBuilder.setTables(TDAdb.CHAPTER_TABLE);
break;
case SINGLE_CHAPTER:
queryBuilder.setTables(TDAdb.CHAPTER_TABLE);
id = uri.getPathSegments().get(1);
queryBuilder.appendWhere(TDAdb.KEY_ROWID + "=" + id);
break;
case ALL_RULES:
// do nothing
queryBuilder.setTables(TDAdb.RULE_TABLE);
break;
case SINGLE_RULE:
queryBuilder.setTables(TDAdb.RULE_TABLE);
id = uri.getPathSegments().get(1);
queryBuilder.appendWhere(TDAdb.KEY_ROWID + "=" + id);
break;
case ALL_RAW_QUERY:
db = dbHelper.getReadableDatabase();
return db.rawQuery(selection, selectionArgs);
case SINGLE_RAW_QUERY:
db = dbHelper.getReadableDatabase();
return db.rawQuery(selection, selectionArgs);
case SEARCH:
queryBuilder.setTables(TDAdb.RULE_TABLE);
queryBuilder.appendWhere(TDAdb.COL_RULETITLE + " LIKE \"%"
+ uri.getPathSegments().get(1) + "%\"");
queryBuilder.setProjectionMap(SEARCH_PROJECTION_MAP);
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
Cursor cursor = queryBuilder.query(db, projection, selection,
selectionArgs, null, null, sortOrder);
Log.i(TAG, "query return cursor ");
// Register the contexts ContentResolver to be notified if
// the cursor result set changes.
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
// The delete() method deletes rows based on the seletion or if an id is
// provided then it deleted a single row. The methods returns the numbers
// of records delete from the database. If you choose not to delete the data
// physically then just update a flag here.
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.i(TAG, "delete ");
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case ALL_CHAPTERS:
// do nothing
break;
case SINGLE_CHAPTER:
String id = uri.getPathSegments().get(1);
selection = TDAdb.KEY_ROWID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
+ ')' : "");
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
int deleteCount = db.delete(TDAdb.CHAPTER_TABLE, selection,
selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return deleteCount;
}
// The update method() is same as delete() which updates multiple rows
// based on the selection or a single row if the row id is provided. The
// update method returns the number of updated rows.
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
Log.i(TAG, "update ");
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case ALL_CHAPTERS:
// do nothing
break;
case SINGLE_CHAPTER:
String id = uri.getPathSegments().get(1);
selection = TDAdb.KEY_ROWID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
+ ')' : "");
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
int updateCount = db.update(TDAdb.CHAPTER_TABLE, values, selection,
selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
Log.i(TAG, "update return updateCount ");
return updateCount;
}
}
データベース アクティビティ (TDAdb.java) は次のとおりです。
package com.birdsall.tda;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
public class TDAdb {
public static final String LOG_TAG = "TDAdb";
// tables
public static final String CHAPTER_TABLE = "chapters";
public static final String RULE_TABLE = "rules";
public static final String INDEXHEADER_TABLE = "indexheader";
public static final String KEYDESCRIPTORS_TABLE = "keydescriptors";
public static String SQLITE_TABLE = "chapters";
// Chapter Table Columns
public static final String KEY_ROWID = "_id";
public static final String COL_CHAPTER = "chapter";
public static final String COL_CHAPTERTITLE = "chaptertitle";
// Rule Table Columns
public static final String COL_RULE = "rule";
// public static final String COL_CHAPTER = "chapter";
public static final String COL_KEYDESCRIPTOR = "keydescriptor";
public static final String COL_RULETITLE = "ruletitle";
public static final String COL_DESCR = "descr";
public static final String COL_DESCRIPTION = "description"; // LongText
public static final String COL_LABEL = "label";
public static final String COL_USERLABEL = "userlabel";
public static final String COL_LABELID = "labelid"; // Integer
public static final String COL_USERLABELID = "userlabelid"; // Integer
public static final String COL_TDTIP = "tdtip";
public static final String COL_DEFUNCT = "defunct";
public static final String COL_USCFREVISION = "uscfrevision";
public static final String COL_HIGHLIGHT = "highlight"; // LongText
public static final String COL_PAGENO = "pageno";
public static final String COL_CHANGEDATE = "changedate"; // Integer
public static final String COL_REFINC = "refinc";
public static final String COL_RULEINC = "ruleinc";
// keydescriptors table columns
public static final String COL_KEYDESC = "keydesc";
public static final String COL_IMAGEREFERENCE = "imagereference";
// indexheader table columns
public static final String COL_INDEX_HEADER = "index_header";
public static final String COL_INDEXID = "indexid";
public static final String COL_INDEXLEXICON = "indexlexicon";
// columns defined in RAW Queries via AS
public static final String COLRAW_XREFRULE = "xrefrule";
public static final String COL_PROJ_THECOUNT = "count(*) as thecound";
public static final String COLTHECOUNT = "thecound";
public static final String[] PROJECTION_CHAPTER = { KEY_ROWID, COL_CHAPTER,
COL_CHAPTERTITLE, };
public static final String[] PROJECTION_RULES = { KEY_ROWID, COL_CHAPTER,
COL_RULE, COL_RULETITLE, COL_KEYDESCRIPTOR, };
/* ************** MAKE SURE THERE'S and _id *********************** */
public static final String RAWQUERY_RULESDESCRIBED = "select rules._id, rule, chapter, ruletitle, rules.keydescriptor, keydesc FROM rules LEFT OUTER JOIN keydescriptors ON rules.keydescriptor = keydescriptors.keydescriptor WHERE chapter = ? group by 1, 2, 3, 4, 5 order by 1, 4";
public static final String RAWQUERY_RULESCROSSREF = "SELECT rules._id, rules.rule, rules.ruletitle, rulereferences.rule AS xrefrule FROM rulereferences INNER JOIN rules ON rulereferences.rulereference = rules.rule WHERE (((rules.keydescriptor)='2') AND ((rulereferences.rule)= ? )) ORDER BY rules.rule";
public static final String RAWQUERY_RULESCROSSREFDETAIL = "SELECT rules._id, rules.rule, rules.ruletitle, keydescriptors.keydesc FROM rules INNER JOIN keydescriptors ON rules.keydescriptor = keydescriptors.keydescriptor WHERE (((rules.rule)= ? )) GROUP BY rules.rule, rules.ruletitle, keydescriptors.keydesc ORDER BY rules.rule, Min(rules.keydescriptor)";
public static final String RAWQUERY_INDEX = "SELECT DISTINCT _id, indexlexicon FROM indexheader GROUP BY 2 ORDER BY 2";
public static final String RAWQUERY_INDEXCHILD = "SELECT indexheader._id, indexheader.index_header, indexer.rule, indexheader.indexid, rules.pageno, rules.uscfrevision, rules.defunct FROM (indexheader LEFT JOIN indexer ON indexheader.indexid = indexer.indexid) LEFT JOIN rules ON indexer.rule = rules.rule WHERE (((indexheader.indexlexicon)= ? )) GROUP BY indexheader._id, indexheader.index_header, indexer.rule, indexheader.indexid, rules.pageno, rules.uscfrevision, rules.defunct HAVING (((rules.pageno) Is Not Null)) ORDER BY indexheader.index_header, indexheader.indexid";
public static final String RAWQUERY_RULEDETAIL = "SELECT rules.rule, rules.ruletitle, rules.descr, rules.description, rules.keydescriptor, rules.tdtip, rules.uscfrevision, rules.defunct, rules.highlight, rules.label, rules.userlabel, rules.changedate FROM rules GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 HAVING (((rules.rule)= ? )) ORDER BY 1, 5";
public static final String RAWQUERY_LABEL = "select distinct _id, label, count(*) as thecount from rules group by 2 order by label";
public static final String RAWQUERY_LABELDETAIL = "SELECT rules._id, rules.rule, rules.ruletitle, keydescriptors.keydesc FROM rules INNER JOIN keydescriptors ON rules.keydescriptor = keydescriptors.keydescriptor WHERE (((rules.label)= ? )) GROUP BY rules.rule, rules.ruletitle, keydescriptors.keydesc ORDER BY rules.rule, Min(rules.keydescriptor)";
public static void onCreate(SQLiteDatabase db) {
Log.i(LOG_TAG, "onCreate");
}
public static void onUpgrade(SQLiteDatabase db, int oldVersion,
int newVersion) {
Log.w(LOG_TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
onCreate(db);
}
}
データベース ヘルパー (TDAdbHelper.java) は次のとおりです。
package com.birdsall.tda;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class TDAdbHelper extends SQLiteOpenHelper {
public static String DATABASE_PATH;
public static final String DATABASE_NAME = "tda.db";
private static final int DATABASE_VERSION = 1;
private Context context;
private SQLiteDatabase db;
public TDAdbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context;
String packageName = context.getPackageName();
DATABASE_PATH = String.format("//data//data//%s//databases//",
packageName);
Log.i(this.getClass().toString(), "... before calling openDatabase ");
openDataBase();
Log.i(this.getClass().toString(), "... after return openDatabase ");
}
@Override
public void onCreate(SQLiteDatabase db) {
Log.i(this.getClass().toString(), "... Starting TDAdb.onCreate ");
TDAdb.onCreate(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
TDAdb.onUpgrade(db, oldVersion, newVersion);
}
// Performing a database existence check
private boolean checkDataBase() {
Log.i(this.getClass().toString(), "... Starting checkDatabase ");
SQLiteDatabase checkDb = null;
try {
String path = DATABASE_PATH + DATABASE_NAME;
checkDb = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLException e) {
Log.e(this.getClass().toString(), "Error while checking db");
}
// Android doesn’t like resource leaks, everything should
// be closed
if (checkDb != null) {
checkDb.close();
}
return checkDb != null;
}
// Method for copying the database
private void copyDataBase() throws IOException {
// Open a stream for reading from our ready-made database
// The stream source is located in the assets
Log.i(this.getClass().toString(), "... in copyDataBase ");
InputStream externalDbStream = context.getAssets().open(DATABASE_NAME);
// Path to the created empty database on your Android device
String outFileName = DATABASE_PATH + DATABASE_NAME;
// Now create a stream for writing the database byte by byte
OutputStream localDbStream = new FileOutputStream(outFileName);
// Copying the database
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = externalDbStream.read(buffer)) > 0) {
localDbStream.write(buffer, 0, bytesRead);
}
// Don’t forget to close the streams
localDbStream.close();
externalDbStream.close();
}
// This piece of code will create a database if it’s not yet created
public void createDataBase() {
Log.i(this.getClass().toString(), "... in createDataBase ");
boolean dbExist = checkDataBase();
if (!dbExist) {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
Log.e(this.getClass().toString(), "Copying error");
throw new Error("Error copying database!");
}
} else {
Log.i(this.getClass().toString(), "Database already exists");
}
}
public SQLiteDatabase openDataBase() throws SQLException {
String path = DATABASE_PATH + DATABASE_NAME;
Log.i(this.getClass().toString(), "Starting openDatabase " + path);
if (db == null) {
createDataBase();
db = SQLiteDatabase.openDatabase(path, null,
SQLiteDatabase.OPEN_READWRITE);
}
return db;
}
}
完全を期すために、メイン アクティビティ (ActivityMain.java) があります。これは単純な Hello World です。
package com.birdsall.tda;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class ActivityMain extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
メイン アクティビティ (activity_main.xml) の単純なレイアウト:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".ActivityMain"
>
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="64dp"
android:layout_marginTop="22dp"
android:text="Test Search - using hardware button. Search for 'check'"
android:textAppearance="?android:attr/textAppearanceMedium" />
</RelativeLayout>
この問題を修正またはデバッグする方法についてご意見がありましたら、よろしくお願いいたします。私は Android 開発に慣れていないので、その理由についても簡単に説明すると役に立ちます。
すてきな一日を。