OsmAnd 数据流使用分析

选择目的地--》搜索页数据

由功能可以很清晰地推测出入口函数在 addTextChangedListener

//QuickSearchDialogFragment.java
        searchEditText.addTextChangedListener({runSearch();})

上述代码为简写,可看到search方法为 runSearch();

runCoreSearchInternal() --> SearchUICore.search() --> searchInternal()

searchInternal中执行了 search 的操作 ,代码如下

void searchInternal(final SearchPhrase phrase, SearchResultMatcher matcher) {
        preparePhrase(phrase);
        ArrayList lst = new ArrayList<>(apis);
        Collections.sort(lst, new Comparator() {
            @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 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() {
                        @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.

3. 数据流总结图

OsmAnd 数据流使用分析_第1张图片
数据流--end.png

你可能感兴趣的:(OsmAnd 数据流使用分析)