OsmAnd 数据流使用分析
2019-04-26 本文已影响0人
温温开水
选择目的地--》搜索页数据
由功能可以很清晰地推测出入口函数在 addTextChangedListener
//QuickSearchDialogFragment.java
searchEditText.addTextChangedListener({runSearch();})
上述代码为简写,可看到search方法为 runSearch();
runCoreSearchInternal() --> SearchUICore.search() --> searchInternal()
在 searchInternal
中执行了 search 的操作 ,代码如下
void searchInternal(final SearchPhrase phrase, SearchResultMatcher matcher) {
preparePhrase(phrase);
ArrayList<SearchCoreAPI> lst = new ArrayList<>(apis);
Collections.sort(lst, new Comparator<SearchCoreAPI>() {
@Override
public int compare(SearchCoreAPI o1, SearchCoreAPI o2) {
return Algorithms.compare(o1.getSearchPriority(phrase),
o2.getSearchPriority(phrase));
}
});
for (SearchCoreAPI api : lst) {
if (matcher.isCancelled()) {
break;
}
if (!api.isSearchAvailable(phrase) || api.getSearchPriority(phrase) == -1) {
continue;
}
try {
//具体 search 入口
api.search(phrase, matcher);
matcher.apiSearchFinished(api, phrase);
} catch (Throwable e) {
e.printStackTrace();
LOG.error(e.getMessage(), e);
}
}
}
关于 search 的操作在 SearchCoreAPI
子类中实现,打断点可看到 lst 有很多个
以搜索朝阳公园为例,最后操作在 SearchAmenityByNameAPI.search
中
search 主要是构造 req ,然后执行 r.searchPoiByName(req);
--> BinaryMapIndexReader.searchPoiByName
--> BinaryMapPoiReaderAdapter.searchPoiByName
protected void searchPoiByName(PoiRegion region, SearchRequest<Amenity> req) throws IOException {
TIntLongHashMap offsets = new TIntLongHashMap();
String query = normalizeSearchPoiByNameQuery(req.nameQuery);
CollatorStringMatcher matcher = new CollatorStringMatcher(query,
StringMatcherMode.CHECK_STARTS_FROM_SPACE);
long time = System.currentTimeMillis();
int indexOffset = codedIS.getTotalBytesRead();
while (true) {
if (req.isCancelled()) {
return;
}
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
switch (tag) {
case 0:
return;
case OsmandOdb.OsmAndPoiIndex.NAMEINDEX_FIELD_NUMBER:
int length = readInt();
int oldLimit = codedIS.pushLimit(length);
// here offsets are sorted by distance
offsets = readPoiNameIndex(matcher.getCollator(), query, req);
codedIS.popLimit(oldLimit);
break;
case OsmandOdb.OsmAndPoiIndex.POIDATA_FIELD_NUMBER:
// also offsets can be randomly skipped by limit
Integer[] offKeys = new Integer[offsets.size()];
if (offsets.size() > 0) {
int[] keys = offsets.keys();
for (int i = 0; i < keys.length; i++) {
offKeys[i] = keys[i];
}
final TIntLongHashMap foffsets = offsets;
Arrays.sort(offKeys, new Comparator<Integer>() {
@Override
public int compare(Integer object1, Integer object2) {
return Double.compare(foffsets.get(object1), foffsets.get(object2));
}
});
int p = BUCKET_SEARCH_BY_NAME * 3;
if (p < offKeys.length) {
for (int i = p + BUCKET_SEARCH_BY_NAME; ; i += BUCKET_SEARCH_BY_NAME) {
if (i > offKeys.length) {
Arrays.sort(offKeys, p, offKeys.length);
break;
} else {
Arrays.sort(offKeys, p, i);
}
p = i;
}
}
}
LOG.info("Searched poi structure in " + (System.currentTimeMillis() - time) +
"ms. Found " + offKeys.length + " subtrees");
for (int j = 0; j < offKeys.length; j++) {
codedIS.seek(offKeys[j] + indexOffset);
int len = readInt();
int oldLim = codedIS.pushLimit(len);
readPoiData(matcher, req, region);
codedIS.popLimit(oldLim);
if (req.isCancelled() || req.limitExceeded()) {
return;
}
}
LOG.info("Whole poi by name search is done in " + (System.currentTimeMillis() - time) +
"ms. Found " + req.getSearchResults().size());
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
return;
default:
skipUnknownField(t);
break;
}
}
}
这个方法为 searchByName 的核心方法,会执行 readPoiData
--> readPoiPoint
来获取数据
2.OsmAnd 数据源
OsmAnd 在使用前需要先下载一个 .obf
后缀的数据包,该数据包为 OsmAnd 的自定义地图数据包,OsmAnd app 内的大部分数据均来自于该数据包
.obf is saved in the OBF format and stores map data, which may include the placement of roads, buildings, natural objects, and walking, hiking, and biking paths. OBF files enable OsmAnd to render, route, and search maps when offline.