导入工程ActionBarCompat时,出现错误。从其他工程下拷贝project.propertiest文件过来,问题仍在。拷贝后需要重启Eclipse才解决。问题如下:

[2013-07-03 16:09:00 - ActionBarCompat] Project has no project.properties file! Edit the project properties to set one.

生词:compat 紧密的,紧凑的,简洁的;

 

Action Bar Compat 字面上就可以理解这个示例

 

工程包名:com.example.android.actionbarcompat

public abstract class ActionBarActivity extends Activity

 

在这个类中重写了以下方法

public MenuInflater getMenuInflater()

protected void onCreate(Bundle savedInstanceState)

protected void onPostCreate(Bundle savedInstanceState)

public boolean onCreateOptionsMenu(Menu menu)

protected void onTitleChanged(CharSequence title, int color)

 

创建了ActionBarHelper对象

final ActionBarHelper mActionBarHelper = ActionBarHelper.createInstance(this);

 

在ActionBarHelper类中,有一个工厂方法,针对不同的平台返回不同的实例

public static ActionBarHelper createInstance(Activity activity)

在createInstance(Activity)中,根据系统版本不同创建不同的ActionBarHelper实例

ICE_CREAM_SANDWICH 数值14,对应4.0。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
    return new ActionBarHelperICS(activity);

HONEYCOMB 数值11,对应3.0。
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    return new ActionBarHelperHoneycomb(activity);

11以下,3.0以下。
} else {
    return new ActionBarHelperBase(activity);
}

在ActionBarHelper类中定义了几个方法,都是空实现,需要在子类中具体实现。

public void onCreate(Bundle savedInstanceState)

public void onPostCreate(Bundle savedInstanceState)

public boolean onCreateOptionsMenu(Menu menu)

protected void onTitleChanged(CharSequence title, int color)

public MenuInflater getMenuInflater(MenuInflater superMenuInflater)

 

一个抽象方法,在所有非抽象子类中必须被实现。

public abstract void setRefreshActionItemState(boolean refreshing);

子类一:ActionBarHelperBase

 

在onCreate方法中

mActivity.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);

注:int android.view.Window.FEATURE_CUSTOM_TITLE = 7 [0x7]
Flag for custom title. You cannot combine this feature with other title features.

生词:

custom n. 习惯,风俗,惯例;adj. 定做的,定制的

feature n. 特征,特色,容貌,特写,故事片

注:boolean android.app.Activity.requestWindowFeature(int featureId)
Enable extended window features. This is a convenience for calling getWindow().requestFeature().

在onPostCreate方法中

mActivity.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.actionbar_compat);

注:void android.view.Window.setFeatureInt(int featureId, int value)
Set the integer value for a feature. The range of the value depends on the feature being set.

For FEATURE_PROGRESSS, it should go from 0 to 10000. At 10000 the progress is complete and the indicator hidden.

生词:

indicator n. 指示器,指示符,指示牌

 

res/values/ids.xml文件

<resources>
    <item type="id" name="actionbar_compat" />
    <item type="id" name="actionbar_compat_title" />
    <item type="id" name="actionbar_compat_item_refresh_progress" />
    <item type="id" name="actionbar_compat_item_refresh" />
    <item type="id" name="menu_refresh" />
</resources>

 

res/layout/actionbar_compact.xml文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@id/actionbar_compat"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" />

 

方法getActionBarCompact,返回在actionbar_compact.xml文件中定义的,id值为actionbar_compact的LinearLayout对象

private ViewGroup getActionBarCompat() {
    return (ViewGroup) mActivity.findViewById(R.id.actionbar_compat);
}

注:android.view.ViewGroup

A ViewGroup is a special view that can contain other views (called children.) The view group is the base class for layouts and views containers. This class also defines the android.view.ViewGroup.LayoutParams class which serves as the base class for layouts parameters.

要点:ViewGroup是一个特殊的View。ViewGroup是布局和视图容器的父类。在ViewGroup中,定义了LayoutParams。

API显示:ViewGroup继承了View,直接继承了ViewGroup的子类有:

AbsoluteLayout, AdapterView<T extends Adapter>, FragmentBreadCrumbs, FrameLayout, GridLayout, LinearLayout, PagerTitleStrip, RelativeLayout, SlidingDrawer, ViewPager

非直接继承了ViewGroup的子类有:

AbsListView, AbsSpinner, AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, CalendarView, DatePicker, DialerFilter, ExpandableListView, FragmentTabHost, Gallery, GestureOverlayView, GridView, HorizontalScrollView, ImageSwitcher, ListView, MediaController, NumberPicker, PagerTabStrip, RadioGroup, ScrollView, SearchView, Spinner, StackView, TabHost, TabWidget, TableLayout, TableRow, TextSwitcher, TimerPicker, TwoLineListItem, ViewAnimator, ViewFlipper, ViewSwitcher, WebView, ZoomControls.

 

方法getMenuInflater,返回一个WrappedMenuInflater实例。

public MenuInflater getMenuInflater(MenuInflater superMenuInflater) {
    return new WrappedMenuInflater(mActivity, superMenuInflater);
}

 

WrappedMenuInflater继承了MenuInflater。

注:android.view.MenuInflater
This class is used to instantiate menu XML files into Menu objects.

For performance reasons, menu inflation relies heavily on pre-processing of XML files that is done at build time. Therefore, it is not currently possible to use MenuInflater with an XmlPullParser over a plain XML file at runtime; it only works with an XmlPullParser returned from a compiled resource (R. something file.)

要点:MenuInflater 将 menu XML文件实例化为Menu对象。

生词:instantiate v. 举例说明,实例化

 

在WrappedMenuInflater中,包装了一个MenuInflater对象。

 

注:private void WrappedMenuInflater.loadActionBarMetadata(int menuResId)

Loads action bar metadata from a menu resource, storing a list of menu item IDs that should be shown on-screen (i.e. those with showAsAction set to always or ifRoom).

 

res/menu/main.xml文件

xmlns:android=http://schemas.android.com/apk/res/android

『xmlns』,XML NameSpace,

『android』表示“名称空间的名字”,

『http://schemas.android.com/apk/res/android』 表示“名称空间的值”,

『android:title』表示“title表示属性名。android表示名称空间。”

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_refresh"
        android:title="@string/menu_refresh"
        android:icon="@drawable/ic_action_refresh"
        android:orderInCategory="1"
        android:showAsAction="always" />
    <item android:id="@+id/menu_search"
        android:title="@string/menu_search"
        android:icon="@drawable/ic_action_search"
        android:orderInCategory="0"
        android:showAsAction="always" />

    <item android:id="@+id/menu_share"
        android:title="@string/menu_share"
        android:icon="@drawable/ic_menu_share"
        android:orderInCategory="1"
        android:showAsAction="never" />
</menu>

 

解析res/menu/main.xml文件方法

private void loadActionBarMetadata(int menuResId) {
    XmlResourceParser parser = null;
    try {

        将menuResId资源文件转成XmlResourceParser对象。
        parser = mActivity.getResources().getXml(menuResId);

        int eventType = parser.getEventType();
        int itemId;
        int showAsAction;

        判断解析工作是否已经到文件结尾了。

        boolean eof = false;
        while (!eof) {
            switch (eventType) {
                case XmlPullParser.START_TAG:

                    如果开始标签不是item的话,不做处理。
                    if (!parser.getName().equals("item")) {
                        break;
                    }

                    getAttributeResourceValue方法原型

                    int android.util.AttributeSet.getAttributeResourceValue(String namespace, String attribute, int defaultValue);

                    namespace,名称空间,MENU_RES_NAMESPACE,http://schemas.android.com/apk/res/android

                    attribute,MENU_ATTR_ID,字符串数组:id

                    itemId = parser.getAttributeResourceValue(MENU_RES_NAMESPACE,
                            MENU_ATTR_ID, 0);
                    if (itemId == 0) {
                        break;
                    }

                    showAsAction = parser.getAttributeIntValue(MENU_RES_NAMESPACE,
                            MENU_ATTR_SHOW_AS_ACTION, -1);

                    属性android:showAsAction可选值有{never, ifRoom, always, withText, collapseActionView}
                    if (showAsAction == MenuItem.SHOW_AS_ACTION_ALWAYS ||
                            showAsAction == MenuItem.SHOW_AS_ACTION_IF_ROOM) {
                        mActionItemIds.add(itemId);
                    }
                    break;

                case XmlPullParser.END_DOCUMENT:
                    eof = true;
                    break;
            }

            eventType = parser.next();
        }
    } catch (XmlPullParserException e) {
        throw new InflateException("Error inflating menu XML", e);
    } catch (IOException e) {
        throw new InflateException("Error inflating menu XML", e);
    } finally {
        if (parser != null) {
            parser.close();
        }
    }
}

 

注:void com.example.android.actionbarcompat.ActionBarActivity.onPostCreate(Bundle savedInstanceState)

Called when activity start-up is complete (after onStart and onRestoreInstanceState have been called).

Applications will generally not implement this method; it is intended for system classes to do final initialization after application code has run.

在 ActionBarHelperBase.onPostCreate(Bundle savedInstanceState) 方法中

public void onPostCreate(Bundle savedInstanceState) {
    mActivity.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
            R.layout.actionbar_compat);
    setupActionBar();

    SimpleMenu menu = new SimpleMenu(mActivity);
    mActivity.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu);
    mActivity.onPrepareOptionsMenu(menu);
    for (int i = 0; i < menu.size(); i++) {
        MenuItem item = menu.getItem(i);
        if (mActionItemIds.contains(item.getItemId())) {
            addActionItemCompatFromMenuItem(item);
        }
    }
}

 

res/values/actionbar_compat.xml文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@id/actionbar_compat"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" />

 

在 ActionBarHelperBase.setupActionBar() 方法中

private void setupActionBar() {
    final ViewGroup actionBarCompat = getActionBarCompat();
    if (actionBarCompat == null) {
        return;
    }

    LinearLayout.LayoutParams springLayoutParams = new LinearLayout.LayoutParams(
            0, ViewGroup.LayoutParams.FILL_PARENT);
    springLayoutParams.weight = 1;

    // Add Home button
    SimpleMenu tempMenu = new SimpleMenu(mActivity);
    SimpleMenuItem homeItem = new SimpleMenuItem(
            tempMenu, android.R.id.home, 0, mActivity.getString(R.string.app_name));
    homeItem.setIcon(R.drawable.ic_home);
    addActionItemCompatFromMenuItem(homeItem);

    // Add title text
    TextView titleText = new TextView(mActivity, null, R.attr.actionbarCompatTitleStyle);
    titleText.setLayoutParams(springLayoutParams);
    titleText.setText(mActivity.getTitle());
    actionBarCompat.addView(titleText);
}

TextView构造方法

android.widget.TextView.TextView(Context context, AttributeSet attrs, int defStyle)

LayoutParams构造方法

android.widget.LinearLayout.LayoutParams.LayoutParams(int width, int height)

 

添加HomeButton时,定义了SimpleMenu和SimpleMenuItem两个类。

SimpleMenu 实现了android.view.Menu接口。

SimpleMenuItem 实现了android.view.MenuItem接口。

 

在SimpleMenu中,方法addInternal 将SimpleMenuItem实例添加到ArrayList对象中。

private MenuItem addInternal(int itemId, int order, CharSequence title) {
    final SimpleMenuItem item = new SimpleMenuItem(this, itemId, order, title);
    mItems.add(findInsertIndex(mItems, order), item);
    return item;
}

在SimpleMenu中,方法findInsertIndex找出SimpleMenuItem将要插入到哪个位置中。

private static int findInsertIndex(ArrayList<? extends MenuItem> items, int order) {
    for (int i = items.size() - 1; i >= 0; i--) {
        MenuItem item = items.get(i);

        如果参数order的数值大于等于item的order数值,插入到item的后面。
        if (item.getOrder() <= order) {
            return i + 1;
        }
    }

    return 0;
}

在SimpleMenu中,方法 findItemIndex(int id) 找出itemId对应的在ArrayList的下标。

public int findItemIndex(int id) {
    final int size = size();

    for (int i = 0; i < size; i++) {
        SimpleMenuItem item = mItems.get(i);
        if (item.getItemId() == id) {
            return i;
        }
    }

    return -1;
}

在SimpleMenuItem中,定义了两个变量和图标有关系,

private Drawable mIconDrawable;
private int mIconResId = 0;

这两个变量有点相互排斥的,

当设置Drawable时,mIconDrawable被赋值,mIconResId被置0.

当设置int类型的mIconResId时,mIconResId被赋值,mIconDrawable被赋null。

当获取Drawable时,如果mIconDrawable不为空时,直接返回,否则将mIconResId转换为Drawable对象返回。

public MenuItem setIcon(Drawable icon) {
    mIconResId = 0;
    mIconDrawable = icon;
    return this;
}

public MenuItem setIcon(int iconResId) {
    mIconDrawable = null;
    mIconResId = iconResId;
    return this;
}

public Drawable getIcon() {
    if (mIconDrawable != null) {
        return mIconDrawable;
    }

    if (mIconResId != 0) {
        return mMenu.getResources().getDrawable(mIconResId);
    }

    return null;
}

 

在 ActionBarHelperBase.addActionItemCompatFromMenuItem(final menuItem item) 方法中

创建 ImageButton 对象

ImageButton actionButton = new ImageButton(mActivity, null,
                itemId == android.R.id.home
                        ? R.attr.actionbarCompatItemHomeStyle
                        : R.attr.actionbarCompatItemStyle);

ImageButton 构造方法原型

android.widget.ImageButton.ImageButton(Context context, AttributeSet attrs, int defStyle)

设置 ImageButton 的宽和高

    actionButton.setLayoutParams(new ViewGroup.LayoutParams(
            (int) mActivity.getResources().getDimension(
                    itemId == android.R.id.home
                            ? R.dimen.actionbar_compat_button_home_width
                            : R.dimen.actionbar_compat_button_width),
            ViewGroup.LayoutParams.FILL_PARENT));

设置 ImageButton 的 id

actionButton.setId(R.id.actionbar_compat_item_refresh);

创建ProgressBar对象

ProgressBar indicator = new ProgressBar(mActivity, null,
                R.attr.actionbarCompatProgressIndicatorStyle);

从dimens.xml文件中得到尺寸像素大小

final int buttonWidth = mActivity.getResources().getDimensionPixelSize(
                    R.dimen.actionbar_compat_button_width);

 

private View addActionItemCompatFromMenuItem(final MenuItem item) {
    final int itemId = item.getItemId();

    final ViewGroup actionBar = getActionBarCompat();
    if (actionBar == null) {
        return null;
    }

    // Create the button
    ImageButton actionButton = new ImageButton(mActivity, null,
            itemId == android.R.id.home
                    ? R.attr.actionbarCompatItemHomeStyle
                    : R.attr.actionbarCompatItemStyle);
    actionButton.setLayoutParams(new ViewGroup.LayoutParams(
            (int) mActivity.getResources().getDimension(
                    itemId == android.R.id.home
                            ? R.dimen.actionbar_compat_button_home_width
                            : R.dimen.actionbar_compat_button_width),
            ViewGroup.LayoutParams.FILL_PARENT));
    if (itemId == R.id.menu_refresh) {
        actionButton.setId(R.id.actionbar_compat_item_refresh);
    }
    actionButton.setImageDrawable(item.getIcon());
    actionButton.setScaleType(ImageView.ScaleType.CENTER);
    actionButton.setContentDescription(item.getTitle());
    actionButton.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
            mActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item);
        }
    });

    actionBar.addView(actionButton);

    if (item.getItemId() == R.id.menu_refresh) {
        // Refresh buttons should be stateful, and allow for indeterminate progress indicators,
        // so add those.
        ProgressBar indicator = new ProgressBar(mActivity, null,
                R.attr.actionbarCompatProgressIndicatorStyle);

        final int buttonWidth = mActivity.getResources().getDimensionPixelSize(
                R.dimen.actionbar_compat_button_width);
        final int buttonHeight = mActivity.getResources().getDimensionPixelSize(
                R.dimen.actionbar_compat_height);
        final int progressIndicatorWidth = buttonWidth / 2;

        LinearLayout.LayoutParams indicatorLayoutParams = new LinearLayout.LayoutParams(
                progressIndicatorWidth, progressIndicatorWidth);
        indicatorLayoutParams.setMargins(
                (buttonWidth - progressIndicatorWidth) / 2,
                (buttonHeight - progressIndicatorWidth) / 2,
                (buttonWidth - progressIndicatorWidth) / 2,
                0);
        indicator.setLayoutParams(indicatorLayoutParams);
        indicator.setVisibility(View.GONE);
        indicator.setId(R.id.actionbar_compat_item_refresh_progress);
        actionBar.addView(indicator);
    }

    return actionButton;
}

res/values/attrs.xml文件

<resources>

    <declare-styleable name="AppTheme">
        <attr name="actionbarCompatTitleStyle" format="reference" />
        <attr name="actionbarCompatItemStyle" format="reference" />
        <attr name="actionbarCompatItemHomeStyle" format="reference" />
        <attr name="actionbarCompatProgressIndicatorStyle" format="reference" />
    </declare-styleable>

    <declare-styleable name="BezelImageView">
        <attr name="maskDrawable" format="reference" />
        <attr name="borderDrawable" format="reference" />
    </declare-styleable>

</resources>

res/values/dimens.xml文件

<resources>
    <dimen name="actionbar_compat_height">48dp</dimen>
    <dimen name="actionbar_compat_button_width">48dp</dimen>
    <dimen name="actionbar_compat_button_home_width">56dp</dimen>
</resources>

res/layout/main.xml文件

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <Button android:id="@+id/toggle_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="@string/toggle_title" />
</FrameLayout>

在MainActivity.java文件中,将res/menu/main.xml文件渲染出来。

public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater menuInflater = getMenuInflater();
    menuInflater.inflate(R.menu.main, menu);

    // Calling super after populating the menu is necessary here to ensure that the
    // action bar helpers have a chance to handle this event.
    return super.onCreateOptionsMenu(menu);
}

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            Toast.makeText(this, "Tapped home", Toast.LENGTH_SHORT).show();
            break;

        case R.id.menu_refresh:
            Toast.makeText(this, "Fake refreshing...", Toast.LENGTH_SHORT).show();
            getActionBarHelper().setRefreshActionItemState(true);
            getWindow().getDecorView().postDelayed(
                    new Runnable() {
                        @Override
                        public void run() {
                            getActionBarHelper().setRefreshActionItemState(false);
                        }
                    }, 1000);
            break;

        case R.id.menu_search:
            Toast.makeText(this, "Tapped search", Toast.LENGTH_SHORT).show();
            break;

        case R.id.menu_share:
            Toast.makeText(this, "Tapped share", Toast.LENGTH_SHORT).show();
            break;
    }
    return super.onOptionsItemSelected(item);
}

在 ActionBarHelperBase.setRefreshActionItemState(boolean refreshing) 文件中

设置refreshButton为View.GONE, 设置refreshIndicator为View.VISIBLE

public void setRefreshActionItemState(boolean refreshing) {
    View refreshButton = mActivity.findViewById(R.id.actionbar_compat_item_refresh);
    View refreshIndicator = mActivity.findViewById(R.id.actionbar_compat_item_refresh_progress);

    if (refreshButton != null) {
        refreshButton.setVisibility(refreshing ? View.GONE : View.VISIBLE);
    }
    if (refreshIndicator != null) {
        refreshIndicator.setVisibility(refreshing ? View.VISIBLE : View.GONE);
    }
}

注:boolean android.app.Activity.onMenuItemSelected(int featureId, MenuItem item)
Default implementation of android.view.Window.Callback.onMenuItemSelected for activities.

This calls through to the new onOptionsItemSelected method for the android.view.Window.FEATURE_OPTIONS_PANEL panel, so that subclasses of Activity don't need to deal with feature codes.

actionButton.setContentDescription(item.getTitle()); 出现错误:

Call requires API level 4 (current min is 3): android.widget.ImageButton#setContentDescription

出错的原因为AndroidManifest.xml中, uses-sdk中的android:minSdkVersion指定错误,按照错误提示变更minSdkVersion即可。

如该例中:<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="14" />

遗留问题:

点击标题栏最前面的Home按键怎么没有反应。

Android系统示例之ActionBarCompat的更多相关文章

  1. Android系统示例分析之AndroidBeamDemo

    在这个示例工程中,只有一个Activity: public class Beam extends Activity implements CreateNdefMessageCallback,      ...

  2. Android系统示例分析之AccelerometerPlay

    程序界面: 创建 SimulationView , 实现接口 SensorEventListener , 实现接口中两个抽象方法 public void onSensorChanged(SensorE ...

  3. [转载]Android系统开机画面的实现

    Android系统开机画面分为下面三个阶段: 1.开机图片:Android内核是基于标准内核的,对linux比较熟悉,特别是在开发板上移植过Linux系统的人就知道在内核引导过程中会显 示出一 个小企 ...

  4. Android 系统属性

    /************************************************************************ * Android 系统属性 * 说明: * 由于需 ...

  5. Android系统在超级终端下必会的命令大全(adb shell命令大全)

    . 显示系统中全部Android平台: android list targets . 显示系统中全部AVD(模拟器): android list avd . 创建AVD(模拟器): android c ...

  6. 【译】Android系统简介—— Activity

    续上一篇,继续介绍Android系统.上一篇: [译]Android系统简介 本文主要介绍构建Android应用的一些主要概念: Activity Activity是应用程序中一个单独的有UI的页面( ...

  7. 【转】Picasso – Android系统的图片下载和缓存类库

    来源:http://blog.chengyunfeng.com/?p=492 另一篇参考:http://blog.csdn.net/xu_fu/article/details/17043231 Pic ...

  8. Android系统的体系结构、开发语言及源码结构

    整理自android系统体系结构 Android 是google公司针对手机开发的一个平台,并公布了其中大部分代码,其大部分应用程序都是用JAVA开发的,毕竟它是商业性的产品嘛,有所保留也是理所 当然 ...

  9. Picasso – Android系统的图片下载和缓存类库

    Picasso – Android系统的图片下载和缓存类库 Picasso 是Square开源的一个用于Android系统下载和缓存图片的项目.该项目和其他一些下载图片项目的主要区别之一是:使用4.0 ...

随机推荐

  1. Linux知识(2)----中文输入法安装

    Ubantu14.04在English的环境下,没有中文输入法,自带的ibus不完整.现在基于ibus框架,有几个比较好用的输入法,如sunpingyin和google pinying,还有五笔的输入 ...

  2. J-LINK序列号修改

    打开J-LINK   COMMANDER中输入 exec setsn=xxxxxxxx 即可

  3. python核心模块之pickle和cPickle解说

    pickle模块使用的数据格式是python专用的,而且不同版本号不向后兼容,同一时候也不能被其它语言说识别.要和其它语言交互,能够使用内置的json包使用pickle模块你能够把Python对象直接 ...

  4. (转)媒体格式分析之flv -- 基于FFMPEG

    本来是应该先写一个媒体文件格式的简单讲解的,还没来得及写,以后再写.今天就先根据ffmpeg的flv.c的flv_demux这个结构体来讲解一下当前比较流行的媒体格式flv. FLV 是FLASH V ...

  5. andriod 下一个页面

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); s ...

  6. 【redis】spring boot中 使用redis hash 操作 --- 之 使用redis实现库存的并发有序操作

    示例: @Autowired StringRedisTemplate redisTemplate; @Override public void dealRedis(Dealer dealer) { d ...

  7. appium+python自动化26-模拟手势点击坐标(tap)

    ​# 前言: 有时候定位元素的时候,你使出了十八班武艺还是定位不到,怎么办呢?(面试经常会问) 那就拿出绝招:点元素所在位置的坐标 tap用法 1.tap是模拟手指点击,一般页面上元素 的语法有两个参 ...

  8. thinkphp输出表格

    //这是打印5列n行的表格,所以mod="5" value="4" <tr> <volist name="data" id ...

  9. Node 多进程并发控制小模块 - lockman

    介绍 lockman 是一个用于多进程的并发控制锁, 类似一些语言中(比如 C#)的 lock 关键字可以用来确保代码块完成运行,而不会被其他进程中断.它可以把一段代码定义为互斥段(critical ...

  10. @MySQL中length字符长度函数使用方法

    MySQL里面的length函数是一个用来获取字符串长度的内置函数,一个汉字是算三个字符,中文的标点符号也是算三个字符,一个数字或字母算一个字符.具体用法示例如下: 1.查看某字符串的长度 SELEC ...