问题
I really need help populating a map with markers from coordinates stored in my database. I've worked with populating listviews from SQLite, and I can add markers to a map, but I cannot figure out how to add markers from an SQLite database. Also, if I could get some help with centering the markers on screen and zooming in where they all fit, that would be awesome! Heres my code so far:
*Updated Code*
ALLMAPACTIVITY
public class allmapactivity extends MapActivity {
GeoPoint GeoP;
MapView mapV;
private SQLiteAdapter mySQLiteAdapter;
public ArrayList<Integer> latitude = new ArrayList<Integer>();
public ArrayList<Integer> longitude = new ArrayList<Integer>();
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.map);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
mapV = (MapView) findViewById(R.id.mapview);
mapV.displayZoomControls(true);
mapV.setBuiltInZoomControls(true);
mapV.setSatellite(false);
final MapController mController = mapV.getController();
List<Overlay> mapOverlays = mapV.getOverlays();
Drawable drawable = this.getResources().getDrawable(R.drawable.pin);
mySQLiteAdapter = new SQLiteAdapter(getApplicationContext());
if(!mySQLiteAdapter.isEmpty())
{
Cursor initcursor = mySQLiteAdapter.queueAll5();
initcursor.moveToFirst();
for(int i = 0; i < initcursor.getCount();i++)
{
HelloItemizedOverlay itemizedoverlay =
new HelloItemizedOverlay(drawable, allmapactivity.this);
int lat = (int) (initcursor.getDouble(initcursor.getColumnIndex("Content11")) * 1E6);
int lon = (int) (initcursor.getDouble(initcursor.getColumnIndex("Content12")) * 1E6);
latitude.add(lat);
longitude.add(lon);
GeoPoint geopoint = new GeoPoint(lat, lon);
String savedtitle = initcursor.getString(initcursor.getColumnIndex("Content9"));
String savedtext = initcursor.getString(initcursor.getColumnIndex("Content10"));
OverlayItem overlayitem = new OverlayItem(geopoint, savedtitle, savedtext);
itemizedoverlay.addOverlay(overlayitem);
mapOverlays.add(itemizedoverlay);
initcursor.moveToNext();
}
}
int latSum = 0;
double latAverage = 0;
for(Integer latitudeValue: latitude)
{
latSum = latSum + latitudeValue;
}
latAverage = (double) latSum/latitude.size();
int lonSum = 0;
double lonAverage = 0;
for(Integer longitudeValue: longitude)
{
lonSum = lonSum + longitudeValue;
}
lonAverage = (double) lonSum/longitude.size();
GeoPoint center = new GeoPoint((int) latAverage, (int) lonAverage);
mController.animateTo(center);
}
@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
}
SQLITEADAPTER
public class SQLiteAdapter {
public static final String MYDATABASE_NAME = "MY_DATABASE";
public static final String MYDATABASE_TABLE = "MY_TABLE";
public static final int MYDATABASE_VERSION = 1;
public static final String KEY_ID = "_id";
public static final String KEY_CONTENT1 = "Content1";
public static final String KEY_CONTENT3 = "Content3";
public static final String KEY_CONTENT4 = "Content4";
public static final String KEY_CONTENT5 = "Content5";
public static final String KEY_CONTENT6 = "Content6";
public static final String KEY_CONTENT7 = "Content7";
public static final String KEY_CONTENT8 = "Content8";
public static final String KEY_CONTENT9 = "Content9";
public static final String KEY_CONTENT10 = "Content10";
public static final String KEY_CONTENT11 = "Content11";
public static final String KEY_CONTENT12 = "Content12";
private static final String SCRIPT_CREATE_DATABASE =
"create table " + MYDATABASE_TABLE + " ("
+ KEY_ID + " integer primary key autoincrement, "
+ KEY_CONTENT1 + " text not null, "
+ KEY_CONTENT3 + " text not null, "
+ KEY_CONTENT4 + " text not null,"
+ KEY_CONTENT5 + " text not null, "
+ KEY_CONTENT6 + " text not null,"
+ KEY_CONTENT7 + " text not null,"
+ KEY_CONTENT8 + " text not null,"
+ KEY_CONTENT9 + " text not null,"
+ KEY_CONTENT10 + " text not null,"
+ KEY_CONTENT11 + " text not null,"
+ KEY_CONTENT12 + " text not null);";
private static final String FOOTPRINT = null;
private SQLiteHelper sqLiteHelper;
private SQLiteDatabase sqLiteDatabase;
private Context context;
public SQLiteAdapter(Context c){
context = c;
}
public SQLiteAdapter openToRead() throws android.database.SQLException {
sqLiteHelper = new SQLiteHelper(context, MYDATABASE_NAME, null, MYDATABASE_VERSION);
sqLiteDatabase = sqLiteHelper.getReadableDatabase();
return this;
}
public SQLiteAdapter openToWrite() throws android.database.SQLException {
sqLiteHelper = new SQLiteHelper(context, MYDATABASE_NAME, null, MYDATABASE_VERSION);
sqLiteDatabase = sqLiteHelper.getWritableDatabase();
return this;
}
public void close(){
sqLiteHelper.close();
}
public long insert(String content1, String content3,
String content4, String content5, String content6, String content7,
String content8, String content9, String content10, String content11, String content12){
ContentValues contentValues = new ContentValues();
contentValues.put(KEY_CONTENT1, content1);
contentValues.put(KEY_CONTENT3, content3);
contentValues.put(KEY_CONTENT4, content4);
contentValues.put(KEY_CONTENT5, content5);
contentValues.put(KEY_CONTENT6, content6);
contentValues.put(KEY_CONTENT7, content7);
contentValues.put(KEY_CONTENT8, content8);
contentValues.put(KEY_CONTENT9, content9);
contentValues.put(KEY_CONTENT10, content10);
contentValues.put(KEY_CONTENT11, content11);
contentValues.put(KEY_CONTENT12, content12);
return sqLiteDatabase.insert(MYDATABASE_TABLE, null, contentValues);
}
public int deleterow(){
SharedPreferences settings = context.getSharedPreferences(FOOTPRINT, 0);
String itemId = settings.getString("columnvalue5", "");
return sqLiteDatabase.delete(MYDATABASE_TABLE, KEY_CONTENT1 + "=" + "?", new String[]{itemId});
}
public int deleterow2(){
SharedPreferences settings = context.getSharedPreferences(FOOTPRINT, 0);
String itemId = settings.getString("columnvalue6", "");
String itemId2 = settings.getString("columnvalue7", "");
return sqLiteDatabase.delete(MYDATABASE_TABLE,
KEY_CONTENT1 + "=?" + " and " + KEY_CONTENT3 + "=?", new String[]{itemId,itemId2});
}
public int deleterow3(){
SharedPreferences settings = context.getSharedPreferences(FOOTPRINT, 0);
String itemId = settings.getString("columnvalue8", "");
return sqLiteDatabase.delete(MYDATABASE_TABLE, KEY_ID + "=" + "?", new String[]{itemId});
}
public Cursor queueAll(){
String[] columns = new String[]{KEY_ID, KEY_CONTENT1, "sum(" + KEY_CONTENT6 + " )", KEY_CONTENT9};
Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns,
null, null, KEY_CONTENT1, null, KEY_CONTENT9+ " DESC");
return cursor;
}
public Cursor queueAll2(){
SharedPreferences settings = context.getSharedPreferences(FOOTPRINT, 0);
String itemId = settings.getString("columnvalue1", "");
String[] columns = new String[]{KEY_ID, KEY_CONTENT1, KEY_CONTENT3, "sum(" + KEY_CONTENT6 + " )", KEY_CONTENT9, KEY_CONTENT10};
Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns,
KEY_CONTENT1 + "=" + "?", new String[]{itemId}, KEY_CONTENT3, null, KEY_CONTENT9+ " DESC");
return cursor;
}
public Cursor queueAll3(){
SharedPreferences settings = context.getSharedPreferences(FOOTPRINT, 0);
String itemId = settings.getString("columnvalue1", "");
String itemId2 = settings.getString("columnvalue2", "");
String[] columns = new String[]{KEY_ID, KEY_CONTENT1, KEY_CONTENT3, KEY_CONTENT4, KEY_CONTENT5, KEY_CONTENT6,
KEY_CONTENT7, KEY_CONTENT8, KEY_CONTENT9, KEY_CONTENT11, KEY_CONTENT12};
Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns,
KEY_CONTENT1 + "=?" + " and " + KEY_CONTENT3 + "=?" , new String[]{itemId,itemId2}, null, null, KEY_CONTENT9+ " DESC");
return cursor;
}
public Cursor queueAll4(){
String[] columns = new String[]{KEY_ID, "sum(" + KEY_CONTENT6 + " )", KEY_CONTENT9, KEY_CONTENT10 };
Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns,
null , null, KEY_CONTENT10, null, KEY_CONTENT9+ " DESC");
return cursor;
}
public Cursor queueAll5(){
String[] columns = new String[]{KEY_CONTENT9, KEY_CONTENT10, KEY_CONTENT11, KEY_CONTENT12};
Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns,
null , null, null, null, null);
return cursor;
}
public boolean isEmpty()
{
try{
Cursor check = sqLiteDatabase.query("MY_TABLE", new String[] {"Content11"}, null, null, null, null, null);
}
catch(NullPointerException e)
{
return true;
}
return false;
}
public class SQLiteHelper extends SQLiteOpenHelper {
public SQLiteHelper(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL(SCRIPT_CREATE_DATABASE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
}
Unfortunately, I get a force close error with this code :( heres the logcat:
07-22 19:14:33.918: E/AndroidRuntime(1330): FATAL EXCEPTION: main
07-22 19:14:33.918: E/AndroidRuntime(1330): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.inn.footprint/com.inn.footprint.allmapactivity}: android.util.AndroidRuntimeException: requestFeature() must be called before adding content
07-22 19:14:33.918: E/AndroidRuntime(1330): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
07-22 19:14:33.918: E/AndroidRuntime(1330): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
07-22 19:14:33.918: E/AndroidRuntime(1330): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
07-22 19:14:33.918: E/AndroidRuntime(1330): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
07-22 19:14:33.918: E/AndroidRuntime(1330): at android.os.Handler.dispatchMessage(Handler.java:99)
07-22 19:14:33.918: E/AndroidRuntime(1330): at android.os.Looper.loop(Looper.java:130)
07-22 19:14:33.918: E/AndroidRuntime(1330): at android.app.ActivityThread.main(ActivityThread.java:3683)
07-22 19:14:33.918: E/AndroidRuntime(1330): at java.lang.reflect.Method.invokeNative(Native Method)
07-22 19:14:33.918: E/AndroidRuntime(1330): at java.lang.reflect.Method.invoke(Method.java:507)
07-22 19:14:33.918: E/AndroidRuntime(1330): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
07-22 19:14:33.918: E/AndroidRuntime(1330): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
07-22 19:14:33.918: E/AndroidRuntime(1330): at dalvik.system.NativeStart.main(Native Method)
07-22 19:14:33.918: E/AndroidRuntime(1330): Caused by: android.util.AndroidRuntimeException: requestFeature() must be called before adding content
07-22 19:14:33.918: E/AndroidRuntime(1330): at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:181)
07-22 19:14:33.918: E/AndroidRuntime(1330): at android.app.Activity.requestWindowFeature(Activity.java:2729)
07-22 19:14:33.918: E/AndroidRuntime(1330): at com.inn.footprint.allmapactivity.onCreate(allmapactivity.java:36)
07-22 19:14:33.918: E/AndroidRuntime(1330): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
07-22 19:14:33.918: E/AndroidRuntime(1330): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
07-22 19:14:33.918: E/AndroidRuntime(1330): ... 11 more
回答1:
The following NotesDbAdapter has been adapted from the Notepad Tutorial on developer.android.com, think of it as a database wrapper. I've added extra fields such as lat, lon which will be the primary key, i.e how you can access the location of a marker, where your marker will be stored. And then following this code, I've also provided a modification to your class allmapactivity which is get all of the 'notes' i.e markers in your database and then populate your map with them. This code will definitely work as I've tested it! Let me know if you need further advice!
Cheers
/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import android.content.ContentValues;
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;
/**
* Simple notes database access helper class. Defines the basic CRUD operations
* for the notepad example, and gives the ability to list all notes as well as
* retrieve or modify a specific note.
*
* This has been improved from the first version of this tutorial through the
* addition of better error handling and also using returning a Cursor instead
* of using a collection of inner classes (which is less scalable and not
* recommended).
*/
public class NotesDbAdapter {
public static final String KEY_TITLE = "title";
public static final String KEY_BODY = "body";
public static final String KEY_LAT = "lat";
public static final String KEY_LON = "lon";
private static final String TAG = "NotesDbAdapter";
public DatabaseHelper mDbHelper;
public SQLiteDatabase mDb;
/**
* Database creation sql statement
*/
private static final String DATABASE_CREATE =
"CREATE TABLE notes (lat REAL, lon REAL, title varchar(60), body varchar(300), PRIMARY KEY (lat, lon));";
private static final String DATABASE_NAME = "data";
private static final String DATABASE_TABLE = "notes";
private static final int DATABASE_VERSION = 2;
private final Context mCtx;
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS notes");
onCreate(db);
}
}
/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* @param ctx the Context within which to work
*/
public NotesDbAdapter(Context ctx) {
this.mCtx = ctx;
open();
}
/**
* Open the notes database. If it cannot be opened, try to create a new
* instance of the database. If it cannot be created, throw an exception to
* signal the failure
*
* @return this (self reference, allowing this to be chained in an
* initialization call)
* @throws SQLException if the database could be neither opened or created
*/
public NotesDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void close() {
mDbHelper.close();
}
/**
* Create a new note using the title and body provided. If the note is
* successfully created return the new rowId for that note, otherwise return
* a -1 to indicate failure.
*
* @param title the title of the note
* @param body the body of the note
* @return rowId or -1 if failed
*/
public long createNote(double lat, double lon, String title, String body) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_LAT, lat);
initialValues.put(KEY_LON, lon);
initialValues.put(KEY_TITLE, title);
initialValues.put(KEY_BODY, body);
return mDb.insert(DATABASE_TABLE, null, initialValues);
}
/**
* Delete the note with the given rowId
*
* @param rowId id of note to delete
* @return true if deleted, false otherwise
*/
public boolean deleteNote(double lat, double lon) {
return mDb.delete(DATABASE_TABLE, KEY_LAT + "=" + lat + " and " + KEY_LON + "=" + lon, null) > 0;
}
/**
* Return a Cursor over the list of all notes in the database
*
* @return Cursor over all notes
*/
public Cursor fetchAllNotes() {
return mDb.query("notes", new String[] {KEY_LAT, KEY_LON,
KEY_TITLE, KEY_BODY}, null, null, null, null, null);
}
/**
* Return a Cursor positioned at the note that matches the given rowId
*
* @param rowId id of note to retrieve
* @return Cursor positioned to matching note, if found
* @throws SQLException if note could not be found/retrieved
*/
public Cursor fetchNote(double lat, double lon) {
try{
Cursor mCursor =
mDb.query(true, DATABASE_TABLE, new String[] {KEY_LAT, KEY_LON,
KEY_TITLE, KEY_BODY}, KEY_LAT + "=" + lat+ " and "+KEY_LON+"="+lon, null,
null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
catch(SQLException sqle)
{
return null;
}
}
/**
* Update the note using the details provided. The note to be updated is
* specified using the rowId, and it is altered to use the title and body
* values passed in
*
* @param rowId id of note to update
* @param title value to set note title to
* @param body value to set note body to
* @return true if the note was successfully updated, false otherwise
*/
public boolean updateNote(double lat, double lon, String title, String body) {
ContentValues args = new ContentValues();
args.put(KEY_TITLE, title);
args.put(KEY_BODY, body);
return mDb.update(DATABASE_TABLE, args, KEY_LAT + "=" + lat + " and " + KEY_LON + "=" + lon, null) > 0;
}
public boolean isEmpty()
{
try{
Cursor check = mDb.query("notes", new String[] {"lat"}, null, null, null, null, null);
}
catch(NullPointerException e)
{
return true;
}
return false;
}
}
-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
Now, the code for your class allmapactivity:
-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/-/
public class allmapactivity extends MapActivity {
MapController mControl;
GeoPoint GeoP;
MapView mapV;
Cursor cursor;
private NotesDbAdapter mDbHelper;
public ArrayList<Integer> latitude = new ArrayList<Integer>();
public ArrayList<Integer> longitude = new ArrayList<Integer>();
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.map);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mapV = (MapView) findViewById(R.id.mapview);
mapV.displayZoomControls(true);
mapV.setBuiltInZoomControls(true);
mapV.setSatellite(false);
final MapController mController = mapV.getController();
List<Overlay> mapOverlays = mapV.getOverlays();
Drawable drawable = this.getResources().getDrawable(R.drawable.pin);
mDbHelper = new NotesDbAdapter(getApplicationContext());
if(!mDbHelper.isEmpty())
{
Cursor initcursor = mDbHelper.fetchAllNotes();
initcursor.moveToFirst();
for(int i = 0; i < initcursor.getCount();i++)
{
HelloItemizedOverlay itemizedoverlay =
new HelloItemizedOverlay(drawable, allmapactivity.this);
int lat = (int) (initcursor.getDouble(initcursor.getColumnIndex("lat")) * 1E6);
int lon = (int) (initcursor.getDouble(initcursor.getColumnIndex("lon")) * 1E6);
latitude.add(lat);
longitude.add(lon);
GeoPoint geopoint = new GeoPoint(lat, lon);
String savedtitle = initcursor.getString(initcursor.getColumnIndex("title");
String savedtext = initcursor.getString(initcursor.getColumnIndex("body"));
OverlayItem overlayitem = new OverlayItem(geopoint, savedtitle, savedtext);
itemizedoverlay.addOverlay(overlayitem);
mapOverlays.add(itemizedoverlay);
initcursor.moveToNext();
}
}
String mapCenter = getMapCenter(latitude, longitude);
int latCenter = (int) (mapCenter.split(",")[0] * 1E6);
int lonCenter = (int) (mapCenter.split(",")[1] * 1E6);
GeoPoint center = new GeoPoint(latCenter, lonCenter);
mController.animateTo(center); // This will move the map focus to the central point of the markers found in the function getMapCenter();
}
public String getMapCenter(ArrayList<Integer> latitudeList, ArrayList<Integer> longitudeList)
{
// This function, as the name suggests will return the latitude, longitude of the central point of the markers found by taking the average of the latitude and longitude values of the markers
int latSum = 0;
int lonSum = 0;
double latAverage = 0;
double lonAverage = 0;
String result;
for(Integer latitudeValue: latitudeList)
{
latSum = latSum + latitudeValue;
}
for(Integer longitudeValue: longitudeList)
{
lonSum = lonSum + longitudeValue;
}
latAverage = (double) latSum/latitudeList.size();
lonAverage = (double) lonSum/longitudeList.size();
result = latAverage+","+lonAverage;
return result;
}
@Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
}
来源:https://stackoverflow.com/questions/11598400/add-markers-to-map-from-sqlite-and-center-fit-them-in-zoom-android