本文旨在教你打造一个真实的一个图片浏览器,并非写一堆链接用来测试;也算是用到Android基本的常用的知识,对于初学者来说是一个不错的练手demo;当然本文对于图片加载也有自己的一些见解,希望可以帮助到各位;

                 

                

首先在开始讲解前要感谢一下github开源社区给了我很多帮助,相信不少人也从这里获取到自己想要的东西,当然如果有能力也是希望可以回馈社区;

再此列出在项目中用到的开源框架:

网络访问框架volley,这个大概大家都知道无需解释:

https://github.com/mcxiaoke/android-volley,详细学习请移至http://hukai.me/android-training-course-in-chinese/connectivity/volley/index.html

图片加载框架universal-image-loader这个谁用谁知道,当然也有不少陷阱:

https://github.com/nostra13/Android-Universal-Image-Loader,详细学习请移至http://codekk.com/open-source-project-analysis

下拉刷新框架android-Ultra-Pull-to-Refresh使用简单定制方便:

https://github.com/liaohuqiu/android-Ultra-Pull-To-Refresh

RippleEffect一个实现Material Design Ripple效果的库:

https://github.com/traex/RippleEffect,其实你仔细看他的实现相信你也可以做到

Stackblur高斯模糊框架,我在上一篇博客中有提到高斯模糊制作启动界面:

https://github.com/kikoso/android-stackblur

Gson解决对象和json的转换,方便简单快速:

https://github.com/google/gson,项目中虽然没有用到,因为字段比较少就省了,但是还是建议去用用

当然还得介绍一下android-open-project,进去看了就明白

https://github.com/Trinea/android-open-project

好了该感谢的都感谢完了,下面切入我们的正题;首先要解决的问题就是数据,app没有数据总是华而不实的,当然这里也不是要我们自己写服务器;

数据来源:百度图片api

http://image.baidu.com/channel/listjson?pn=0&rn=30&tag1=美女&tag2=全部,打开链接可以看到返回的json数据

参数详细介绍

pn:从第几项开始加载

rn:加载多少项

tag1:大分类(既然是美女图,那么这里就填美女喽)

tag2:小分类(例如:清纯,性感,气质...等等,可以去百度图片看看分类)

上面的链接解释就是:从第0项加载30个所有美女类型的图片;

如果要加载第二页呢?pn=30,其他不变;详细可以移至http://blog.csdn.net/yuanwofei/article/details/16343743,不过这篇博客有些时候了,可能用法上有误,pn不是页数;

项目结构及分包:

如果是为了测试其实倒也无所谓,但是这里我还是要做到一定的规范;正所谓写代码很容易,写好却不容易:

包结构图


  • .util:存放app所需的工具类,这个模块不只是这一个项目会用到,大多数项目都可以复用。
  • .view:自定义view存放目录
  • .app:存放application类,app的入口用于初始化全局的一些东西

其他包就不多加解释了;

界面布局

欢迎界面

欢迎界面的高斯模糊效果请移至高斯模糊制作启动界面

主界面

头部是一个Toolbar,Toolbar右侧是一个menu用于弹出美女类型的popwindow;

内容区域是一个GirdView,附在下拉刷新布局中;

查看大图界面

一个viewpager,每个view是一个ImageView;

界面布局大致就是这样,是不是感觉很简单;

主界面:

Activity布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><include layout="@layout/toolbar" /><FrameLayoutandroid:id="@+id/fragmentContainer"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>

Toolbar

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res/com.xiaozhi.beautygallery"android:id="@+id/toolbar"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="?attr/colorPrimary"android:minHeight="?attr/actionBarSize"app:popupTheme="@style/ThemeOverlay.AppCompat.Light"android:visibility="gone"android:theme="@style/ThemeOverlay.AppCompat.ActionBar" ></android.support.v7.widget.Toolbar>

Fragment布局

<?xml version="1.0" encoding="utf-8"?>
<in.srain.cube.views.ptr.PtrFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"android:id="@+id/rotate_header_grid_view_frame"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/background_material_dark"cube_ptr:ptr_duration_to_close="200"cube_ptr:ptr_duration_to_close_header="1000"cube_ptr:ptr_keep_header_when_refresh="true"cube_ptr:ptr_pull_to_fresh="false"cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"cube_ptr:ptr_resistance="1.7" ><GridViewandroid:id="@+id/gridView"android:layout_width="match_parent"android:layout_height="match_parent"android:fadingEdge="none"android:focusable="false"android:horizontalSpacing="@dimen/image_padding"android:listSelector="@null"android:numColumns="2"android:verticalSpacing="@dimen/image_padding" /></in.srain.cube.views.ptr.PtrFrameLayout>

GridView item布局

<?xml version="1.0" encoding="utf-8"?>
<com.xiaozhi.beautygallery.view.RippleView xmlns:android="http://schemas.android.com/apk/res/android"xmlns:ripple="http://schemas.android.com/apk/res-auto"android:id="@+id/rect"android:layout_width="match_parent"android:layout_height="match_parent"ripple:rv_alpha="50"ripple:rv_rippleDuration="100"ripple:rv_type="rectangle"ripple:rv_zoom="true"ripple:rv_zoomDuration="150" ><ImageViewandroid:id="@+id/imageView"android:layout_width="match_parent"android:layout_height="@dimen/image_height"android:contentDescription="@string/app_name"android:scaleType="centerCrop" /></com.xiaozhi.beautygallery.view.RippleView>

GridView底部布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/foot_view_layout"android:layout_width="fill_parent"android:layout_height="50dp"android:layout_columnSpan="2"android:gravity="center"android:orientation="horizontal"android:background="@drawable/footer_bg"><ProgressBarandroid:id="@+id/footer_loading"style="@android:style/Widget.ProgressBar.Small.Inverse"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center" /><TextViewandroid:id="@+id/footview_text"android:layout_width="wrap_content"android:layout_height="50dip"android:layout_gravity="center"android:gravity="center"android:textColor="@android:color/white"android:textSize="15sp"android:textStyle="bold" /><Buttonandroid:id="@+id/footview_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_marginLeft="5dp"android:background="@null"android:text="refresh" /></LinearLayout>

Popwindow布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/pop_win_bg"android:orientation="vertical"android:padding="@dimen/image_padding" ><GridViewandroid:id="@+id/popGridView"android:layout_width="match_parent"android:layout_height="match_parent"android:fadingEdge="none"android:focusable="false"android:gravity="center"android:horizontalSpacing="@dimen/image_padding"android:listSelector="@drawable/shape_more_pop"android:numColumns="5"android:verticalSpacing="@dimen/image_padding" /></LinearLayout>

实现

SingleFragmentActivity所有以fragment为布局的activity继承该类:

public abstract class SingleFragmentActivity extends AppCompatActivity {protected abstract Fragment createFragment();@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取FragmentManager对象FragmentManager fm = getSupportFragmentManager();// 获取fragmentFragment fragment = fm.findFragmentById(R.id.fragmentContainer);// fragment事务if (fragment == null) {fragment = createFragment();fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();}}}

MainActivity主界面activity

public class MainActivity extends SingleFragmentActivity {private Toolbar mToolbar;private MorePopWindow mMorePopWindow;private Fragment mFragment;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);initViews();}protected void initViews() {mToolbar = (Toolbar) findViewById(R.id.toolbar);mToolbar.setVisibility(View.VISIBLE);setSupportActionBar(mToolbar);mMorePopWindow = new MorePopWindow(this);mMorePopWindow.setOnMorePopWindowItemClickListener(new OnMorePopWindowItemClickListener() {@Overridepublic void onItemClick(int position, String item) {if (mFragment instanceof FragmentMain) {((FragmentMain) mFragment).changeOtherBeautyType(item);}}});mToolbar.setOnMenuItemClickListener(new OnMenuItemClickListener() {@Overridepublic boolean onMenuItemClick(MenuItem item) {switch (item.getItemId()) {case R.id.action_more:showMorePopWindow();break;default:break;}return false;}});}protected void showMorePopWindow() {// 显示窗口mMorePopWindow.showAsDropDown(mToolbar);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();if (id == R.id.action_more) {return true;}return super.onOptionsItemSelected(item);}@Overrideprotected Fragment createFragment() {mFragment = new FragmentMain();return mFragment;}
}

FragmentMain显示图片列表fragment

public class FragmentMain extends Fragment {private static final String TAG = "FragmentMain";/** 从第几项开始加载图片*/private int pn;private String tag2;private String oldTag2;private GridView mGridView;private MyGridViewAdapter mAdapter;public static List<Image> mListImages = new ArrayList<Image>();private View view;private PtrFrameLayout mFrame;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {view = inflater.inflate(R.layout.fragment_main, container, false);initViews();return view;}private void initViews() {tag2 = CustomUtil.getInstance().getString(VolleyUtil.TAG2);if (tag2 == null) {tag2 = VolleyUtil.TAG2_DEFAULT;CustomUtil.getInstance().save(VolleyUtil.TAG2, tag2);}oldTag2 = tag2;mGridView = (GridView) view.findViewById(R.id.gridView);mAdapter = new MyGridViewAdapter(getActivity(), mListImages);mAdapter.setLoadListener(new LoadListener() {@Overridepublic void onLoad() {loadNextPage();}});mGridView.setAdapter(mAdapter);mFrame = (PtrFrameLayout) view.findViewById(R.id.rotate_header_grid_view_frame);StoreHouseHeader header = new StoreHouseHeader(getActivity());header.setPadding(0, 15, 0, 15);header.initWithString("Loading...");mFrame.setDurationToCloseHeader(1500);mFrame.setHeaderView(header);mFrame.addPtrUIHandler(header);mFrame.postDelayed(new Runnable() {@Overridepublic void run() {mFrame.autoRefresh(false);}}, 100);mFrame.setPtrHandler(new PtrHandler() {@Overridepublic boolean checkCanDoRefresh(PtrFrameLayout frame,View content, View header) {return PtrDefaultHandler.checkContentCanBePulledDown(frame,content, header);}@Overridepublic void onRefreshBegin(PtrFrameLayout frame) {mListImages.clear();pn = 0;if (!oldTag2.equals(tag2)) {CustomUtil.getInstance().save(VolleyUtil.TAG2, tag2);oldTag2 = tag2;}loadItems();}});}/*** 加载一页数据*/private void loadItems() {JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET,VolleyUtil.getInstance().getUrl(pn, tag2), null,new Listener<JSONObject>() {@Overridepublic void onResponse(JSONObject jsonObject) {VolleyUtil.parseItems(mListImages, jsonObject);mFrame.refreshComplete();updateAdapter();mAdapter.setFooterViewStatus(FooterView.MORE);}}, new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError arg0) {Toast.makeText(getActivity(), R.string.loading_error,Toast.LENGTH_SHORT).show();mFrame.refreshComplete();}});VolleyUtil.getInstance().addToRequestQueue(request);}/*** 加载下一页数据*/private void loadNextPage() {if (mAdapter != null) {mAdapter.setFooterViewStatus(FooterView.LOADING);}pn += VolleyUtil.PAGE_SIZE;loadItems();}private void updateAdapter() {mAdapter.notifyDataSetChanged();}public void changeOtherBeautyType(String tag2) {this.tag2 = tag2;mFrame.autoRefresh();}
}

MorePopWindow显示美女类型

public class MorePopWindow extends PopupWindow {private View mMoreView;private LayoutInflater mInflater;private Context mContext;private GridView mGridView;private ArrayAdapter<String> mAdapter;private List<String> mList;private String[] mBeautyTypes;private PopupWindow mPopupWindow;private int mCurrentPosition = 0;public MorePopWindow(Context context) {super(context);this.mContext = context;mPopupWindow = this;mInflater = LayoutInflater.from(mContext);mMoreView = mInflater.inflate(R.layout.view_more_pop, null);mGridView = (GridView) mMoreView.findViewById(R.id.popGridView);initStrings();mAdapter = new ArrayAdapter<String>(mContext,R.layout.view_more_pop_item, mBeautyTypes);mGridView.setAdapter(mAdapter);mGridView.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {if (mOnMorePopWindowItemClickListener != null) {mOnMorePopWindowItemClickListener.onItemClick(position,mBeautyTypes[position]);}parent.getChildAt(mCurrentPosition).setBackgroundColor(Color.TRANSPARENT);view.setBackgroundResource(R.drawable.shape_more_pop);mCurrentPosition = position;mPopupWindow.dismiss();Log.d("More", "onItemClick:" + position);}});// 设置SelectPicPopupWindow的Viewthis.setContentView(mMoreView);// 设置SelectPicPopupWindow弹出窗体的宽this.setWidth(LayoutParams.MATCH_PARENT);// 设置SelectPicPopupWindow弹出窗体的高this.setHeight(LayoutParams.WRAP_CONTENT);// 设置SelectPicPopupWindow弹出窗体可点击this.setFocusable(true);// 设置SelectPicPopupWindow弹出窗体动画效果this.setAnimationStyle(R.style.popwin_anim_style);// 实例化一个ColorDrawable颜色为透明ColorDrawable dw = new ColorDrawable(0x55000000);// 设置SelectPicPopupWindow弹出窗体的背景this.setBackgroundDrawable(dw);}private void initStrings() {mBeautyTypes = mContext.getResources().getStringArray(R.array.beauty_array);mList = new ArrayList<String>();for (int i = 0; i < 20; i++) {mList.add("item" + i);}}public interface OnMorePopWindowItemClickListener {public void onItemClick(int position, String item);}private OnMorePopWindowItemClickListener mOnMorePopWindowItemClickListener;public void setOnMorePopWindowItemClickListener(OnMorePopWindowItemClickListener onMorePopWindowItemClickListener) {mOnMorePopWindowItemClickListener = onMorePopWindowItemClickListener;}
}

MyGridViewAdapter这个是核心,基本上所有的操作都和他有关

public class MyGridViewAdapter extends BaseAdapter {/** 图片视图类型 */public static final int VIEW_TYPE_ITEM = 0;/** 底部图片类型 */public static final int VIEW_TYPE_FOOT = 1;/** 视图数量 */public static final int VIEW_TYPE_COUNT = 2;private List<Image> mListImages;private Context mContext;private LayoutInflater mInflater;private FooterView mFooterView;public MyGridViewAdapter(Context context, List<Image> images) {this.mContext = context;this.mListImages = images;mInflater = LayoutInflater.from(mContext);}@Overridepublic int getCount() {// 注意此处因为加了底部视图所以加1return mListImages.size() + 1;}@Overridepublic Image getItem(int position) {return mListImages.get(position);}@Overridepublic long getItemId(int position) {return position;}/*** 复写该方法使GridView正确缓存不同视图*/@Overridepublic int getViewTypeCount() {return VIEW_TYPE_COUNT;}/*** 复写该方法使GridView正确缓存不同视图*/@Overridepublic int getItemViewType(int position) {if (position == getCount() - 1) {return VIEW_TYPE_FOOT;}return VIEW_TYPE_ITEM;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {if (convertView == null) {convertView = initConvertView(position, convertView, parent);}setDataToConvertView(position, convertView);return convertView;}/*** 给convertView设置数据* * @param position* @param convertView*/private void setDataToConvertView(int position, View convertView) {if (getItemViewType(position) == VIEW_TYPE_ITEM) {ViewHolder holder = (ViewHolder) convertView.getTag();Log.d("MyGrid", "position:" + position);holder.mImageView.setTag(R.id.imageView, getItem(position).getUrl());ImageLoaderUtil.displayImage(getItem(position).getUrl(), holder.mImageView);} else if (getItemViewType(position) == VIEW_TYPE_FOOT && position != 0) {setFooterViewStatus(FooterView.MORE);}}/*** 初始化convertView* * @param position* @param convertView* @param parent* @return*/private View initConvertView(final int position, View convertView,ViewGroup parent) {ViewHolder holder = null;if (getItemViewType(position) == VIEW_TYPE_FOOT) {// 初始化底部加载更多视图mFooterView = new FooterView(mContext);convertView = mFooterView;mFooterView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (mFooterView.getStatus() == FooterView.MORE&& mLoadListener != null) {mLoadListener.onLoad();}}});GridView.LayoutParams pl = new GridView.LayoutParams(MeasureUtil.getScreenSize(mContext)[0],LayoutParams.WRAP_CONTENT);mFooterView.setLayoutParams(pl);setFooterViewStatus(FooterView.HIDE);} else {// 初始化图片视图convertView = mInflater.inflate(R.layout.view_gallery_item, parent,false);holder = new ViewHolder();holder.mImageView = (ImageView) convertView.findViewById(R.id.imageView);holder.mImageView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(final View v) {new Handler().postDelayed(new Runnable() {@Overridepublic void run() {Intent intent = new Intent(mContext,BeautyPagerActivity.class);intent.putExtra(BeautyPagerActivity.POSITION,(Integer) v.getTag(R.id.gridView));mContext.startActivity(intent);}}, 200);}});convertView.setTag(holder);}return convertView;}class ViewHolder {ImageView mImageView;}/*** 加载更多回调接口*/public interface LoadListener {void onLoad();}private LoadListener mLoadListener;public void setLoadListener(LoadListener loadListener) {mLoadListener = loadListener;}public void setFooterViewStatus(int status) {if (mFooterView != null) {mFooterView.setStatus(status);}}}

上一篇博客中我讲到了Adapter中多布局缓存的问题,这次这里也用到了详细请移至Android学习之当ScrollView遭遇ListView(GridView)

好吧接下来我们梳理一遍流程

1.进入主界面也就是当FragmentMain初始化时调用loadItems()方法加载第一页数据并通过volley下载解析放到mListImages中;其实这个过程是通过PtrFrameLayout.autoRefresh()在回调接口中onRefreshBegin()实现刷新过程;

2.刷新MyGridViewAdapter显示图片,通过universal-image-loader的displayImage方法直接将url和imageview传入即可显示图片;也算是相当的简单了;(ps:可是坑才刚刚开始)

3.我们可以点击popwindow中的美女类型类切换图片,因为popwindow在activity中,要改变fragment的值;fragment只能向外公布接口了changeOtherBeautyType方法用来改变图片类型并在此方法中做刷新操作

运行项目检验成果

               

OMG的图片滑动明显混乱不堪,popwindow说好的从Toolbar下方滑动显示呢?这都是什么呢?

遭受打击之后,博主孕育出了第二篇Android学习之优化美女图片浏览器,让我们一同来优化吧;相信这个过程是痛并快乐着的,哈哈...欲知详情且听下回分解

Android学习之打造美女图片浏览器相关推荐

  1. Android学习之优化美女图片浏览器

    接上一篇文章:Android学习之打造美女图片浏览器 上一篇博文其实我给大家留了好多坑,那么这篇文章我就一一把坑都埋了,好吧:)有一种自己挖坑自己埋的感觉,不过埋的过程我们也是可以学到不少的:而且我比 ...

  2. Android学习笔记26:图片切换控件ImageSwitcher的使用

    在Windows操作系统中,要查看多张图片,可以通过使用"Windows照片查看器"在"上一张"和"下一张"之间切换,进行多张图片的浏览. ...

  3. Android学习笔记之在图片特效

    1.涂鸦(能清屏) HandWritingActivity.java [java] view plaincopy package xiaosi.handWriting; import android. ...

  4. Android小程序(3)--简单图片浏览器

    简单图片浏览器 此使用的知识点是XML布局文件与Java代码的混合来控制UI界面. 首先在布局文件中定义简单的线性布局容器: <?xml version="1.0" enco ...

  5. Android学习笔记进阶十一图片动画播放(AnimationDrawable)

    大家平时见到的最多的可能就是Frame动画了,Android中当然也少不了它.它的使用更加简单,只需要创建一个 AnimationDrawabledF对象来表示Frame动画,然后通过addFrame ...

  6. Android学习笔记19-ImageView实现图片适屏与裁剪

    在Android中,要将一张图片显示在屏幕上,需要创建一个显示图片的对象,该对象就是ImageView. 1.ImageView常用属性 要对图片进行适屏裁剪操作,首先需要了解ImageView的常用 ...

  7. android教你打造独一无二的图片加载框架

    前言 首先,最近是在忙okhttp没错.不过或许有人问为什么忙着okhttp怎么又扯到了图片加载上了.其实,最近想实现下断点续传以及多文件下载,但并不知道怎么搞.群里有小伙伴提出了控制线程池来实现.然 ...

  8. android学习之路(六)---- 图片加载库的优化、封装

    封装Image-Loader 一.背景         universal-image-loader是一项伟大的开源项目,作者在其中运用到的软件工程解决办法让人印象深刻,在本篇文章的开篇,首先向uni ...

  9. Android学习之RecyclerView带刺的玫瑰

    上述小诗先逗比一下,接下来切入正题: 自从RecyclerView的诞生起,人们就为她贴上了高贵的标签:她灵活华丽高度可定制,而另一边ListView确已是明日黄花:人们趋之若鹜的奔向了Recycle ...

最新文章

  1. 网络推广外包专员浅析网络推广外包优化当中的那些细枝末节!
  2. win11怎么改任务栏大小
  3. JavaScript使用技巧精萃 经典代码收藏版
  4. LinkedIn联合创始人:硅谷也就700万人,为什么能创建这么多瞩目的公司 ?
  5. iOS音频播放 (二):AudioSession 转
  6. 教程 | 一个基于TensorFlow的简单故事生成案例:带你了解LSTM
  7. 系统辨识工具箱使用指南
  8. 推荐一款在线文件对比工具
  9. mac如何彻底删除/卸载程序
  10. Nodejs版本更新
  11. 技术晨读_2014_9_1
  12. 教你怎样选配电脑硬件
  13. 计算机主机内部同步传输,北航网教计算机网络与应用习题-考查课
  14. 对重装系统彻底说再见——电脑C盘备份
  15. 【转】本人常用资源整理(ing...)
  16. 英语学习笔记——语法篇(持续更新)
  17. 【6G】通信感知一体化(SSaC:Symbiotic Sensing and Communications)概述
  18. 声明一个Tree(树)类,有成员ages(树龄),成员函数grow(int years)用以对ages 加上years,showage( )用以显示tree对象的ages值。在主函数中定义Tree类对
  19. lm358集成电路参数资料 原厂资料 pdf datasheet 免费下载
  20. python 利用百度推广API接口,每日调整关键词价格,关键词点击率大于10%的进行降低价格和点击率小于4%进行增加价格

热门文章

  1. 今天许多的家庭有计算机翻译成英语,新视野英语教程课后翻译答案(高职高专版)...
  2. [1980]不存在的泳池
  3. 神是什么?神即道 道法自然 如来
  4. chatgpt赋能python:Python迭代器介绍:什么是迭代器?
  5. (一).NET的历史介绍
  6. 软件架构-Spring boot快速开始及核心功能介绍(中)
  7. 中级职称的评审流程,我不允许你还不知道!
  8. 连平新视界-连平最全客车发车时刻表!收好喽
  9. 测试老鸟告诉你测试员常用的软件
  10. 知识融合开源工具Falcon-Ao和LIMES