当前位置: 首页 > news >正文

有哪些做相册视频剪辑的网站青岛网络优化费用

有哪些做相册视频剪辑的网站,青岛网络优化费用,在线注册,运营公众号还是做网站Android Settings 系列文章: Android Settings解析SettingsIntelligenceSettingsProvider 首语 Android Settings中搜索功能帮助我们可以快速访问设置项,进行自定义设置,以得到更佳的使用体验。Android Settings搜索的实现实际不在Setting…

Android Settings 系列文章:

  • Android Settings解析
  • SettingsIntelligence
  • SettingsProvider

首语

Android Settings中搜索功能帮助我们可以快速访问设置项,进行自定义设置,以得到更佳的使用体验。Android Settings搜索的实现实际不在Settings模块里,而是存在一个单独的模块—SettingsIntelligence,它里面实现了Settings的核心搜索功能,因此,学习SettingsIntelligence搜索实现可以让我们更多了解Settings模块。

搜索实现流程

本文以Android 13 SettingsIntelligence模块源码进行分析。

首先搜索栏的跳转实现在SearchFeatureProvider的initSearchToolbar中,initSearchToolbar在Android Settings解析文章分析过,在SettingsHomepageActivity的initSearchBarView方法中调用。最终跳转到包名为com.android.settings.intelligence,action为android.settings.APP_SEARCH_SETTINGS的页面中。

public interface SearchFeatureProvider {default void initSearchToolbar(FragmentActivity activity, Toolbar toolbar, int pageId) {...final Intent intent = buildSearchIntent(context, pageId).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);...toolbar.setOnClickListener(tb -> {FeatureFactory.getFactory(context).getSlicesFeatureProvider().indexSliceDataAsync(context);FeatureFactory.getFactory(context).getMetricsFeatureProvider().logSettingsTileClick(KEY_HOMEPAGE_SEARCH_BAR, pageId);final Bundle bundle = ActivityOptions.makeSceneTransitionAnimation(activity).toBundle();activity.startActivity(intent, bundle);});}
}

它对应的模块为SettingsIntelligence,模块路径:packages/apps/SettingsIntelligence。从AndroidManifest.xml可以看到,Settings跳转搜索的页面为SearchActivity,SearchActivity添加SearchFragment,在SearchFragment中实现了搜索的核心逻辑。

查看onCreate方法,进行了一些变量的初始化,onCreateView方法中进行view初始化,设置布局为search_panel,我们只需要关注搜索框控件SearchView,设置查询字符串为mQuery,即输入搜索的内容。

设置查询监听,重写onQueryTextSubmit和onQueryTextChange方法。当搜索框文本改变时,通过restartLoaders方法调用LoadManager开启加载数据流程。当Loader创建成功时,回调onCreateLoader方法,调用getSearchResultLoader方法来SearchResultLoader实例。

public class SearchFragment extends Fragment implements SearchView.OnQueryTextListener,LoaderManager.LoaderCallbacks<List<? extends SearchResult>>, IndexingCallback {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {...	mSearchView = toolbar.findViewById(R.id.search_view);mSearchView.setQuery(mQuery, false /* submitQuery */);mSearchView.setOnQueryTextListener(this);mSearchView.requestFocus();return view;}  @Overridepublic boolean onQueryTextChange(String query) {...if (isEmptyQuery) {final LoaderManager loaderManager = getLoaderManager();loaderManager.destroyLoader(SearchCommon.SearchLoaderId.SEARCH_RESULT);mShowingSavedQuery = true;mSavedQueryController.loadSavedQueries();mSearchFeatureProvider.hideFeedbackButton(getView());} else {mMetricsFeatureProvider.logEvent(SettingsIntelligenceEvent.PERFORM_SEARCH);restartLoaders();}return true;}@Overridepublic boolean onQueryTextSubmit(String query) {// Save submitted query.mSavedQueryController.saveQuery(mQuery);hideKeyboard();return true;}private void restartLoaders() {mShowingSavedQuery = false;final LoaderManager loaderManager = getLoaderManager();loaderManager.restartLoader(SearchCommon.SearchLoaderId.SEARCH_RESULT,null /* args */, this /* callback */);}@Overridepublic Loader<List<? extends SearchResult>> onCreateLoader(int id, Bundle args) {final Activity activity = getActivity();switch (id) {case SearchCommon.SearchLoaderId.SEARCH_RESULT:return mSearchFeatureProvider.getSearchResultLoader(activity, mQuery);default:return null;}}
}

在SearchFeatureProvider实现类SearchFeatureProviderImpl中创建了SearchResultLoader实例,SearchResultLoader在子线程进行数据查找。

public class SearchResultLoader extends AsyncLoader<List<? extends SearchResult>> {private final String mQuery;public SearchResultLoader(Context context, String query) {super(context);mQuery = query;}@Overridepublic List<? extends SearchResult> loadInBackground() {SearchResultAggregator aggregator = SearchResultAggregator.getInstance();return aggregator.fetchResults(getContext(), mQuery);}
}

fetchResults方法进行数据查找,并创建了一个tasks集合,然后变量tasks,保存到taskResults中。

public class SearchResultAggregator {@NonNullpublic synchronized List<? extends SearchResult> fetchResults(Context context, String query) {final SearchFeatureProvider mFeatureProvider = FeatureFactory.get(context).searchFeatureProvider();final ExecutorService executorService = mFeatureProvider.getExecutorService();final List<SearchQueryTask> tasks =mFeatureProvider.getSearchQueryTasks(context, query);// Start tasksfor (SearchQueryTask task : tasks) {executorService.execute(task);}// Collect resultsfinal Map<Integer, List<? extends SearchResult>> taskResults = new ArrayMap<>();final long allTasksStart = System.currentTimeMillis();for (SearchQueryTask task : tasks) {final int taskId = task.getTaskId();try {taskResults.put(taskId,task.get(SHORT_CHECK_TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS));} catch (TimeoutException | InterruptedException | ExecutionException e) {Log.d(TAG, "Could not retrieve result in time: " + taskId, e);taskResults.put(taskId, Collections.EMPTY_LIST);}}// Merge resultsfinal List<? extends SearchResult> mergedResults = mergeSearchResults(taskResults);return mergedResults;}
}

getSearchQueryTasks中构建了各种类型的task,如DatabaseResultTask/InstalledAppResultTask等等。这些task都继承于SearchQueryTask.QueryWorker。

public class SearchFeatureProviderImpl implements SearchFeatureProvider {@Overridepublic List<SearchQueryTask> getSearchQueryTasks(Context context, String query) {final List<SearchQueryTask> tasks = new ArrayList<>();final String cleanQuery = cleanQuery(query);tasks.add(DatabaseResultTask.newTask(context, getSiteMapManager(), cleanQuery));tasks.add(InstalledAppResultTask.newTask(context, getSiteMapManager(), cleanQuery));tasks.add(AccessibilityServiceResultTask.newTask(context, getSiteMapManager(), cleanQuery));tasks.add(InputDeviceResultTask.newTask(context, getSiteMapManager(), cleanQuery));return tasks;}
}

而SearchQueryTask又继承于FutureTask,call方法去处理任务,完成后返回结果。

public class SearchQueryTask extends FutureTask<List<? extends SearchResult>> {public static abstract class QueryWorker implements Callable<List<? extends SearchResult>> {@Overridepublic List<? extends SearchResult> call() throws Exception {final long startTime = System.currentTimeMillis();try {return query();} finally {final long endTime = System.currentTimeMillis();FeatureFactory.get(mContext).metricsFeatureProvider(mContext).logEvent(getQueryWorkerId(), endTime - startTime);}}}
}

我们以DatabaseResultTask为例,查看它实现的query方法。query方法通过一系列的查询方法将数据添加到resultSet中,可以看到query方法中获取SQLite数据库实例,IndexDatabaseHelper中初始化数据库,可以看到数据库名为search_index.db,表名和表字段。最后通过query方法查询数据。

public class DatabaseResultTask extends SearchQueryTask.QueryWorker {public static SearchQueryTask newTask(Context context, SiteMapManager siteMapManager,String query) {return new SearchQueryTask(new DatabaseResultTask(context, siteMapManager, query));}@Overrideprotected List<? extends SearchResult> query() {if (mQuery == null || mQuery.isEmpty()) {return new ArrayList<>();}// Start a Future to get search result scores.FutureTask<List<Pair<String, Float>>> rankerTask = mFeatureProvider.getRankerTask(mContext, mQuery);if (rankerTask != null) {ExecutorService executorService = mFeatureProvider.getExecutorService();executorService.execute(rankerTask);}final Set<SearchResult> resultSet = new HashSet<>();resultSet.addAll(firstWordQuery(MATCH_COLUMNS_PRIMARY, BASE_RANKS[0]));resultSet.addAll(secondaryWordQuery(MATCH_COLUMNS_PRIMARY, BASE_RANKS[1]));resultSet.addAll(anyWordQuery(MATCH_COLUMNS_SECONDARY, BASE_RANKS[2]));resultSet.addAll(anyWordQuery(MATCH_COLUMNS_TERTIARY, BASE_RANKS[3]));// Try to retrieve the scores in time. Otherwise use static ranking.if (rankerTask != null) {try {final long timeoutMs = mFeatureProvider.smartSearchRankingTimeoutMs(mContext);List<Pair<String, Float>> searchRankScores = rankerTask.get(timeoutMs,TimeUnit.MILLISECONDS);return getDynamicRankedResults(resultSet, searchRankScores);} catch (TimeoutException | InterruptedException | ExecutionException e) {Log.d(TAG, "Error waiting for result scores: " + e);}}List<SearchResult> resultList = new ArrayList<>(resultSet);Collections.sort(resultList);return resultList;}private Set<SearchResult> firstWordQuery(String[] matchColumns, int baseRank) {final String whereClause = buildSingleWordWhereClause(matchColumns);final String query = mQuery + "%";final String[] selection = buildSingleWordSelection(query, matchColumns.length);return query(whereClause, selection, baseRank);}private Set<SearchResult> query(String whereClause, String[] selection, int baseRank) {final SQLiteDatabase database =IndexDatabaseHelper.getInstance(mContext).getReadableDatabase();//查询搜索数据try (Cursor resultCursor = database.query(TABLE_PREFS_INDEX, SELECT_COLUMNS,whereClause,selection, null, null, null)) {return mConverter.convertCursor(resultCursor, baseRank, mSiteMapManager);}}
}

那么问题来了,Settings搜索数据存储在SQLite数据库中,我们分析了它的查询流程,那么它是如何存储的呢?

其实在SearchFragment的onCreate就有实现,通过updateIndexAsync刷新数据。

public class SearchFragment extends Fragment implements SearchView.OnQueryTextListener,LoaderManager.LoaderCallbacks<List<? extends SearchResult>>, IndexingCallback {...mSearchFeatureProvider.updateIndexAsync(getContext(), this /* indexingCallback */);            
}

通过indexDatabase方法更新数据。

public class SearchFeatureProviderImpl implements SearchFeatureProvider {@Overridepublic void updateIndexAsync(Context context, IndexingCallback callback) {if (DEBUG) {Log.d(TAG, "updating index async");}getIndexingManager(context).indexDatabase(callback);}
}

IndexingTask继承于AsyncTask。异步执行performIndexing方法,通过queryIntentContentProviders方法获取ContentProvider,然后根据provider查找数据,更新到数据库中。看下intent指定的action PROVIDER_INTERFACE为"android.content.action.SEARCH_INDEXABLES_PROVIDER",在Settings查找是否有定义此action的ContentProvider。

public class DatabaseIndexingManager {public void indexDatabase(IndexingCallback callback) {IndexingTask task = new IndexingTask(callback);task.execute();}public class IndexingTask extends AsyncTask<Void, Void, Void> {@VisibleForTestingIndexingCallback mCallback;private long mIndexStartTime;public IndexingTask(IndexingCallback callback) {mCallback = callback;}@Overrideprotected void onPreExecute() {mIndexStartTime = System.currentTimeMillis();mIsIndexingComplete.set(false);}@Overrideprotected Void doInBackground(Void... voids) {performIndexing();return null;}@Overrideprotected void onPostExecute(Void aVoid) {int indexingTime = (int) (System.currentTimeMillis() - mIndexStartTime);FeatureFactory.get(mContext).metricsFeatureProvider(mContext).logEvent(SettingsIntelligenceLogProto.SettingsIntelligenceEvent.INDEX_SEARCH,indexingTime);mIsIndexingComplete.set(true);if (mCallback != null) {mCallback.onIndexingFinished();}}}public void performIndexing() {final Intent intent = new Intent(SearchIndexablesContract.PROVIDER_INTERFACE);final List<ResolveInfo> providers =mContext.getPackageManager().queryIntentContentProviders(intent, 0);final boolean isFullIndex = IndexDatabaseHelper.isFullIndex(mContext, providers);if (isFullIndex) {rebuildDatabase();}PreIndexData indexData = getIndexDataFromProviders(providers, isFullIndex);final long updateDatabaseStartTime = System.currentTimeMillis();updateDatabase(indexData, isFullIndex);IndexDatabaseHelper.setIndexed(mContext, providers);if (DEBUG) {final long updateDatabaseTime = System.currentTimeMillis() - updateDatabaseStartTime;Log.d(TAG, "performIndexing updateDatabase took time: " + updateDatabaseTime);}}
}

可以发现,在Settings的AndroidManifest.xml中指定一个Provider。

<providerandroid:name=".search.SettingsSearchIndexablesProvider"android:authorities="com.android.settings"android:multiprocess="false"android:grantUriPermissions="true"android:permission="android.permission.READ_SEARCH_INDEXABLES"android:exported="true"><intent-filter><action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" /></intent-filter></provider>

SettingsSearchIndexablesProvider继承于SearchIndexablesProvider,SearchIndexablesProvider继承于ContentProvider, query方法进行了分类查询,插入,删除,更新均不支持,通过final修饰和抛出UnsupportedOperationException屏蔽了。

public abstract class SearchIndexablesProvider extends ContentProvider {@Overridepublic Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder) {try {switch (mMatcher.match(uri)) {case MATCH_RES_CODE:return queryXmlResources(null);case MATCH_RAW_CODE:return queryRawData(null);case MATCH_NON_INDEXABLE_KEYS_CODE:return queryNonIndexableKeys(null);case MATCH_SITE_MAP_PAIRS_CODE:return querySiteMapPairs();case MATCH_SLICE_URI_PAIRS_CODE:return querySliceUriPairs();case MATCH_DYNAMIC_RAW_CODE:return queryDynamicRawData(null);default:throw new UnsupportedOperationException("Unknown Uri " + uri);}} catch (UnsupportedOperationException e) {throw e;} catch (Exception e) {Log.e(TAG, "Provider querying exception:", e);return null;}}@Overridepublic final Uri insert(Uri uri, ContentValues values) {throw new UnsupportedOperationException("Insert not supported");}
}

以queryXmlResources为例,通过getSearchIndexableResourcesFromProvider方法获取数据集合,并保存到cursor中。bundles里一个class类型的集合。

public class SettingsSearchIndexablesProvider extends SearchIndexablesProvider {@Overridepublic Cursor queryXmlResources(String[] projection) {final MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);final List<SearchIndexableResource> resources =getSearchIndexableResourcesFromProvider(getContext());for (SearchIndexableResource val : resources) {final Object[] ref = new Object[INDEXABLES_XML_RES_COLUMNS.length];ref[COLUMN_INDEX_XML_RES_RANK] = val.rank;ref[COLUMN_INDEX_XML_RES_RESID] = val.xmlResId;ref[COLUMN_INDEX_XML_RES_CLASS_NAME] = val.className;ref[COLUMN_INDEX_XML_RES_ICON_RESID] = val.iconResId;ref[COLUMN_INDEX_XML_RES_INTENT_ACTION] = val.intentAction;ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE] = val.intentTargetPackage;ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS] = null; // intent target classcursor.addRow(ref);}return cursor;}private List<SearchIndexableResource> getSearchIndexableResourcesFromProvider(Context context) {final Collection<SearchIndexableData> bundles = FeatureFactory.getFactory(context).getSearchFeatureProvider().getSearchIndexableResources().getProviderValues();List<SearchIndexableResource> resourceList = new ArrayList<>();for (SearchIndexableData bundle : bundles) {Indexable.SearchIndexProvider provider = bundle.getSearchIndexProvider();final List<SearchIndexableResource> resList =provider.getXmlResourcesToIndex(context, true);if (resList == null) {continue;}for (SearchIndexableResource item : resList) {item.className = TextUtils.isEmpty(item.className)? bundle.getTargetClass().getName(): item.className;}resourceList.addAll(resList);}return resourceList;}
}

SearchIndexableResourcesMobile继承于SearchIndexableResourcesBase,

public class SearchFeatureProviderImpl implements SearchFeatureProvider {@Overridepublic SearchIndexableResources getSearchIndexableResources() {if (mSearchIndexableResources == null) {mSearchIndexableResources = new SearchIndexableResourcesMobile();}return mSearchIndexableResources;}
}

SearchIndexableResourcesMobile类生成在IndexableProcessor中,IndexableProcessor设置的注解为SearchIndexable,SearchIndexable注解可以指定target(ALL/MOBILE/TV/WEAR/AUTO/ARC)对应不同平台。通过JavaPoet库来addCode实例化SearchIndexableData,getProviderValues方法返回的是带有SearchIndexable注解的所有类集合。

@SupportedSourceVersion(SourceVersion.RELEASE_9)
@SupportedAnnotationTypes({"com.android.settingslib.search.SearchIndexable"})
public class IndexableProcessor extends AbstractProcessor {@Overridepublic boolean process(Set<? extends TypeElement> annotations,for (Element element : roundEnvironment.getElementsAnnotatedWith(SearchIndexable.class)) {if (element.getKind().isClass()) {Name className = element.accept(new SimpleElementVisitor8<Name, Void>() {@Overridepublic Name visitType(TypeElement typeElement, Void aVoid) {return typeElement.getQualifiedName();}}, null);if (className != null) {SearchIndexable searchIndexable = element.getAnnotation(SearchIndexable.class);int forTarget = searchIndexable.forTarget();MethodSpec.Builder builder = baseConstructorBuilder;if (forTarget == SearchIndexable.ALL) {builder = baseConstructorBuilder;} else if ((forTarget & SearchIndexable.MOBILE) != 0) {builder = mobileConstructorBuilder;} else if ((forTarget & SearchIndexable.TV) != 0) {builder = tvConstructorBuilder;} else if ((forTarget & SearchIndexable.WEAR) != 0) {builder = wearConstructorBuilder;} else if ((forTarget & SearchIndexable.AUTO) != 0) {builder = autoConstructorBuilder;} else if ((forTarget & SearchIndexable.ARC) != 0) {builder = arcConstructorBuilder;}//实例化SearchIndexableDatabuilder.addCode("$N(new SearchIndexableData($L.class, $L"+ ".SEARCH_INDEX_DATA_PROVIDER));\n",addIndex, className, className);...}}inal MethodSpec getProviderValues = MethodSpec.methodBuilder("getProviderValues").addAnnotation(Override.class).addModifiers(Modifier.PUBLIC).returns(ParameterizedTypeName.get(ClassName.get(Collection.class),searchIndexableData)).addCode("return $N;\n", providers).build();final TypeSpec baseClass = TypeSpec.classBuilder(CLASS_BASE).addModifiers(Modifier.PUBLIC).addSuperinterface(ClassName.get(PACKAGE, "SearchIndexableResources")).addField(providers).addMethod(baseConstructorBuilder.build()).addMethod(addIndex).addMethod(getProviderValues).build();final JavaFile searchIndexableResourcesBase = JavaFile.builder(PACKAGE, baseClass).build();final JavaFile searchIndexableResourcesMobile = JavaFile.builder(PACKAGE,TypeSpec.classBuilder(CLASS_MOBILE).addModifiers(Modifier.PUBLIC).superclass(ClassName.get(PACKAGE, baseClass.name)).addMethod(mobileConstructorBuilder.build()).build()).build();
}

实例化SearchIndexableData,mTargetClass为className.class,mSearchIndexProvider为className.SEARCH_INDEX_DATA_PROVIDER,其中的className就是对应添加SearchIndexable注解的类名

public class SearchIndexableData {public SearchIndexableData(Class targetClass, Indexable.SearchIndexProvider provider) {mTargetClass = targetClass;mSearchIndexProvider = provider;}
}

总结一下,Settings搜索功能就是在需要被提供的页面添加@SearchIndexable注解,在这页面创建一个常量SEARCH_INDEX_DATA_PROVIDER,这个常量类型必须为Indexable.SearchIndexProvider。以TopLevelSettings为例。添加了@SearchIndexable注解,指定Target为MOBILE,也创建了SEARCH_INDEX_DATA_PROVIDER,Settings封装了一个基础的SearchIndexProvider,不返回任何要索引的数据,类名为BaseSearchIndexProvider。

@SearchIndexable(forTarget = MOBILE)
public class TopLevelSettings extends DashboardFragment implements SplitLayoutListener,PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =new BaseSearchIndexProvider(R.xml.top_level_settings) {@Overrideprotected boolean isPageSearchEnabled(Context context) {// Never searchable, all entries in this page are already indexed elsewhere.return false;}};
}

SearchIndexProvider和BaseSearchIndexProvider扩展的方法可以让我们准确处理菜单搜索需求。

public class BaseSearchIndexProvider implements Indexable.SearchIndexProvider {public BaseSearchIndexProvider() {}public BaseSearchIndexProvider(int xmlRes) {mXmlRes = xmlRes;}//返回SearchIndexableResource@Overridepublic List<SearchIndexableResource> getXmlResourcesToIndex(Context context, boolean enabled) {if (mXmlRes != 0) {final SearchIndexableResource sir = new SearchIndexableResource(context);sir.xmlResId = mXmlRes;return Arrays.asList(sir);}return null;}//返回SearchIndexableRaw集合@Overridepublic List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {return null;}//返回动态数据集合@Overridepublic List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {return null;}//无法搜索的集合@Override@CallSuperpublic List<String> getNonIndexableKeys(Context context) {...}//页面是否启用搜索protected boolean isPageSearchEnabled(Context context) {return true;}//获取xml设置禁用搜索的集合@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)public List<String> getNonIndexableKeysFromXml(Context context, @XmlRes int xmlResId,boolean suppressAllPage) {return getKeysFromXml(context, xmlResId, suppressAllPage);}
}

以上就是Settings的搜索逻辑。要测试新菜单的可搜索性,需要先清除Settings数据,让数据库重新添加数据。

总结

Settings菜单如果想要支持搜索,首先对应页面需要添加@SearchIndexable注解,其次在本页面创建一个常量SEARCH_INDEX_DATA_PROVIDER,然后根据需要重写需要的实现方法。这样这个菜单就支持搜索了。

SettingsIntelligence会扫描这些添加@SearchIndexable注解的页面,将这些页面的菜单添加到数据库中,查询时根据关键词进行匹配查询。


文章转载自:
http://patriarchic.gtqx.cn
http://ticca.gtqx.cn
http://acarpous.gtqx.cn
http://notaphily.gtqx.cn
http://phosphorescent.gtqx.cn
http://monostable.gtqx.cn
http://pyroborate.gtqx.cn
http://cornfed.gtqx.cn
http://rangership.gtqx.cn
http://northwestward.gtqx.cn
http://cichlid.gtqx.cn
http://scald.gtqx.cn
http://virose.gtqx.cn
http://chloride.gtqx.cn
http://thousand.gtqx.cn
http://bookkeeper.gtqx.cn
http://isotron.gtqx.cn
http://satanism.gtqx.cn
http://calendric.gtqx.cn
http://shedder.gtqx.cn
http://hierarchy.gtqx.cn
http://androstenedione.gtqx.cn
http://umbrette.gtqx.cn
http://coomassie.gtqx.cn
http://maldivian.gtqx.cn
http://germinability.gtqx.cn
http://aceldama.gtqx.cn
http://antisexual.gtqx.cn
http://pretzel.gtqx.cn
http://crawdad.gtqx.cn
http://amaigamate.gtqx.cn
http://processionist.gtqx.cn
http://belgrade.gtqx.cn
http://greenback.gtqx.cn
http://unrestraint.gtqx.cn
http://counterplead.gtqx.cn
http://stumpy.gtqx.cn
http://rout.gtqx.cn
http://nonet.gtqx.cn
http://adele.gtqx.cn
http://didact.gtqx.cn
http://unquarried.gtqx.cn
http://hcl.gtqx.cn
http://quinquecentennial.gtqx.cn
http://preventorium.gtqx.cn
http://bicuculline.gtqx.cn
http://commuterdom.gtqx.cn
http://requital.gtqx.cn
http://noctambulist.gtqx.cn
http://vitrine.gtqx.cn
http://which.gtqx.cn
http://heptagonal.gtqx.cn
http://lye.gtqx.cn
http://knell.gtqx.cn
http://agapanthus.gtqx.cn
http://hijacker.gtqx.cn
http://unwincing.gtqx.cn
http://firing.gtqx.cn
http://containerport.gtqx.cn
http://lessness.gtqx.cn
http://calumniatory.gtqx.cn
http://egregiously.gtqx.cn
http://externalise.gtqx.cn
http://clostridium.gtqx.cn
http://begat.gtqx.cn
http://drang.gtqx.cn
http://roentgenoscope.gtqx.cn
http://overbodice.gtqx.cn
http://hifi.gtqx.cn
http://parable.gtqx.cn
http://electrodialytic.gtqx.cn
http://pieria.gtqx.cn
http://gcm.gtqx.cn
http://dat.gtqx.cn
http://tonsure.gtqx.cn
http://ber.gtqx.cn
http://ostracize.gtqx.cn
http://valetta.gtqx.cn
http://unpredictable.gtqx.cn
http://sloping.gtqx.cn
http://sublabial.gtqx.cn
http://bentonitic.gtqx.cn
http://turbit.gtqx.cn
http://cursed.gtqx.cn
http://vocation.gtqx.cn
http://skibobbing.gtqx.cn
http://thorianite.gtqx.cn
http://anthropogenesis.gtqx.cn
http://algaecide.gtqx.cn
http://slinky.gtqx.cn
http://skean.gtqx.cn
http://raa.gtqx.cn
http://heavy.gtqx.cn
http://stetson.gtqx.cn
http://wga.gtqx.cn
http://baton.gtqx.cn
http://zoftig.gtqx.cn
http://luciferase.gtqx.cn
http://insula.gtqx.cn
http://newground.gtqx.cn
http://www.15wanjia.com/news/66342.html

相关文章:

  • wordpress编辑页面的颜色哈尔滨优化网站方法
  • 怎么做网站站内优化网络推广公司有哪些
  • wordpress 获取当前文章的分类id跟我学seo
  • 网站开发技术员游戏广告投放平台
  • 国外化妆品网站模板腾讯企点app
  • 国家企业信息公示系统官网(全国)网站建设优化推广系统
  • 建一个网站需要什么条件沈阳seo顾问
  • 政务网站建设管理今天的最新消息新闻
  • 平凉市建设局网站企业邮箱入口
  • 大型购物网站深圳网站制作公司
  • 太原网站建设电话廊坊seo
  • 网站建设 钱武汉seo技术
  • 天津做网站哪个公司好如何做网站推广优化
  • 静态单页网站wordpress郑州专业seo首选
  • 做公司的网站怎么上线关键词代做排名推广
  • 刚建设的网站如何推广如何创建自己的小程序
  • 跨境b2b网站有哪些今日西安头条最新消息
  • 石家庄网站制作报价seo关键词排名优化是什么
  • 做网站教程百度云我想找一个营销团队
  • 一个完整网站开发需要什么技术商品推广软文写作500字
  • 做网站图片广告推广怎么忽悠人的十大免费b2b网站
  • 《美食天下》网站的建设企业推广网站有哪些
  • 济南兼职做网站网络营销类型
  • 网站商品台管理系统关键词全网搜索
  • 做网站的公司算外包公司吗seo技术顾问阿亮
  • 经典网站域名企业培训课程有哪些
  • 上海seo网络推广公司国内搜索引擎优化的公司
  • seo排名优化怎样优化系统软件
  • 建设银行网站是什么百度提问登陆入口
  • 开单独网站做a货鞋多层次网络营销合法吗