[转载]ORM开发之解析lambda实现完整查询(附测试例子) - hubro - 博客园

mikel阅读(1513)

[转载]ORM开发之解析lambda实现完整查询(附测试例子) – hubro – 博客园.

上次讲解了怎么解析匿名对象(ORM开发之解析lambda实现group查询),这次来实现解析二元运算,完成基本条件语法

先看一个表达式

1
query.Where(b => b.Number == 10&&b.Id<20);

表达式结构

一个运算符表示一个表达式,因此,此表达式实际上包含两个子表达式 b.Number==10 和b.Id<20 他们的关系为And

看一个子表达式 b.Number==10
按运算符为位置,左边为左操作数,右边为右操作数

以And操作符来看,b.Number==10也为左操作数,b.Id<20为右操作数

再增加其它条件时,也是同样的道理

那么我们解析将一个子表达式 b.Number==10 转换为SQL逻辑,则需要:

  1. 取出左表达式对应的字段名称 Number
  2. 取出运算符 =
  3. 取出右表达式的值 10

表达式类型

由上可以看出,表达式分左边和右边,左右两边也可是子表达式,它们形成一个表达式树,基类型都为System.Linq.Expressions.Expression

具体类型大致按下面划分为:

  1. BinaryExpression 表示包含二元运算符的表达式。 可以理解为一个子表达式,如 b.Number>10
  2. MemberExpression 表示访问字段或属性。 如 b.Number
  3. NewArrayExpression 表示创建新数组并可能初始化该新数组的元素。
  4. MethodCallExpression 表示对静态方法或实例方法的调用 如 b.Name.Contains(“123”)
  5. ConstantExpression 表示具有常量值的表达式 如 b.Name=”hubro”
  6. UnaryExpression 表示包含一元运算符的表达式

因此,需要根据不同的类型解析不同的表达式

开始解析

拆分表达式树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/// <summary>
        /// 拆分表达式树
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public string BinaryExpressionHandler(Expression left, Expression right, ExpressionType type)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("(");
            string needParKey = "=,>,<,>=,<=,<>";
            string leftPar = RouteExpressionHandler(left);//获取左边
            string typeStr = ExpressionTypeCast(type);//转换运算符
            var isRight = needParKey.IndexOf(typeStr) > -1;//用以区分是解析左边的名称还是右边的值
            string rightPar = RouteExpressionHandler(right, isRight);//获取右边
            string appendLeft = leftPar;
            sb.Append(appendLeft);//字段名称
           
            if (rightPar.ToUpper() == "NULL")
            {
                if (typeStr == "=")
                    rightPar = " IS NULL ";
                else if (typeStr == "<>")
                    rightPar = " IS NOT NULL ";
            }
            else
            {
                sb.Append(typeStr);
            }
            sb.Append(rightPar);
            sb.Append(")");
            return sb.ToString();
        }

解析表达式

表达式树也会在这里处理,形成递归调用,当表达式是MemberExpression时,为了区分是左边的属性名还是右边的属性值,加了isRight进行区分

当是MethodCallExpression时,如果是左边,则需要进行解析(这里没有实现),右边只需要执行方法结果即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/// <summary>
        /// 解析表达式
        /// </summary>
        /// <param name="exp"></param>
        /// <param name="isRight"></param>
        /// <returns></returns>
        public string RouteExpressionHandler(Expression exp, bool isRight = false)
        {
            if (exp is BinaryExpression)
            {
                BinaryExpression be = (BinaryExpression)exp;
                //重新拆分树,形成递归
                return BinaryExpressionHandler(be.Left, be.Right, be.NodeType);
            }
            else if (exp is MemberExpression)
            {
                MemberExpression mExp = (MemberExpression)exp;
                if (isRight)//按表达式右边值
                {
                    var obj = Expression.Lambda(mExp).Compile().DynamicInvoke();
                    if (obj is Enum)
                    {
                        obj = (int)obj;
                    }
                    return obj + "";
                }
                return mExp.Member.Name;//按左边的名称
            }
            else if (exp is NewArrayExpression)
            {
                #region 数组
                NewArrayExpression naExp = (NewArrayExpression)exp;
                StringBuilder sb = new StringBuilder();
                foreach (Expression expression in naExp.Expressions)
                {
                    sb.AppendFormat(",{0}", RouteExpressionHandler(expression));
                }
                return sb.Length == 0 ? "" : sb.Remove(0, 1).ToString();
                #endregion
            }
            else if (exp is MethodCallExpression)
            {
                if (isRight)
                {
                    return Expression.Lambda(exp).Compile().DynamicInvoke() + "";
                }
                //在这里解析方法
                throw new Exception("暂不支持");
            }
            else if (exp is ConstantExpression)
            {
                #region 常量
                ConstantExpression cExp = (ConstantExpression)exp;
                if (cExp.Value == null)
                    return "null";
                else
                {
                    return cExp.Value.ToString();
                }
                #endregion
            }
            else if (exp is UnaryExpression)
            {
                UnaryExpression ue = ((UnaryExpression)exp);
                return RouteExpressionHandler(ue.Operand, isRight);
            }
            return null;
        }

转换运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public string ExpressionTypeCast(ExpressionType expType)
        {
            switch (expType)
            {
                case ExpressionType.And:
                    return "&";
                case ExpressionType.AndAlso:
                    return " AND ";
                case ExpressionType.Equal:
                    return "=";
                case ExpressionType.GreaterThan:
                    return ">";
                case ExpressionType.GreaterThanOrEqual:
                    return ">=";
                case ExpressionType.LessThan:
                    return "<";
                case ExpressionType.LessThanOrEqual:
                    return "<=";
                case ExpressionType.NotEqual:
                    return "<>";
                case ExpressionType.Or:
                    return "|";
                case ExpressionType.OrElse:
                    return " OR ";
                case ExpressionType.Add:
                case ExpressionType.AddChecked:
                    return "+";
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked:
                    return "-";
                case ExpressionType.Divide:
                    return "/";
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked:
                    return "*";
                default:
                    throw new InvalidCastException("不支持的运算符");
            }
        }

获取解析值

1
2
3
4
5
6
7
8
9
internal string FormatExpression(Expression<Func<T, bool>> expression)
        {
            string condition;
            var visitor = new ExpressionVisitor();
            if (expression == null)
                return "";
            condition = visitor.RouteExpressionHandler(expression.Body);
            return condition;
        }

拼接完整的SQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public string GetQuery()
        {
            string where = Condition;
            where = string.IsNullOrEmpty(where) ? " 1=1 " : where;
            #region group判断
            if (groupFields.Count > 0)
            {
                where += " group by ";
                foreach (var item in groupFields)
                {
                    where += item + ",";
                }
                where = where.Substring(0, where.Length - 1);
            }
            #endregion
            string tableName = typeof(T).Name;
            string fileds = string.Join(",", queryFields);
            var part = string.Format("select {0} from {1}  where {2}", fileds, tableName, where);
            return part;
        }

运行输出

1
2
3
4
5
6
7
8
9
var query = new LambdaQuery<Product>();
            query.Select(b => new { b.BarCode, b.ProductName, total = b.BarCode.COUNT() });
            query.GroupBy(b => new { b.BarCode, b.ProductName });
            query.Where(b => b.ProductName == "ddd");
            query.Where(b => b.Number == 10);
            query.Where(b => b.Number == new aa().bb);//测试获取对象参数
            query.OrderBy(b => b.BarCode.COUNT(), true);
            Console.Write(query.GetQuery());

这样,一般查询就能用lambda来表示了,但是一些SQL函数,是没法表示的,和之前说的一样,可以用扩展方法解决

上面上解析方法调用表达式里,解析即可,解析方法比较复杂,就不在这里写了

1
2
3
4
5
6
7
8
9
else if (exp is MethodCallExpression)
            {
                if (isRight)
                {
                    return Expression.Lambda(exp).Compile().DynamicInvoke() + "";
                }
                //在这里解析方法
                throw new Exception("暂不支持");
            }

测试例子下载 http://files.cnblogs.com/files/hubro/LambdaQueryTest2.rar

请出价 估值过亿 要用C2B颠覆B2C?

mikel阅读(1329)

原文《微信服务号请出价:凭什么估值过亿? 用C2B颠覆B2C》摘要:

用C2B颠覆B2C

马云不久前在德国汉诺威IT博览会(CeBIT)上演讲说,未来的生意将是C2B而不是B2C,用户改变企业,而不是企业向用户出售。马云做梦都想实现的这种商业模式,正是 “请出价”的核心:C2B。

C2B的价值在于:

1、颠覆了现有所有电商平台的售卖模式。不论是淘宝、京东、天猫,几乎所有电商平台都是平台定价,用户只有购买和不购买的权利,没有议价权。请出价不同,将定价权交给用户,用户自己来决定自己购买的价格。

在传统的商业行为中,中国老百姓是有议价砍价的习惯的。在互联网上,这种习惯被弱化为比价,用户会筛选多个电商平台,然后选择价格更为合适的平 台来购买产品。比价的效率低下,花费时间不说,而且比价的最终的结果未必满意,小平台的价格可能更低,但是产品质量难以保证。请出价恰恰是满足了对价格较 为敏感,同时又不想花费太多时间去筛选的这部分消费者需求。

2、改变了商品的实际售卖价格。消费者在请出价平台买的商品,实际价格都比电商平台价格较低,原因是什么?还是回到用户出价模式。

由于出价信息不公开,每个消费者的出价均不相同,迫切想得到这件商品的土豪朋友,可能出得价格较高,他们是一群想成为首批iphon6和 iwatch使用者的特定人群;经济宽裕的普通民众,他们出的价格相对合理,不会低于各大电商平台的平均售价太多;很少一部分穷人消费者会出价极低——出 价越低,购买商品的成功率就越低。经过土豪消费者和穷人消费者的加和,请出价的最终定价就无限接近于普通民众的出价区间,这样三类人都将获得好处:土豪抢 先拥有了商品,普通消费者如愿以偿拿到了定价稍低的商品并且还不用花费时间去比价,穷人消费者以不可思议的价格购入了商品。

观点:

网购的时候最麻烦的就是比价格,需要到处搜索商品到处比较运费、价格、产品评论等等问题,消费者完全是被动接受卖家的报价,顶多在旺旺上侃侃运费和小礼品什么的,完全没有翻身做主的感觉,买个东西跟欠别人钱似的,就这个价,低了不卖!

在现在这个产能过剩,供大于求的时代,老百姓完全可以自己定价,至于这个价格是否合理,我想有了前期的商家定价售卖,不会偏差到哪去,有钱的出高点儿,没钱的出低点儿,取个平均值,基本上大家都能接受,不想买了就弃单不买,其实很容易简单处理,至于商家就需要保质保量的出货,价格自己有个可以接受的范围,毕竟不能赔本儿赚吆喝不是,就跟线下砍价一样,合适就交易,不合适就拉倒。

至于什么C2B垫付B2C,那就是噱头,没那么严重谁颠覆谁,大家节约时间,提高效率,别在那为了一毛钱争得面红耳赤就行了!商业就是买卖,一个愿买,一个愿卖,交易就达成了,整那么多噱头没用!到让人看着迷茫!

[转载]浅谈Android五大布局(二)——RelativeLayout和TableLayout - 熊猫82 - 博客园

mikel阅读(1129)

[转载]浅谈Android五大布局(二)——RelativeLayout和TableLayout – 熊猫82 – 博客园.

  在浅谈Android五大布局(一)中 已经描述了LinearLayout(线性布局)、FrameLayout(单帧布局)和AbsoulteLayout(绝对布局)三种布局结构,剩下的 两种布局RelativeLayout(相对布局)和TableLayout(表格布局)相对之前布局结构稍显复杂一点,所以这里另起篇幅进行介绍。

RelativeLayout:

RelativeLayout按照各子元素之间的位置关系完成布局。在此布局中的子元素里与位置相关的属性将生效。例如 Android:layout_below, Android:layout_above等。子元素就通过这些属性和各自的ID配合指定位置关系。注意在指定位置关系时,引用的ID必须在引用之前,先 被定义,否则将出现异常。

RelativeLayout里常用的位置属性如下:
Android:layout_toLeftOf —— 该组件位于引用组件的左方
android:layout_toRightOf —— 该组件位于引用组件的右方
android:layout_above —— 该组件位于引用组件的上方
android:layout_below —— 该组件位于引用组件的下方
android:layout_alignParentLeft —— 该组件是否对齐父组件的左端
android:layout_alignParentRight —— 该组件是否齐其父组件的右端
android:layout_alignParentTop —— 该组件是否对齐父组件的顶部
android:layout_alignParentBottom —— 该组件是否对齐父组件的底部
android:layout_centerInParent —— 该组件是否相对于父组件居中
android:layout_centerHorizontal —— 该组件是否横向居中
android:layout_centerVertical —— 该组件是否垂直居中

RelativeLayout是Android五大布局结构中最灵活的一种布局结构,比较适合一些复杂界面的布局。下面示例就展示这么一个情况,第一个文本框与父组件的底部对齐,第二个文本框位于第一个文本框的上方,并且第三个文本框位于第二个文本框的左方。

RelativeLayout
<!--?xml version="1.0" encoding="utf-8"?-->

TableLayout:

  TableLayout顾名思义,此布局为表格布局,适用于N行N列的布局格式。一个TableLayout由许多TableRow组成,一个TableRow就代表TableLayout中的一行。

TableRow是LinearLayout的子类,它的android:orientation属性值恒为horizontal,并且它的 android:layout_width和android:layout_height属性值恒为MATCH_PARENT和 WRAP_CONTENT。所以它的子元素都是横向排列,并且宽高一致的。这样的设计使得每个TableRow里的子元素都相当于表格中的单元格一样。在 TableRow中,单元格可以为空,但是不能跨列。

下面示例演示了一个TableLayout的布局结构,其中第二行只有两个单元格,而其余行都是三个单元格。

TableLayout
<!--?xml version="1.0" encoding="utf-8"?-->








[转载]浅谈Android五大布局(一)——LinearLayout、FrameLayout和AbsoulteLayout - 熊猫82 - 博客园

mikel阅读(1131)

[转载]浅谈Android五大布局(一)——LinearLayout、FrameLayout和AbsoulteLayout – 熊猫82 – 博客园.

  Android的界面是有布局和组件协同完成的,布局好比是建筑里的框架,而组件则相当 于建筑里的砖瓦。组件按照布局的要求依次排列,就组成了用户所看见的界面。Android的五大布局分别是LinearLayout(线性布局)、 FrameLayout(单帧布局)、RelativeLayout(相对布局)、AbsoluteLayout(绝对布局)和 TableLayout(表格布局)。

  LinearLayout:

LinearLayout按照垂直或者水平的顺序依次排列子元素,每一个子元素都位于前一个元素之后。如果是垂直排列,那么将是一个N行单列的 结构,每一行只会有一个元素,而不论这个元素的宽度为多少;如果是水平排列,那么将是一个单行N列的结构。如果搭建两行两列的结构,通常的方式是先垂直排 列两个元素,每一个元素里再包含一个LinearLayout进行水平排列。

LinearLayout中的子元素属性Android:layout_weight生效,它用于描述该子元素在剩余空间中占有的大小比例。加 入一行只有一个文本框,那么它的默认值就为0,如果一行中有两个等长的文本框,那么他们的android:layout_weight值可以是同为1。如 果一行中有两个不等长的文本框,那么他们的android:layout_weight值分别为1和2,那么第一个文本框将占据剩余空间的三分之二,第二 个文本框将占据剩余空间中的三分之一。android:layout_weight遵循数值越小,重要度越高的原则。显示效果如下:

LinearLayout
<!--?xml version="1.0" encoding="utf-8"?-->

  FrameLayout:

FrameLayout是五大布局中最简单的一个布局, 在这个布局中,整个界面被当成一块空白备用区域,所有的子元素都不能被指定放置的位置,它们统统放于这块区域的左上角,并且后面的子元素直接覆盖在前面的 子元素之上,将前面的子元素部分和全部遮挡。显示效果如下,第一个TextView被第二个TextView完全遮挡,第三个TextView遮挡了第二 个TextView的部分位置。

 

FrameLayout
<!--?xml version="1.0" encoding="utf-8"?-->

  AbsoluteLayout:

AbsoluteLayout是绝对位置布局。 在此布局中的子元素的android:layout_x和android:layout_y属性将生效,用于描述该子元素的坐标位置。屏幕左上角为坐标原 点(0,0),第一个0代表横坐标,向右移动此值增大,第二个0代表纵坐标,向下移动,此值增大。在此布局中的子元素可以相互重叠。在实际开发中,通常不 采用此布局格式,因为它的界面代码过于刚性,以至于有可能不能很好的适配各种终端。显示效果如下:

AbsoluteLayout
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
<TextView android:layout_width="50dp" android:layout_height="50dp" android:background="#ffffffff" android:gravity="center" android:layout_x="50dp" android:layout_y="50dp" android:text="1"/>
<TextView android:layout_width="50dp" android:layout_height="50dp" android:background="#ff654321" android:gravity="center" android:layout_x="25dp" android:layout_y="25dp" android:text="2"/>
<TextView  android:layout_width="50dp" android:layout_height="50dp" android:background="#fffedcba" android:gravity="center" android:layout_x="125dp" android:layout_y="125dp" android:text="3"/>
</AbsoluteLayout>

屎一样的产品,运营也得吞下去

mikel阅读(1293)

原文《关于运营工作的10个误区全在这儿,你信吗?不信,你看!》摘要:

运营工作虽苦逼却是十分神圣的,毕竟是身处一线,直接面对用户,人前挨骂不说,在公司还经常背黑锅,甚至不被重视。我希望大家能正视这个行业,能理解他们工作的不易。当然做啥都不容易,我不是有意袒护运营,改天我可以再写一篇关于产品工作的。

为什么运营不能被取代?“技术改变世界”、“产品改变世界”这种说法经常有,人家只是说要重视和强调技术和产品,这点毋庸置疑,我也深信,但不代表可以漠 视运营。机器、代码、规则永远是冷冰冰的,无感情的,灵活性远远不够。我也相信未来的某一天,人类科技可以做到,但至少目前不是。所以运营无法被取代。

 

误解2:屎一样的产品,运营也得吞下去

我觉得这是极其不负责的一句话。互联网已经不是2010年以前运营为驱动的时代了,早年的社区产品、功能其实都很渣,运营硬撑,也能做的很不错。猫扑是典 型的强运营为驱动的产品,我们社区的人数从来没超过20人,所以做过的运营模块足够多。再就是秀场模式,他们的运营强度更大。

2010年以后,尤其是移动互联网崛起之后,已经进入产品时代。产品做得太渣,神仙都难救,因为可替代品实在太多了,你做得不好,用户就去别家了。

必须重视产品,把产品体验做得够好,真正把握用户的需求。现在这个时代,已经不能抱有“强奸用户”的思维了。很多互联网一代、二代的成功者,思维已经落伍了。

产品和运营需要保持一个合适的比重,我从来不赞成堆人头的战术。产品强,运营成本就可以小,运营的压力也可以小。产品弱,运营做的就会更苦逼。

反省吧,别再为你的产品渣得可怜,还努力找借口!

运营可以抱怨、吐槽么?关键是你抱怨也没用啊,活儿还不得照干。领导不是傻子,能成为你领导肯定都有他的本事。要么忍,要么滚。而且抱怨、吐槽会极其影响团队的激情和团结,这种人能力再强,都不可留,这种情绪应该及时阉割。

产品也没有做完的时候,上线之后也需要不断优化。一个产品最终成为何种形态,是需要跟着用户需求、运营的需求、跟着时代趋势不断演进的。连张小龙都不敢说微信的最终形态是啥样的,何况咱们这些后辈?

观点:

运营工作不是人人都可以做的,进入门槛低,看似简单,其实任何一个职业都怕做得深入和坚持,你深入做10年运营,自然你就可以做到极致,就像做产品和做技术的一样,很多人对自己的职业就像看围城,城内的人看着别的职业好,抱怨自己的职业如何如何不如人意,城外的人却羡慕城内的人多么滋润等等。

这个产品运营密不可分的时代,有多少产品可以分清楚运营和产品,你看看小米,各种产品开发人员天天泡论坛、当客服,做用户反馈等等工作,这样才会做出眼前一亮的产品,所以说运营工作不简单也很复杂,未来运营不和或缺的人才就是综合人才,但是文章总结的几点也是别的职业值得借鉴的,不要抱怨多思考深入自己的业务能力,才能做好。

[转载]App的成本 - 纯银的日志 - 网易博客

mikel阅读(1131)

[转载]App的成本 – 纯银的日志 – 网易博客.

今晚想算算制造一款App的成本。

单说iPhone版。

通常情况下需要后端工程师×1,客户端工程师×1,UI设计师×1,产品经理×1。这已经是比较精简的配置。搁大公司,还得再配置测试工程师,运维工程师,交互设计师等等。

如果遇上全端工程师,或者对后端的依赖不大,工程师或许可以减少到1个。如果产品经理和UI设计师恰好可以合体,那么产品团队最少2个人——这情况很罕见,大部分时候起码得3-4人拿出一款产品来,5-6人也很正常。

3-6人,从人数上来看并不多。麻烦的是分散在三四个工种,独当一面,各自负责三四个核心环节,也就是出现短板的风险特别大。

根据我的经验,互联网从业人员里,合格者的比例可能还不到一半。即便人合格吧,也不一定适合这款产品的设计风格,技术特性。产品项目最大的人力支出项并不是薪酬,而是招募组建这支团队的时间成本,以及在不得已的情况下,降低标准组队带来的质量与效率下降。

好吧,我们假定组队成功。从头研发一款App通常需要1-3个月,从发布到产品相对稳定,相对成熟,又需要1-6个月。合起来是1-3个季度。

如果4个人半年多就能折腾一款体验成熟的App出来,那真不算什么事儿——大头是运营成本。

运营成本可以细分为用户运营,内容运营,资源拓展、市场营销等等,只要产品还活着,就会持续地要求运营投入。前三样也就是1-10个人的配置,真正可怕的是营销成本,毕竟做一款有需求有品质的产品,很快自发传播开的时代早就过去了。这里有几种情况需要考虑:

1、App分发渠道高度集中,以至于排行榜更迭速度极快。新产品即便上榜也会快速下沉,接下来需要持续的营销投入来维持曝光。

2、没钱投入,分发渠道靠不住的话,就得依赖社交传播。然而用户是否活跃,是否容易分享内容,首先取决于产品定位与场景,其次才关系到品质与体验。只可惜用户活跃又乐意分享的产品类型注定是极少数,比如10%。

3、即便你的产品就是那10%,能带来有效的社交传播,它还能创造稳定的使用场景与用户价值吗?是否一阵风刮过去,然后就寂然无声。想想曾经风靡一时的疯狂猜图,曾经一个月内(全球)下载上百万次的画中画相机。

4、即便你的产品就是那1%,又有社交传播,又有用户价值,你以为这就搞掂了吗?Too simple,sometimes naive。这样的产品会在瞬间被大公司复制去,只留下你坐在地上蹬腿哭闹:他们欺负我,他们不要脸。

绝大部分新应用想存活下来,就得准备足够的营销费用,别妄想“酒好不怕巷子深”。这个数字可能是起初人力成本的N倍。当然,产品足够赞,也会减少营销费用的比例,但产品的其他成本又飙上去了。你还真指望三五个人做款App出来打遍天下无敌手啊?

所以,钱,钱,钱,以及越来越多的人和时间。当你推进一个移动项目的时候,就掉进了成本的无底洞里,并非“只差一个程序员了”这么简单。何况我还没有计算App从用户价值到商业价值之间的低效率转化。

绝大部分App支付不起这么大的投入,冒个泡就沉了,或者冒个泡没多久就沉了,或者冒个泡之后死撑了一两年,然后就咕嘟咕嘟沉了。

如此高的成本,使得新应用必然往大里使劲,想成为大家伙,做大事业,拿下大市场,这才能说服VC和老板给予大投入。小打小闹死路一条。

但人人都往大里做,带来的结果是产品种类上的同质化,反倒遏制了创新。我去跟别人谈新应用想法,得到的回应首先是:能做多大?有商业价值吗?拿得到几百万融资?

做产品既可以是一件事业,也可以是一种自我满足的游戏,后者能激发更多的创造力,带来市场的多样化。但是,一想到要投入如此高成本,最后很可能还是无声无息地沉了下去,大多数人宁肯把有限的精力押在有可能做大的产品上面,进入谨小慎微的高风险高回报模式。

2013 年至今,国内外互联网都没有出现“爆款”的产品。如果做产品总是一场输不起的豪赌,这个市场的创新能力就会渐渐衰竭。下半年,我会推动一系列个性十足的、 不乏创新与趣味,但全无商业价值的小应用项目,在蝉小队内部,或者在外面组织兴趣小组来实现,但求绽放如烟火。特此预告,焚香祈祷。

————————————————————

PS: 这篇文章发出来,又有不少人加重语气感慨大公司的抄袭问题。请问,一整个2013年,国内有哪些创新产品靠自己挺直腰板打下一片地盘,又因为被大公司抄 袭,侵蚀市场份额流血而死的?100个怕被抄的人啊,99个连被抄的资格都没有,感慨个啥。说得好像人家不来抄你,自个儿就能活得下去一样。

艾王爷 月入百万的另类淘宝客

mikel阅读(1382)

原文《月入百万的另类淘宝客(嘉宾:艾王爷)》摘要:

艾王爷:现在每个月上百万左右,其实也没啥 要是把一个项目当一份事业做了 这点钱其实真不多,在我们圈内还有更多比我厉害的人。

艾王爷:我觉得新手还是从佣金高的产品下手,因为每天这些宝贝的流量大,搜索人 数。我分享一个淘宝代购的方法吧,这个是正规的可以分享,现在很多做淘宝代购,不是国外代购那种,而是你不会在淘宝买东西,你让我来给你买,你直接给我现 金就ok。但是做代购的人不知道淘宝客这么回事,那么我们就要找到这些人跟他们做合作,让他们买东西的时候跟我们合作,用我们的淘宝客链接去购买,然后给 对方佣金,可以一人一半。一般在初中高中和大学边上的小商店就有很多人做代购,他们完全不知道用淘客链接去买,跟他们谈下来合作就ok了,如果能搞定一个城市的所有商店,一个月赚个一两万没啥问题,我有个读者,把北京通州的所有商家都谈下来了,现在一天4000+收入。

观点:

淘宝客自从阿里妈妈频频改了规则后,很多人放弃了这个项目,转作其他,国内很多疯狂一时的各种淘宝客网站和论坛纷纷偃旗息鼓,可规则变了,就真的没得玩了?!今天看了艾王爷的访谈文章,感觉还是心态问题,艾王爷说的好一个项目要当一份事业做,而不是当成投机赚暴利的工具,当成事业就会认真的去分析和策划了。

方法艾王爷提到个方法,就是现在各个媒体嚷嚷的O2O方式,人家都已经做到了线上线下互利营销做到百万,可见那些赚到钱的都是低调行事,闷头赚钱,只有那些不懂的和想骗钱的才在各个媒体上发文章分析这个分析那个,结果都是骗眼球然后赚培训费,至于有没有效果那就可想而知了。所以说国内互联网就是乱呢,那么多不负责任的媒体在那瞎逼逼,混淆视听,罪不可赦!根本没有节操可言!

[转载]Fragment销毁时replace和add两个方法的区别 - 观千剑而后识器,操千曲而后晓声。 - 博客频道 - CSDN.NET

mikel阅读(1082)

[转载]Fragment销毁时replace和add两个方法的区别 – 观千剑而后识器,操千曲而后晓声。 – 博客频道 – CSDN.NET.

这个首先从一个bug说起,如图:

 

我们都知道fragment切换有两种方式:

1. replace方式

transaction.replace(R.id.content, IndexFragment);

2. add-hide-show方式

transaction.add(R.id.content, IndexFragment);  transaction.hide(otherfragment);  transaction.show(thisfragment);

而上面按钮中出现bug的就是采用第二种方式。然后我们来分析下用add,hide,show为什么出现这种bug,我把每个操作都打印出了以下日志:

复现bug的操作是:
1.首先打开,默认选中的是第一个tab,如上面的一张图片正常那样。
2.切换到tab2,并把tab1 hide掉;
3.再切回到tab1,并不会触发tab1对应fragment的任何生命周期;
4.然后home键进入后台,我在activity的onPause()中手动对IndexFragment赋空,模拟长时间后台,系统销毁了该引用。

IndexFragment=null;

5.再次启动,其实tab1 的fragment实例在内存中还在,只是他的引用被销毁了。
6.再切到tab2,这里其实是先把tab1的hide,在show tab2,但是tab1 的fragment引用为空,所以无法hide,就出现了tab2叠在tab1上的花屏情况。
7.再切到tab1,tab1就会重复创建对象。

同样的操作,我们使用replace的方式

使 用replace方式,虽然这种方式会避免上述的bug,但也是重复创建了对象。因为replace方式,对应的FrameLayout只有一 层,而add方式,这个FrameLayout其实有2层。但是这种方式的缺点是:每次replace会把生命周期全部执行一遍,如果在这些生命周期函数 里拉取数据的话,就会不断重复的加载刷新数据。

那么最合适的处理方式是这样的:

1.在add的时候,加上一个tab参数
transaction.add(R.id.content, IndexFragment,”Tab1″);
2.然后当IndexFragment引用被回收置空的话,先通过
IndexFragment=FragmentManager.findFragmentByTag(“Tab1″);
找到对应的引用,然后继续上面的hide,show;

莆田系和百度的竞价撕逼大战

mikel阅读(1238)

原文《百度回应将加大整治莆田系,莆田系医院凭什么敢与百度抗争?》摘要:

敢于和百度叫板,作为中国民营医疗市场主力军的“莆田系”到底是如何发家?所谓的四大家族旗下又有哪些产业?莆田系遍布全国背后操纵的大人物为何又要有意保持神秘?

缘于近日莆田(中国)健康产业总会向所有莆田系医疗机构发放通知,要求协会中所有机构停止在互联网上的有偿网络推广。莆田总会指出:如今因为网络竞 价的规则,导致行业面临严重问题,很多医疗机构几乎为互联网公司打工。另据微博账号@龚文祥提供的信息,很多大城市的医疗竞价词都涨到封顶,达到每次点击 999元。

今日早些时候百度新闻官方微博就针对莆田系的抵制进行了回应,微博内容称近日由于百度加大整治并下线违规医院,引发了最大民营医院群体莆田系的联合抵制。百度对此事的态度强硬到底,并会加大整治以莆田系为代表的违规医疗推广。

百度回应
观点:

两个行业的老大互相的撕逼大战,曾经是百度的大客户莆田系“ 2013 年的广告总量是 260 亿元,莆田的民营医院在百度就做了 120 亿元的广告。”可见医疗行业的暴利之大让人瞠目结舌,后面确实百度这个大赢家在闷头数钱,后来经过央视曝光网络医疗的广告内幕,百度不得不挥泪斩马谡,开始加大审核力度,那为什么曾经的大客户现在拒绝抱大腿了?表面上看是竞价规则对医疗审查的严控,大客户受不了管制彻底决裂。

为什么选择现在出逃就值得令人回味了,做了那么多年的竞价又不是今天点击单价高得吓人了,都挺过来了,天下熙熙皆为利来,可见利润被彻底的稀释没了,所以大客户迫于收益的压力反目成仇,背后则是互联网监管不严的情况下,让那些暴利行业盯上了这个“人傻 钱多 没人管”的大市场,这是国内互联网必须经历的一个过程,从放任自流无人管到更加严格净化和维护互联网的环境还原一个本来面目互联网给网民和企业,不再有那么多的黑手在上面捞钱,百度的态度就比较令人回味了,说是自己强化监管冠冕堂皇,实则是自己迫于各方面的监管增强的压力下不得不迈出这一步,纯属被逼的,竞价目前还是百度赖以生存的收入来源不能有任何闪失,只能弃卒保车了!

 

[转载]9.1.1 setDuration方法:设置持续时间 - 51CTO.COM

mikel阅读(1584)

[转载]9.1.1 setDuration方法:设置持续时间 – 51CTO.COM.

9.1.1  setDuration方法:设置持续时间

【功能说明】该方法用于设置动画的持续时间,以毫秒为单位。该方法是设置补间动画时间长度的主要方法,使用非常普遍。

【基本语法】public void setDuration (long durationMillis)

其中,参数durationMillis为动画的持续时间,单位为毫秒(ms)。

setDuration方法的示例可以参阅startNow方法中的示例代码。