如何正确理解和使用Activity的4种启动模式

 更新时间:2017年7月6日 23:19  点击:1747
本文介绍了如何正确理解和使用Activity的4种启动模式的教程,非常实用,有兴趣的同学快来看看吧

关于Activity启动模式的文章已经很多,但有的文章写得过于简单,有的则过于注重细节,本文想取一个折中,只关注最重要和最常用的概念,原理和使用方法,便于读者正确应用。

Activity的启动模式有4种,分别是standard.singleTop. SingleTask.  singleInstance,可以在AndroidMainifest.xml文件中指定每一个Activity的启动模式。一个Android应用一般都会有多个Activity,系统会通过任务栈来管理这些Activity,栈是一种后进先出的集合,当前的Activity就在栈顶,按返回键,栈顶Activity就会退出。Activity启动模式不同,系统通过任务栈管理Activity的方式也会不同,以下将分别介绍。

1 Standard模式

Standard模式是Android的默认启动模式,你不在配置文件中做任何设置,那么这个Activity就是standard模式,这种模式下,Activity可以有多个实例,每次启动Activity,无论任务栈中是否已经有这个Activity的实例,系统都会创建一个新的Activity实例,以下是实验验证。

新建一个FirstActivity,用一个Button去启动它本身:

发现每次都会启动一个新的FristActivity, Log信息如下

什么时候用standard模式呢?standartd模式是activity的默认模式,大部分情况下,都应该使用这种模式,也就是在配置文件中什么都不用做,当确实有特殊需求时,再考虑其他模式。

2 SingleTop模式

SingleTop模式和standard模式非常相似,主要区别就是当一个singleTop模式的Activity已经位于任务栈的栈顶,再去启动它时,不会再创建新的实例,如果不位于栈顶,就会创建新的实例,现在把配置文件中FirstActivity的启动模式改为SingleTop,我们的应用只有一个Activity,FirstActivity自然处于任务栈的栈顶。

当应用第一次启动后,我们再按Button去启动新的FirstActivity,发现Log信息中不再打印onCreate函数,说明不再创建新的FirstActivity实例。

这里有一个新的问题,对于每次启动Activity,我们该如何分别处理。答案就是onNewIntent()函数,虽然系统不会调用onCreat(),但会调用onNewIntent,我们可以在这个函数做相应的处理。

当一个Activity已经在栈顶,但依然有可能启动它,而你又不想产生新的Activity实例,此时就可以用singleTop模式。例如,一个搜索Activity,可以输入搜索内容,也可以产生搜索结果,此时就可以用singleTop模式,不会用户每次搜索都会产生一个实例。

3 SingleTask模式

SingleTask模式的Activity在同一个Task内只有一个实例,如果Activity已经位于栈顶,系统不会创建新的Activity实例,和singleTop模式一样。但Activity已经存在但不位于栈顶时,系统就会把该Activity移到栈顶,并把它上面的activity出栈。修改上面的程序,新建一个SecondActivity,将FirstActivity设置为singleTask启动模式,并让它启动SecondActivity,再让SecondActivity来启动FirstActivity。

Log信息如下

当SecondActivity启动FirstActivity时,并不会调用FirstActivity的onCreate函数,但会调用onNewIntent函数,同时会调用SecondActivity的onDestroy函数,SecondActivity实例被销毁。

singleTask模式和前面两种模式的最大区别就是singleTask模式是任务内单例的,所以我们是否设定Activity为singleTask模式,就是看我们activity是否需要单例,例如你的某个Activity

里面有一个列表,如果有多个实例,有可能导致用户看到的列表不一致,有的Activity需要经常启动,如果每次都创建实例,会导致占用资源过多,这些情况都可以使用singleTask模式,但启动singleTask模式的Activity会导致任务栈内它上面的Activity被销毁,有可能会影响用户体验,使用时要注意。

4 SingleInstance模式

singleInstance模式也是单例的,但和singleTask不同,singleTask只是任务栈内单例,系统里是可以有多个singleTask  Activity实例的,而singleInstance  Activity在整个系统里只有一个实例,启动一singleInstanceActivity时,系统会创建一个新的任务栈,并且这个任务栈只有他一个Activity。

SingleInstance模式并不常用,如果我们把一个Activity设置为singleInstance模式,你会发现它启动时会慢一些,切换效果不好,影响用户体验。它往往用于多个应用之间,例如一个电视launcher里的Activity,通过遥控器某个键在任何情况可以启动,这个Activity就可以设置为singleInstance模式,当在某应用中按键启动这个Activity,处理完后按返回键,就会回到之前启动它的应用,不影响用户体验。

以上分析了Activity的4种启动模式,将Activity设置为哪种启动模式并没有标准答案,有时候,你可能发现将某个Activity设置为一种启动模式或者另一种启动模式,并没有明显区别,而具体的评判标准就是看哪种模式更满足应用功能,更有利于用户体验。

本文介绍了Android自定义View仿IOS圆盘时间选择器,非常实用,有兴趣的同学可以看看

通过自定义view实现仿iOS实现滑动两端的点选择时间的效果

效果图

这里写图片描述

这里写图片描述

自定义的view代码

 

 代码如下复制代码

publicclassRing_Slide2extendsView {

 privatestaticfinaldoubleRADIAN =180/ Math.PI;

 privateintmax_progress;// 设置最大进度

 privateintcur_progress;//设置锚点1当前进度

 privateintcur_progress2;//设置锚点2进度

 privateintbottom_color;//设置底色

 privateintcircle_color;//设置圆的颜色(锚点)

 privateintslide_color;//设置滑动过的颜色

 privatefloatring_width;//圆环的宽度

 privatedoublecur_Angle;//当前锚点1旋转角度

 privatedoublecur_Angle2;//当前锚点2的旋转角度

 privatefloatring_Radius;//圆环的半径

 privatefinalint[] arrColorCircle =newint[]{0xFFFFde37,0xFFFFa400};

 privateintmain_width;//圆的宽度

 privatefloatmWheelCurX, mWheelCurY;//圆的位置

 privatefloatmWheelCurX2, mWheelCurY2;//圆2的位置

 privatePaint circle_Paint;//圆环的画笔

 privatePaint select_Paint;//选中的画笔

 privatePaint dot1;//圆点1

 privatePaint dot2;//圆点2

 privateContext context;

 privateOnSeekBarChangeListener changeListener,changeListener2;

 publicRing_Slide2(Context context) {

  this(context,null);

 }

 publicRing_Slide2(Context context, AttributeSet attrs) {

  this(context, attrs,0);

 }

 publicRing_Slide2(Context context, AttributeSet attrs,intdefStyleAttr) {

  super(context, attrs, defStyleAttr);

  this.context=context;

  initAttrs(attrs,defStyleAttr);

  initPadding();

  //初始化画笔

  initPaints();

 }

 //初始化属性

 privatevoidinitAttrs(AttributeSet attrs,intdefStyle){

  TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.Cricle_slide, defStyle,0);

  max_progress=typedArray.getInt(R.styleable.Cricle_slide_max_progress,720);

  cur_progress=typedArray.getInt(R.styleable.Cricle_slide_cur_progress,420);

  cur_progress2=typedArray.getInt(R.styleable.Cricle_slide_cur_progress2,540);

  if(cur_progress > max_progress) cur_progress = max_progress;

  if(cur_progress2 > max_progress) cur_progress2 = max_progress;

  Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.select_sun_bg2);

  main_width= bitmap.getWidth();

  ring_width=typedArray.getFloat(R.styleable.Cricle_slide_Ring_Width,main_width);

  bottom_color=typedArray.getColor(R.styleable.Cricle_slide_bottom_color,getColor(R.color.select_main_bg_color));

  circle_color=typedArray.getColor(R.styleable.Cricle_slide_circle_color,getColor(R.color.duration));

  slide_color=typedArray.getColor(R.styleable.Cricle_slide_slide_color,getColor(R.color.time));

  typedArray.recycle();

 }

 //初始化边距

 privatevoidinitPadding(){

  intpaddingLeft = getPaddingLeft();

  intpaddingTop = getPaddingTop();

  intpaddingRight = getPaddingRight();

  intpaddingBottom = getPaddingBottom();

  intpaddingStart =0, paddingEnd =0;

  if(Build.VERSION.SDK_INT >=17) {

   paddingStart = getPaddingStart();

   paddingEnd = getPaddingEnd();

  }

  intmaxPadding = Math.max(paddingLeft, Math.max(paddingTop,

    Math.max(paddingRight, Math.max(paddingBottom, Math.max(paddingStart, paddingEnd)))));

  setPadding(maxPadding, maxPadding, maxPadding, maxPadding);

 }

 privatevoidinitPaints(){

  /*

  圆环的画笔

   */

  circle_Paint=new Paint(Paint.ANTI_ALIAS_FLAG);

  circle_Paint.setAntiAlias(true);

  circle_Paint.setColor(bottom_color);

  circle_Paint.setStyle(Paint.Style.STROKE);

  circle_Paint.setStrokeWidth(ring_width);

  /*

  选中区域的画笔

   */

  select_Paint=new Paint(Paint.ANTI_ALIAS_FLAG);

  select_Paint.setShader(new SweepGradient(0, 0, arrColorCircle, null));

  /*select_Paint.setColor(circle_color);*/

  select_Paint.setAntiAlias(true);

  select_Paint.setStyle(Paint.Style.STROKE);

  select_Paint.setStrokeWidth(ring_width);

  // 画锚点

  dot1 = new Paint(Paint.ANTI_ALIAS_FLAG);

  dot1.setColor(circle_color);

  dot1.setAntiAlias(true);

  dot1.setStyle(Paint.Style.FILL);

  // 画锚点2

  dot2 = new Paint(Paint.ANTI_ALIAS_FLAG);

  dot2.setColor(slide_color);

  dot2.setAntiAlias(true);

  dot2.setStyle(Paint.Style.FILL);

 }

 //获取宽度

 private float getDimen(int dimenId) {

  return getResources().getDimension(dimenId);

 }

 //获取颜色

 @TargetApi(Build.VERSION_CODES.M)

 private int getColor(int colorId) {

  final int version = Build.VERSION.SDK_INT;

  if (version >= 23) {

   return getContext().getColor(colorId);

  } else {

   return ContextCompat.getColor(getContext(), colorId);

  }

 }

 @Override

 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

  super.onMeasure(widthMeasureSpec, heightMeasureSpec);

  Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.setalarm_colock_bg);

  int height = bitmap.getHeight()+main_width*2;

  int width = bitmap.getWidth()+main_width*2;

  int min = Math.min(height, width);

  setMeasuredDimension(min,min);

  initposition();

 }

 private void initposition(){

  //转换为360度

  cur_Angle=(double) cur_progress / max_progress*360.0;

  cur_Angle2=(double)cur_progress2 / max_progress*360.0;

  //计算初始化旋转的角度

  double cos = -Math.cos(Math.toRadians(cur_Angle));

  double cos2 = -Math.cos(Math.toRadians(cur_Angle2));

  //根据旋转的角度来确定位置

  MakeCurPosition(cos);

  MakeCurPosition2(cos2);

  //确定圆环的半径

  ring_Radius=(getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - ring_width) / 2;

 }

 private void MakeCurPosition(double cos){

  //根据旋转的角度来确定圆的位置

  //确定x点的坐标

  mWheelCurX = calcXLocationInWheel(cur_Angle, cos);

  //确定y点的坐标

  mWheelCurY=calcYLocationInWheel(cos);

 }

 private void MakeCurPosition2(double cos2){

  //根据旋转的角度来确定圆的位置

  //确定x点的坐标

  mWheelCurX2 = calcXLocationInWheel(cur_Angle2, cos2);

  //确定y点的坐标

  mWheelCurY2=calcYLocationInWheel(cos2);

 }

 //确定x点的坐标

 private float calcXLocationInWheel(double angle,double cos){

  if (angle < 180) {

   return (float) (getMeasuredWidth() / 2 + Math.sqrt(1 - cos * cos) * ring_Radius); //Math.sqrt正平分根 9-3

  } else {

   return (float) (getMeasuredWidth() / 2 - Math.sqrt(1 - cos * cos) * ring_Radius);

  }

 }

 //确定y点的坐标

 private float calcYLocationInWheel(double cos) {

  return getMeasuredWidth() / 2 + ring_Radius * (float) cos;

 }

 @Override

 protected void onDraw(Canvas canvas) {

  super.onDraw(canvas);

  float left = getPaddingLeft() + ring_width / 2;

  float top = getPaddingTop() + ring_width / 2;

  float right = canvas.getWidth() - getPaddingRight() - ring_width / 2;

  float bottom = canvas.getHeight() - getPaddingBottom() - ring_width / 2;

  float centerX = (left + right) / 2;

  float centerY = (top + bottom) / 2;

  float wheelRadius = (canvas.getWidth() - getPaddingLeft() - getPaddingRight()) / 2 - ring_width / 2;

  canvas.drawCircle(centerX, centerY, wheelRadius, circle_Paint);

  //画选中区域

  //  canvas.drawArc(new RectF(left, top, right, bottom), (float) (Math.PI *  RADIAN + Math.acos(cur_Angle) * RADIAN), (float)  (Math.abs(cur_Angle-cur_Angle2)), false, select_Paint);

  Log.i("TAG","第一个的角度="+cur_Angle);

  Log.i("TAG","第一个的角度2="+cur_Angle2);

  float begin=0; //圆弧的起点位置

  float stop=0;

  if(cur_Angle>180 && cur_Angle>cur_Angle2 ){ //180 -- 360

   begin=(float) (-Math.abs(cur_Angle-360)-90);

   stop=(float) Math.abs(Math.abs(cur_Angle-360)+cur_Angle2);

   Log.i("TAG","begin="+begin);

   Log.i("TAG","stop="+stop);

  }else if(cur_Angle>cur_Angle2){

   begin=(float) cur_Angle-90;

   stop=(float)(360-(cur_Angle-cur_Angle2));

  }else {

    begin=(float) cur_Angle-90;

   stop=(float) Math.abs(cur_Angle-cur_Angle2);

  }

  canvas.drawArc(new RectF(left, top, right, bottom), begin,stop, false, select_Paint);

  //画锚点 画圆

  canvas.drawCircle(mWheelCurX, mWheelCurY, ring_width/2, dot1);

  //画锚点 画圆

  canvas.drawCircle(mWheelCurX2, mWheelCurY2, ring_width/2, dot2);

  Log.i("TAG","锚点1Y"+mWheelCurY+"锚点1X"+mWheelCurX);

  Log.i("TAG","锚点2Y"+mWheelCurY2+"锚点1X"+mWheelCurX2);

 }

 @Override

 public boolean onTouchEvent(MotionEvent event) {

  float x = event.getX();

  float y = event.getY();

  int flag=0;

  //判断是否触控到两个点中的其中某个点

  if(isMovedot2(x,y)){

   flag=2;

  }else if(isMovedot1(x,y)){

   flag=1;

  }

  /* if(isMovedot1(x,y)){

   flag=1;

  }else if(isMovedot2(x,y)){

   flag=2;

  }*/

  if(event.getAction()==MotionEvent.ACTION_MOVE || isMovedot1(x,y) ==true|| isMovedot2(x,y)==true){

   Log.i("TAG","进入X="+x+"进入Y="+y);

   //通过触摸点算出cos角度值

   floatcos = calculateCos(x, y);

   // 通过反三角函数获得角度值

   doubleangle;//获取滑动的角度

   if(x < getWidth() /2) {// 滑动超过180度

    angle = Math.PI * RADIAN + Math.acos(cos) * RADIAN;//通过计算得到滑动的角度值

   }else{// 没有超过180度

    angle = Math.PI * RADIAN - Math.acos(cos) * RADIAN;//PI 周长比直径 返回弧角度的余弦值

   }

   if(flag==1){

    cur_Angle=angle;

    cur_progress=getSelectedValue(cur_Angle);

    MakeCurPosition(cos);

    if(changeListener !=null) {

     changeListener.onChanged(this, cur_progress);

    }

   }elseif(flag==2){

    cur_Angle2=angle;

    cur_progress2=getSelectedValue(cur_Angle2);

    MakeCurPosition2(cos);

    if(changeListener2 !=null) {

     changeListener2.onChanged(this, cur_progress2);

    }

   }

   invalidate();

   returntrue;

  }else{

   returnsuper.onTouchEvent(event);

  }

 }

 privatebooleanisMovedot1(floatx,floaty){

  floatdot1x = Math.abs(mWheelCurX - x);

  floatdot1y = Math.abs(mWheelCurY - y);

  if(dot1x<30&& dot1y<30){

   returntrue;

  }else{

   returnfalse;

  }

 }

 privatebooleanisMovedot2(floatx,floaty){

  floatdot1x = Math.abs(mWheelCurX2 - x);

  floatdot1y = Math.abs(mWheelCurY2 - y);

  if(dot1x<30&& dot1y<30){

   returntrue;

  }else{

   returnfalse;

  }

 }

 //拿到切斜角的cos值

 privatefloatcalculateCos(floatx,floaty){

  floatwidth = x - getWidth() /2;

  floatheight = y - getHeight() /2;

  floatslope = (float) Math.sqrt(width * width + height * height);

  returnheight / slope;

 }

 privateintgetSelectedValue(doublemCurAngle) {//角度转进度

  returnMath.round(max_progress * ((float) mCurAngle /360));//四舍五入

 }

 publicvoidsetOnSeekBarChangeListener(OnSeekBarChangeListener listener) {

  changeListener = listener;

 }

 publicvoidsetOnSeekBarChangeListener2(OnSeekBarChangeListener listener) {

  changeListener2 = listener;

 }

 publicvoidinitRadian(intpro1,intpro2){

  this.cur_progress=pro1;

  this.cur_progress2=pro2;

  invalidate();

 }

 publicinterfaceOnSeekBarChangeListener {

  voidonChanged(Ring_Slide2 seekbar,intcurValue);

 }

}

 

自定义stayle样式,在values下新建sttrs.xml文件

 

 代码如下复制代码

 //设置最大进度

 

 //设置当前进度

 

 //设置当前进度

 

 //设置底色

 

 //设置圆的颜色

 

 //设置滑动的颜色

 

 //圆环的宽度 (dimension是代表尺寸值)

 


 

这篇文章主要介绍了Android编程之ActionBar Tabs用法,结合实例形式分析了ActionBar Tabs的功能及Tab切换不同的Fragment的相关实现技巧,需要的朋友可以参考下

这里主要实现用Tab切换不同的Fragment,点击View显示or隐藏ActionBar,把ActionBar 设为透明,使界面更加友好,详细代码见资源里的ActionBarTabs。

ActionBar Tab主要用于Fragment之间的切换,其必须要设置ActionBar.TabListener,详细代码如下

ActionBarActivity.Java:

 

 代码如下复制代码

importandroid.app.ActionBar;

importandroid.app.Activity;

importandroid.app.FragmentTransaction;

importandroid.app.ActionBar.Tab;

importandroid.os.Bundle;

importandroid.os.CountDownTimer;

importandroid.view.MotionEvent;

importandroid.view.Window;

publicclassActionBarActivityextendsActivity {

  /** Called when the activity is first created. */

  @Override

  publicvoidonCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    //使ActionBar变得透明

    requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);

    setContentView(R.layout.main);

    finalActionBar actionBar = getActionBar();

    actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

    // remove the activity title to make space for tabs

    actionBar.setDisplayShowTitleEnabled(false);

    AFragment aFragment =newAFragment();

    actionBar.addTab(actionBar.newTab().setText("Tab-A")

        .setTabListener(newListenerA(aFragment)));

    BFragment bFragment =newBFragment();

    actionBar.addTab(actionBar.newTab().setText("Tab-B")

        .setTabListener(newListenerB(bFragment)));

  }

  //点击显示or隐藏ActionBar

  publicbooleanonTouchEvent(MotionEvent event){

    ActionBar bar = getActionBar();

    switch(event.getAction()){

      caseMotionEvent.ACTION_UP:

        if(bar.isShowing()) bar.hide();

        elsebar.show();

        break;

      default:

          break;

    }

    returntrue;

  }

  privateclassListenerAimplementsActionBar.TabListener {

    privateAFragment mFragment;

    // Called to create an instance of the listener when adding a new tab

    publicListenerA(AFragment fragment) {

      mFragment = fragment;

    }

    publicvoidonTabSelected(Tab tab, FragmentTransaction ft) {

      ft.add(R.id.fragment, mFragment,null);

    }

    publicvoidonTabUnselected(Tab tab, FragmentTransaction ft) {

      ft.remove(mFragment);

    }

    publicvoidonTabReselected(Tab tab, FragmentTransaction ft) {

      // do nothing }

    }

  }

  privateclassListenerBimplementsActionBar.TabListener {

    privateBFragment mFragment;

    // Called to create an instance of the listener when adding a new tab

    publicListenerB(BFragment fragment) {

      mFragment = fragment;

    }

    publicvoidonTabSelected(Tab tab, FragmentTransaction ft) {

      ft.add(R.id.fragment, mFragment,null);

    }

    publicvoidonTabUnselected(Tab tab, FragmentTransaction ft) {

      ft.remove(mFragment);

    }

    publicvoidonTabReselected(Tab tab, FragmentTransaction ft) {

      // do nothing }

    }

  }

}

 

其中涉及到两个Fragment,在前面Fragment的笔记中讲过,这里就不再赘述。类AFragment实现如下,BFragment实现与这类似:

 

 代码如下复制代码

publicclassAFragmentextendsFragment {

  publicView onCreateView(LayoutInflater inflater, ViewGroup container,

      Bundle savedInstanceState) {

    returninflater.inflate(R.layout.alayout, container,false);

    }

}

 

小编给大家推荐的这篇文章介绍了 Android编程之交互对话框实例浅析,非常实用,有兴趣的同学快来看看吧!

1. 在Android SDK中,虽然有许多的窗口,有些类似Modeless的窗口、有些类似于前端Force Focus的窗口,但真正具有交互功能的则为AlertDialog对话窗口。

 

 代码如下复制代码

newAlertDialog.Builder(EX03_12.this)

.setTitle(R.string.app_about)

.setMessage(R.string.app_about_msg)

.setPositiveButton(R.string.str_ok,

  newDialogInterface.OnClickListener()

  {

  publicvoidonClick(DialogInterface dialoginterface,inti)

  {

  }

  }).show();

 

这里仅是有一个确定按钮,还可以添加其他的按钮和图标,可以参照Android文档。

2.提到AlertDialog,自然就会想到Toast。Toast就是一个简短的小信息,可以提示音量大小的调整等。对程序员来说,它也是一个非常好用的Debug工具。

 

 代码如下复制代码

/*使用系统标准的 makeText()方式来产生Toast讯息*/

Toast.makeText( EX04_03.this,String,Toast.LENGTH_LONG).show();

 

第三个参数可以是LENGTH_LONG或LENGTH_SHORT,前者表示时间长,后者较短。当然,也可以使用重写的Toast对象的方法,自己定义Toast显示的Layout。

[!--infotagslink--]

相关文章

  • Tomcat配置及如何在Eclipse中启动

    这篇文章主要介绍了Tomcat配置及如何在Eclipse中启动,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-04
  • 图解PHP使用Zend Guard 6.0加密方法教程

    有时为了网站安全和版权问题,会对自己写的php源码进行加密,在php加密技术上最常用的是zend公司的zend guard 加密软件,现在我们来图文讲解一下。 下面就简单说说如何...2016-11-25
  • ps怎么使用HSL面板

    ps软件是现在很多人都会使用到的,HSL面板在ps软件中又有着非常独特的作用。这次文章就给大家介绍下ps怎么使用HSL面板,还不知道使用方法的下面一起来看看。 &#8195;...2017-07-06
  • 学习JavaScript设计模式之装饰者模式

    这篇文章主要为大家介绍了JavaScript设计模式中的装饰者模式,对JavaScript设计模式感兴趣的小伙伴们可以参考一下...2016-01-21
  • Plesk控制面板新手使用手册总结

    许多的朋友对于Plesk控制面板应用不是非常的了解特别是英文版的Plesk控制面板,在这里小编整理了一些关于Plesk控制面板常用的使用方案整理,具体如下。 本文基于Linu...2016-10-10
  • javascript设计模式之解释器模式详解

    神马是“解释器模式”?先翻开《GOF》看看Definition:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。在开篇之前还是要科普几个概念: 抽象语法树: 解释器模式并未解释如...2014-06-07
  • Postgresql 如何选择正确的关闭模式

    这篇文章主要介绍了Postgresl 如何选择正确的关闭模式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-18
  • 使用insertAfter()方法在现有元素后添加一个新元素

    复制代码 代码如下: //在现有元素后添加一个新元素 function insertAfter(newElement, targetElement){ var parent = targetElement.parentNode; if (parent.lastChild == targetElement){ parent.appendChild(newEl...2014-05-31
  • jQuery 1.9使用$.support替代$.browser的使用方法

    jQuery 从 1.9 版开始,移除了 $.browser 和 $.browser.version , 取而代之的是 $.support 。 在更新的 2.0 版本中,将不再支持 IE 6/7/8。 以后,如果用户需要支持 IE 6/7/8,只能使用 jQuery 1.9。 如果要全面支持 IE,并混合...2014-05-31
  • 使用percona-toolkit操作MySQL的实用命令小结

    1.pt-archiver 功能介绍: 将mysql数据库中表的记录归档到另外一个表或者文件 用法介绍: pt-archiver [OPTION...] --source DSN --where WHERE 这个工具只是归档旧的数据,不会对线上数据的OLTP查询造成太大影响,你可以将...2015-11-24
  • 使用GruntJS构建Web程序之构建篇

    大概有如下步骤 新建项目Bejs 新建文件package.json 新建文件Gruntfile.js 命令行执行grunt任务 一、新建项目Bejs源码放在src下,该目录有两个js文件,selector.js和ajax.js。编译后代码放在dest,这个grunt会...2014-06-07
  • 如何使用php脚本给html中引用的js和css路径打上版本号

    在搜索引擎中搜索关键字.htaccess 缓存,你可以搜索到很多关于设置网站文件缓存的教程,通过设置可以将css、js等不太经常更新的文件缓存在浏览器端,这样访客每次访问你的网站的时候,浏览器就可以从浏览器的缓存中获取css、...2015-11-24
  • C#注释的一些使用方法浅谈

    C#注释的一些使用方法浅谈,需要的朋友可以参考一下...2020-06-25
  • MySQL日志分析软件mysqlsla的安装和使用教程

    一、下载 mysqlsla [root@localhost tmp]# wget http://hackmysql.com/scripts/mysqlsla-2.03.tar.gz--19:45:45-- http://hackmysql.com/scripts/mysqlsla-2.03.tar.gzResolving hackmysql.com... 64.13.232.157Conn...2015-11-24
  • php-fpm 启动报please specify user and group other than root, pool ‘default’

    本文章来给大家介绍关于php-fpm 启动报please specify user and group other than root, pool ‘default’的解决办法。 安装PHP ,配置fpm 成功后启动发现报错: St...2016-11-25
  • 安装和使用percona-toolkit来辅助操作MySQL的基本教程

    一、percona-toolkit简介 percona-toolkit是一组高级命令行工具的集合,用来执行各种通过手工执行非常复杂和麻烦的mysql和系统任务,这些任务包括: 检查master和slave数据的一致性 有效地对记录进行归档 查找重复的索...2015-11-24
  • IDEA 2021.2 激活教程及启动报错问题解决方法

    这篇文章主要介绍了IDEA 2021.2 启动报错及激活教程,文章开头给大家介绍了idea2021最新激活方法,关于idea2021启动报错的问题小编也给大家介绍的非常详细,需要的朋友可以参考下...2021-10-15
  • php语言中使用json的技巧及json的实现代码详解

    目前,JSON已经成为最流行的数据交换格式之一,各大网站的API几乎都支持它。我写过一篇《数据类型和JSON格式》,探讨它的设计思想。今天,我想总结一下PHP语言对它的支持,这是开发互联网应用程序(特别是编写API)必须了解的知识...2015-10-30
  • c#启动EXE文件的方法实例

    在程序执行中会遇到启动本软件的exe问,或者启用其它的exe文件,已达到执行某些操作的作用。下面是两种最常见的启动exe文件。...2020-06-25
  • 使用jquery修改表单的提交地址基本思路

    基本思路: 通过使用jquery选择器得到对应表单的jquery对象,然后使用attr方法修改对应的action 示例程序一: 默认情况下,该表单会提交到page_one.html 点击button之后,表单的提交地址就会修改为page_two.html 复制...2014-06-07