android fragmentactivity fragment,Android:Activity与Fragment通信(99%)完美解决方案

前言

最近一直在想着能否有一种更好的方案来解决:Android中Activity与Fragment之间通信的问题,什么叫更好呢,就是能让Fragment的复用性高,性能还有好(不用反射),代码还要好维护,不需要为每对Activity和Fragment之间定义接口而发愁。

先简单说下Javascript这门语言吧,或许有人就会问:咱们不是聊Android的java问题吗?怎么话题转到JavaScript了。因为我的解决方案的启发是从它来的,没兴趣的朋友可以略过。最近在学习javascript这门语言,同时自己搞Android(java)开发也有5年多时间了,所以在学习js的过程中,就会惯性的把这两者进行比较。

与java语言的 严谨 相比 Javascript是一门"放荡不羁"、"不拘小节"(宽泛)的语言。

为什么要用"放荡不羁"这个词呢,下面是它的一个解释:

放荡不羁 [fàng dàng bù jī][解释] 羁:约束。放纵任性,不加检点,不受约束。

因为我觉得这个词更能充分的体现js弱类型的特点。

在给变量赋值时 可以这样写:

var a = 1;

还可以这样写:

var b = '123';

var o = new Object();

甚至还可以这样写:

var fun = new function(){};

fun1 = new function(){};

可以把任何类型的值赋给一个变量,也可以不加var关键字来声明一个变量,是不是很任性,很不拘束啊。

"不拘小节"主要体现了JavaScript的语法更宽泛、更简单的特点: 比如:

js代码:

//函数声明不需要定义返回值,参数前面不需要有类型出现,

//函数体里面就可以有返回值

function max(a,b){ return a > b? a:b; }

/* *可以传递任意多个参数,在java里面根本不可以 */

function print(){

var len = arguments.length;

for(var i = 0; i < len; i++){

console.log(arguments[i]);

}

}

相应java代码:

int max(int a, int b){

return a> b? a:b;

}

/* *传递任意多个Object类型的参数 */

void print(Object... args){

for (int i = 0; i < args.length; i++){

System.out.println(args[i]);

}

}

上面的代码说明了JavaScript在声明函数时,不会有像java那么严格的规定,语法不拘小节,语法更简单(这里没有说java不好的意思)。

启发点

JavaScript中有一个重要的点(万事万物皆对象),函数也不列外,并且函数可以作为另外一个函数的参数,如:

js代码:

//遍历一个数组如果是它是数组,就把它乘以10再输出

var array = [1,2, '你好' , '不' ,31,15];

//数组的each方法接收一个函数

testArray.each( function( value ){

typeof value == 'number' ? alert( value *10 ):null;

}) ;

当我看到上面JavaScript中函数的用法时我眼前一亮,为啥我不可以借鉴之来解决android中activity与fragment通信的问题呢?

Fragment的使命

先让我们聊聊Fragment为什么出现,这对于我们解决Activity与Fragment的通信有帮助。一个新事物的产生总是为了解决旧事物存在的问题,Fragment是android3.0的产物,在android3.0之前解决手机、平板电脑的适配问题是很头疼的,对ActivityGroup有印象的朋友,应该能深深的体会到ActivityGroup包裹的多个Activity之间切换等一系列的性能问题。由此Fragment诞生了。个人总结的Fragment的使命:

解决手机、平板电脑等各种设备的适配问题

解决多个Activity之间切换性能问题

模块化,因为模块化导致复用的好处

Fragment的使用

Fragment是可以被包裹在多个不同Activity内的,同时一个Activity内可以包裹多个Fragment,Activity就如一个大的容器,它可以管理多个Fragment。所有Activity与Fragment之间存在依赖关系。

Activity与Fragment通信方案

上文提到Activity与Fragment之间是存在依赖关系的,因此它们之间必然会涉及到通信问题,解决通信问题必然会涉及到对象之间的引用。因为Fragment的出现有一个重要的使命就是:模块化,从而提高复用性。若达到此效果,Fragment必须做到高内聚,低耦合。

现在大家动动脚趾都能想到的解决它们之间通信的方案有:handler,广播,EvnetBus,接口等(或许还有别的方案,请大家多多分享),那我们就聊下这些方案。

handler方案:

先上代码

public class MainActivity extends FragmentActivity{

//声明一个Handler

public Handler mHandler = new Handler(){

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

...相应的处理代码

}

}

...相应的处理代码

}

public class MainFragment extends Fragment{

//保存Activity传递的handler

private Handler mHandler;

@Override

public void onAttach(Activity activity) {

super.onAttach(activity);

//这个地方已经产生了耦合,若还有其他的activity,这个地方就得修改

if(activity instance MainActivity){

mHandler = ((MainActivity)activity).mHandler;

}

}

...相应的处理代码

}

该方案存在的缺点:

Fragment对具体的Activity存在耦合,不利于Fragment复用

不利于维护,若想删除相应的Activity,Fragment也得改动

没法获取Activity的返回数据

handler的使用个人感觉就很不爽(不知大家是否有同感)

广播方案:

具体的代码就不写了,说下该方案的缺点:

用广播解决此问题有点大材小用了,个人感觉广播的意图是用在一对多,接收广播者是未知的情况

广播性能肯定会差(不要和我说性能不是问题,对于手机来说性能是大问题)

传播数据有限制(必须得实现序列化接口才可以)

暂时就想到这些缺点,其他的缺点请大家集思广益下吧。

EventBus方案:

具体的EventBus的使用可以自己搜索下,个人对该方案的看法:

EventBus是用反射机制实现的,性能上会有问题(不要和我说性能不是问题,对于手机来说性能是大问题)

EventBus难于维护代码

没法获取Activity的返回数据

接口方案

我想这种方案是大家最易想到,使用最多的一种方案吧,具体上代码:

//MainActivity实现MainFragment开放的接口

public class MainActivity extends FragmentActivity implements FragmentListener{

@override

public void toH5Page(){ }

...其他处理代码省略

}

public class MainFragment extends Fragment{

public FragmentListener mListener;

//MainFragment开放的接口

public static interface FragmentListener{

//跳到h5页面

void toH5Page();

}

@Override

public void onAttach(Activity activity) {

super.onAttach(activity);

//对传递进来的Activity进行接口转换

if(activity instance FragmentListener){

mListener = ((FragmentListener)activity);

}

}

...其他处理代码省略

}

这种方案应该是既能达到复用,又能达到很好的可维护性,并且性能也是杠杠的。但是唯一的一个遗憾是假如项目很大了,Activity与Fragment的数量也会增加,这时候为每对Activity与Fragment交互定义交互接口就是一个很头疼的问题(包括为接口的命名,新定义的接口相应的Activity还得实现,相应的Fragment还得进行强制转换)。 想看更好的解决方案请看下面章节。

大招来也

设计模式里经常提到的一个概念就是封装变化,同时受javascript中的函数的参数可以是函数对象的启发下,我有了下面的想法,先上代码:代码地址

/** * + Created by niuxiaowei on 2016/1/20.

* 各种方法集合的类,可以把一个方法类以key-value的形式放入本类,

* 可以通过key值来调用相应的方法 */

public class Functions {

//带参数方法的集合,key值为方法的名字

private HashMap mFunctionWithParam ;

//无参数无返回值的方法集合,同理key值为方法名字

private HashMap mFunctionNoParamAndResult ;

/** * 基础方法类 */

public static abstract class Function{

//方法的名字,用来做调用,也可以理解为方法的指针

public String mFunctionName;

public Function(String functionName){

this.mFunctionName = functionName;

}

}

/** * 带有参数没有返回值的方法

* @param 参数 */

public static abstract class FunctionWithParam extends Function{

public FunctionWithParam(String functionName) {

super(functionName);

}

public abstract void function(Param param);

}

/** * 没有参数和返回值的方法 */

public static abstract class FunctionNoParamAndResult extends Function{

public FunctionNoParamAndResult(String functionName) {

super(functionName);

}

public abstract void function();

}

/** * 添加带参数的函数

* @param function {@link com.niu.myapp.myapp.view.util.Functions.FunctionWithParam}

* @return */

public Functions addFunction(FunctionWithParam function){

if(function == null){

return this;

}

if(mFunctionWithParam == null){

mFunctionWithParam = new HashMap<>(1);

}

mFunctionWithParam.put(function.mFunctionName,function);

return this;

}

/** * 添加带返回值的函数

* @param function {@link com.niu.myapp.myapp.view.util.Functions.FunctionWithResult}

* @return */

public Functions addFunction(FunctionNoParamAndResult function){

if(function == null){ return this; }

if(mFunctionNoParamAndResult == null){

mFunctionNoParamAndResult = new HashMap<>(1);

}

mFunctionNoParamAndResult.put(function.mFunctionName,function);

return this;

}

/** * 根据函数名,回调无参无返回值的函数

* @param funcName */

public void invokeFunc(String funcName) throws FunctionException {

FunctionNoParamAndResult f = null;

if(mFunctionNoParamAndResult != null){

f = mFunctionNoParamAndResult.get(funcName);

if(f != null){ f.function(); }

}

if(f == null){ throw new FunctionException("没有此函数"); }

}

/** * 调用具有参数的函数

* @param funcName

* @param param

* @param */

public void invokeFunc(String funcName,Param param)throws FunctionException{

FunctionWithParam f = null;

if(mFunctionWithParam != null){

f = mFunctionWithParam.get(funcName);

if(f != null){ f.function(param); }

}

}

}

设计思路:

1. 用一个类来模拟Javascript中的一个Function

Function就是此类,它是一个基类,每个Functioon实例都有一个mFuncName 既然是方法(或者函数)它就有有参数和无参数之分

FunctionWithParam是Function的子类,代表有参数的方法类,方法参数通过泛型解决

FunctionNoParamAndResult是Function的子类,代表无参无返回值的方法类

2. 一个可以存放多个方法(或者函数)的类

Functions类就是此类,下面简单介绍下Functions有4个主要方法:

addFunction(FunctionNoParamAndResult function) 添加一个无参无返回值的方法类

addFunction(FunctionWithParam function) 添加一个有参无返回值的方法类

invokeFunc(String funcName) 根据funcName调用一个方法

invokeFunc(String funcName,Param param) 根据funcName调用有参无返回值的方法类

使用举例:代码地址

每个app都有的基础activity(BaseActivity)

public abstract class BaseActivity extends FragmentActivity {

/**

* 为fragment设置functions,具体实现子类来做

* @param fragmentId */

public void setFunctionsForFragment(

int fragmentId){

}

}

其中的一个activity:

public class MainActivity extends BaseActivity {

@Override public void setFunctionsForFragment(int fragmentId) {

super.setFunctionsForFragment(fragmentId);

switch (fragmentId) {

case R.id.fragment_main:

FragmentManager fm = getSupportFragmentManager();

BaseFragment fragment = (BaseFragment) fm.findFragmentById(fragmentId);

//开始添加functions

fragment.setFunctions(new Functions()

.addFunction(new Functions.FunctionNoParamAndResult(MainFragment.FUNCTION_NO_PARAM_NO_RESULT) {

@Override

public void function() {

Toast.makeText(MainActivity.this, "成功调用无参无返回值方法", Toast.LENGTH_LONG).show();

}

}).

addFunction(new Functions.FunctionWithParam(MainFragment.FUNCTION_HAS_PARAM_NO_RESULT) {

@Override

public void function(Integer o) {

Toast.makeText(MainActivity.this, "成功调用有参无返回值方法 参数值=" + o, Toast.LENGTH_LONG).show(); } }));

}

}

}

每个app都会有的基础fragment(BaseFragment)

public abstract class BaseFragment extends Fragment {

protected BaseActivity mBaseActivity;

/** * 函数的集合 */

protected Functions mFunctions;

/** * activity调用此方法进行设置Functions

* @param functions */

public void setFunctions(Functions functions){

this.mFunctions = functions;

}

@Override

public void onAttach(Activity activity) {

super.onAttach(activity);

//呼叫activity进行回调方法的设置

if(activity instanceof BaseActivity){

mBaseActivity = (BaseActivity)activity;

mBaseActivity.setFunctionsForFragment(getId());

}

}

}

MainActivity对应的MainFragment

public class MainFragment extends BaseFragment {

/** * 没有参数没有返回值的函数 */

public static final String FUNCTION_NO_PARAM_NO_RESULT = "FUNCTION_NO_PARAM_NO_RESULT";

/** * 有参数没有返回值的函数 */

public static final String FUNCTION_HAS_PARAM_NO_RESULT = "FUNCTION_HAS_PARAM_NO_RESULT";

@Override

public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);

mBut1 = (Button) getView().findViewById(R.id.click1);

mBut3 = (Button) getView().findViewById(R.id.click3);

mBut1.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

try {

//调用无参无返回值的方法

mFunctions.invokeFunc(

FUNCTION_NO_PARAM_NO_RESULT);

} catch (FunctionException e) {

e.printStackTrace();

}

}

});

mBut3.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

try {

//调用有参无返回值的方法

mFunctions.invokeFunc(

FUNCTION_HAS_PARAM_NO_RESULT, 100);

} catch (FunctionException e) {

e.printStackTrace(); }

}

});

}

看到这您是不是觉得已经结束了,当然是没有了,因为还有2个问题没解决。方法返回值和方法接收多个参数的问题。

方法返回值的问题

上代码:代码地址

/** * 有返回值,没有参数的方法

* @param */

public static abstract class FunctionWithResult extends Function{

public FunctionWithResult(String functionName) {

super(functionName);

}

public abstract Result function();

}

/** * 带有参数和返回值的 方法

* @param

* @param */

public static abstract class FunctionWithParamAndResult extends Function{

public FunctionWithParamAndResult(String functionName) {

super(functionName);

}

public abstract Result function(Param data);

}

FunctionWithResult无参数有返回值的方法类

FunctionWithParamAndResult 有参数也有返回值的方法类

在Functions类中定义添加和调用这2种方法类的 相应方法。

其次是方法含有多个参数的问题

在解决此问题时我想了很多办法(比如怎样引入多个泛型,但最终以失败告终,希望有看了这篇文章的朋友可以多提下宝贵意见)。然后我就想到了用Bundle来解决多参数的问题,把多个参数放到Bundle中,但是在往Bundle中塞入数据时得有一个对应的key值,生成key值以及记住key值(记住key值是为了从Bundle中取数据)是一个繁琐的事。同时Bundle不能传递非序列化对象。所以就封装了一个FunctionParams类解决以上问题,请看类的实现: 代码地址

/** * 函数的参数,当函数的参数涉及到多个值时,可以用此类,

* 此类使用规则:存参数与取参数的顺序必须一致,

* 比如存参数顺序是new

*FunctionParamsBuilder().putString("a").putString("b").putInt(100);

*取的顺序也是: functionParams.getString(),

*functionParams.getString(), functionParams.getInt(); */

public static class FunctionParams {

private Bundle mParams = new Bundle(1);

private int mIndex = -1;

private Map mObjectParams = new HashMap(1);

FunctionParams(Bundle mParams,Map mObjectParams){

this.mParams = mParams;

this.mObjectParams = mObjectParams;

}

public Param getObject(Class p){

if(mObjectParams == null){ return null; }

return p.cast(mObjectParams.get((mIndex++) + "")); }

/** * 获取int值

* @return */

public int getInt(){

if(mParams != null){

return mParams.getInt((mIndex++) + ""); } return 0;

}

/** * 获取int值

* @param defalut

* @return */

public int getInt(int defalut){

if(mParams != null){

return mParams.getInt((mIndex++) + "");

}

return defalut;

}

/** * 获取字符串

* @param defalut * @return */

public String getString(String defalut){

if(mParams != null){

return mParams.getString((mIndex++) + "");

}

return defalut;

}

/** * 获取字符串 * @return */

public String getString(){

if(mParams != null){

return mParams.getString((mIndex++) + "");

} return null;

}

/** * 获取Boolean值

* @return 默认返回false */

public boolean getBoolean(){

if(mParams != null){

return mParams.getBoolean((mIndex++) + "");

} return false;

}

/** * 该类用来创建函数参数 */

public static class FunctionParamsBuilder{

private Bundle mParams ;

private int mIndex = -1;

private Map mObjectParams = new HashMap(1);

public FunctionParamsBuilder(){ }

public FunctionParamsBuilder putInt(int value){

if(mParams == null){

mParams = new Bundle(2);

}

mParams.putInt((mIndex++) + "", value);

return this;

}

public FunctionParamsBuilder putString(String value){

if(mParams == null){

mParams = new Bundle(2);

}

mParams.putString((mIndex++) + "", value);

return this;

}

public FunctionParamsBuilder putBoolean(boolean value){

if(mParams == null){ mParams = new Bundle(2); }

mParams.putBoolean((mIndex++) + "", value);

return this;

}

public FunctionParamsBuilder putObject(Object value){

if(mObjectParams == null){

mObjectParams = new HashMap(1);

}

mObjectParams.put((mIndex++) + "", value);

return this;

}

public FunctionParams create(){

FunctionParams instance = new FunctionParams(mParams,mObjectParams); return instance;

}

}

}

FunctionParams封装了取参数的功能,比如:

public Param getObject(Class p){

if(mObjectParams == null){ return null; }

return p.cast(mObjectParams.get((mIndex++) + ""));

}

取对象参数的功能,不需要传人key值,只需要传人需要即将取出来的类的Class实例即可

FunctionParamsBuilder类,看它的名字就知道是用了设计模式里的Builder(构建)模式。该类是用来存放参数的,当所有的参数都存放完毕后调用create()方法创建一个FunctionParams对象事物都是有两面性的,有缺点就有优点,只不过是在某些场合下优点大于缺点,还是反之。

FunctionParams解决了以上提到的Bundle传递多参数种种不便的问题,但同时FunctionParams也有一个缺点就是存参数的顺序与取参数的顺序一定要一致,比如:

//存的顺序 new

FunctionParamsBuilder().putString("1").putInt(2)

.putBoolean(true).create();

//取的顺序

functionParams.getString();

functionParams.getInt();

functionParams.getBoolean();

但是这种缺点函数的定义来看也不是缺点。

Activity与Fragment之间的通信是通过Functions的,即把变化的部分封装在Functions是类中,Functions起一个桥梁作用。

此方案优点:

Fragment与Activity的耦合性几乎没有

性能也好(没用反射)

可以从Activity获取返回数据

扩展性好(新增加的成对的Activity与Fragment之间的通信只需做以下几步:

1.新增加Activity只需要覆盖BaseActivity中的 setFunctionsForFragment(int fragmentId) 方法,把相应的回调函数加入。

2.相应的Fragment定义函数key值即可)

总结

简单总结为以下几点:

Fragment的使命

Activity与Fragment之间通信的解决方案(handler,广播,EventBus,接口)的优缺点。

我自己关于Activity与Fragment之间通信的解决方案(Functions),其实解决的主要是Fragment调用Activity的方案。

希望大家能多提宝贵意见,多交流。代码地址

本人微信:704451290

1b824e26105b

本人公众账号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363713.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分布式人工智能标记语言(DAIML)示例

DAIML&#xff08;Distributed Artificial Intelligence Markup Language&#xff09;是用于分布式人工智能系统中智能语言的标记库。DAIML主要分为Pattern和Template两部分&#xff0c;Pattern用于模式匹配&#xff0c;Template用于回答模板&#xff0c;下面将分别介绍两者的示…

Ext.js数据展示问题name展示code

出现以上问题是因为model中定义的类型跟数据库不匹配 去掉js中vehicleModel的type或者改为type:int即可。转载于:https://www.cnblogs.com/feifeicui/p/10438900.html

Solr中的前缀和后缀匹配

搜索引擎都是关于查找字符串的。 用户输入一个查询词&#xff0c;然后从反向索引中检索它。 有时&#xff0c;用户正在寻找的值只是索引中值的子字符串&#xff0c;并且用户可能也对这些匹配感兴趣。 对于德语这样的包含复合词&#xff08;例如Semmelkndel&#xff09;的语言&a…

使用FormData进行Ajax请求上传文件

Servlet3.0开始提供了一系列的注解来配置Servlet、Filter、Listener等等。这种方式可以极大的简化在开发中大量的xml的配置。从这个版本开始&#xff0c;web.xml可以不再需要&#xff0c;使用相关的注解同样可以完成相应的配置。 我笔记里也有记文件上传&#xff1a;https://w…

基于 jq 实现拖拽上传 APK 文件,js解析 APK 信息

技术栈 jquery文件上传&#xff1a;jquery.fileupload&#xff0c;github 文档apk 文件解析&#xff1a;app-info-parser&#xff0c;github 文档参考&#xff1a;前端解析ipa、apk安装包信息 —— app-info-parser 支持功能 点击或拖拽上传 apk 文件校验文件类型及文件大小js …

调试以了解终结器

这篇文章涵盖了Java内置概念之一&#xff0c;称为Finalizer 。 这个概念实际上是众所周知的&#xff0c;也是众所周知的&#xff0c;这取决于您是否有足够的时间来仔细研究一下java.lang.Object类。 就在java.lang.Object本身中&#xff0c;有一个名为finalize&#xff08;&…

Zookeeper实现注册与发现

1.Zookeeper的数据模型 (1) Zookeeper的数据模型&#xff0c;类似于树形结构&#xff1a; (2) Zookeeper的每一个节点成为称为Znode&#xff0c;主要用来存储数据。 data : 存储数据信息。acl : 记录Znode的访问权限。child : 当前节点的子节点引用。stat &#xff1a;包含Zn…

class 命名规范

本文是从简书复制的, markdown语法可能有些出入, 想看"正版"和更多内容请关注 简书: 小贤笔记 注: 文章摘自 penggelies07- 简书, super晴天 - CSDN 常见class关键词 布局类&#xff1a;header, footer, container, main, content, aside, page, section 包裹类&am…

web策略类游戏开发(四)一个可以承载万人在线的架构

web策略类游戏开发(四)一个可以承载万人在线的架构 Webgame现在已经开始需要进入大统一服务器时代&#xff0c;每个游戏区域容纳的玩家数量将从现在的几万人发展到几十万人&#xff0c;因此在新的背景下&#xff0c;webgame如何处理大量用户的请求将成为问题。目前一台asp.net做…

复制物料时不复制安全库存

1.打开bos&#xff0c;选择物料-功能控制 2.把允许复制去掉 转载于:https://www.cnblogs.com/RogerLu/p/10441588.html

CSS实现水平垂直居中

1、需求分析 子元素在父元素中水平垂直居中 2、技术分析 基础的css、html 3、详细分析 如图: 3.1 HTML部分 如图所示&#xff0c;大边框内包含一个小边框两部分&#xff0c;设置一个父元素div和一个子元素div。 <div class"container">父元素<div class…

从Java连接到Cassandra

在我的帖子Hello Cassandra中 &#xff0c;我研究了如何下载Cassandra NoSQL数据库并使用cqlsh连接到Cassandra数据库。 在本文中&#xff0c;我将介绍从Java客户端连接到Cassandra数据库的基础知识。 尽管有几种可用于从Java访问Cassandra数据库的 框架 &#xff0c;但我将在…

Django---Model操作

一、字段 1 AutoField(Field)2 - int自增列&#xff0c;必须填入参数 primary_keyTrue3 4 BigAutoField(AutoField)5 - bigint自增列&#xff0c;必须填入参数 primary_keyTrue6 7 注&#xff1a;当model中如果没有自增列&#xff0c;则自动会创建…

Vuex的第一次接触

前言&#xff1a;最近在做Vue实现去哪网&#xff0c;想要实现在城市列表页面&#xff0c;点击某个城市的时候&#xff0c;主页的头部的城市会随着改变&#xff0c;就是首页和城市页面有共用的数据要分享&#xff0c;这里使用Vuex 1. Vuex是什么&#xff1f; 是Vue官方推荐的数…

java IO流小结

Java流操作有关的类或接口&#xff1a; Java流类图结构&#xff1a; 流的概念和作用 流是一组有顺序的&#xff0c;有起点和终点的字节集合&#xff0c;是对数据传输的总称或抽象。即数据在两设备间的传输称为流&#xff0c;流的本质是数据传输&#xff0c;根据数据传输特性将流…

华为android是什么型号,华为手机机型众多,目前这几款最值得入手

华为手机机型众多&#xff0c;目前这几款最值得入手2020-09-22 15:00:033点赞0收藏0评论华为手机可以说是国家手机的代名词。受某种感情的影响&#xff0c;很多人都用华为取代了iPhone。为了表达感情&#xff0c;很多人也纷纷效仿&#xff0c;购买华为手机。但我想说的是支持华…

pt-online-schema-change VS oak-online-alter-table【转】

前言 在上篇文章中提到了MySQL 5.6 Online DDL&#xff0c;如果是MySQL 5.5的版本在DDL方面是要付出代价的&#xff0c;虽然已经有了Fast index Creation&#xff0c;但是在添加字段还是会锁表的&#xff0c;而且在添加删除辅助索引是会加S锁&#xff0c;也就是无法进行写操作。…

vue命令行错误处理

全局安装vue/cli时&#xff1a;npm install -g vue/cli &#xff08;1&#xff09;Error: EACCES: permission denied, access /usr/local/lib/node_modules/vue/cli 原因: 执行命令时没有获得管理员权限 解决办法: 在命令前面加上sudo即可.然后输入电脑的管理员密码操作即可…

RAC(ReactiveCocoa)介绍(一)

最近在学习RAC&#xff0c;之前在iOS工作中&#xff0c;类之间的传值&#xff0c;无非是block、delegate代理、KVO和Notification等这几种方法。在RAC中&#xff0c;同样具备替代block、delegate代理、KVO和Notification&#xff0c;UI target、定时器timer、数据结构等各种方式…

一段简单的html 5 音频,5个用于处理HTML5音频的库和API

在过去的几个月中&#xff0c;我遇到了许多不同的库&#xff0c;它们利用了相对较新的HTML5 Audio API以及更著名的HTML5 Audio Element及其更简单的API。我以为我会在本文中分享这些库中的一小部分&#xff0c;以向您展示如果选择创建需要操纵声音文件的游戏或应用程序&#x…