Android的IPC机制(一)——AIDL的使用

综述

  IPC(interprocess communication)是指进程间通信,也就是在两个进程间进行数据交互。不同的操作系统都有他们自己的一套IPC机制。例如在Linux操作系统中可以通过管道、信号量、消息队列、内存共享、套接字等进行进程间通信。那么在Android系统中我们可以通过Binder来进行进程间的通信。当然除了Binder我们还可以使用Socket来进行进程间的通信。 
  既然需要进程通信,那么就必须有多个进程。当然,在两个应用交互中必然出现多进程的情况。若是在一个应用中呢?我们可以通过给四大组件在AndroidMenifest中为他们指定android:process属性来实现不同的组件在不同进程中运行。下面就来介绍一下Android中进程间通信的实现方式。

AIDL简介

  AIDL是 Android Interface Definition Language的缩写。AIDL 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行 IPC的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数。 
  AIDL IPC机制是面向接口的,像COM或Corba一样,但是更加轻量级。它是使用代理类在客户端和实现端传递数据。

AIDL用法

  首先我们创建一个AIDL文件,在AndroidStudio中当我们创建一个AIDL文件时会自动为我们创件一个AILD文件夹,用于存放AIDL文件。创建完之后重新rebuild会自动生成aidl实现类。 
  这里写图片描述 
  在下面的例子当中,我们将Service单独作为一个应用在系统中运行,在另一个用于访问Service的client也单独作为一个应用运行在系统中。这样保证了两个程序分别运行在两个进程中。并且使用了butterknife进行控件绑定。

AIDL简单用法

演示

  在Service中我们对客户端传来的两个整数做了一次加法运算并返回到客户端中。 
这里写图片描述 
  

AIDL代码

// ICalculate.aidl
package com.ljd.aidl;// Declare any non-default types here with import statementsinterface ICalculate {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/int add(int first, int second); }

服务端代码

package com.ljd.aidl.service;import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder; import android.os.RemoteException; import com.ljd.aidl.ICalculate; public class CalculateService extends Service { public CalculateService() { } private Binder mBinder = new ICalculate.Stub(){ @Override public int add(int first, int second) throws RemoteException { return first + second; } }; @Override public IBinder onBind(Intent intent) { return mBinder; } }

客户端代码

package com.ljd.aidl.activity;import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Toast; import com.ljd.aidl.ICalculate; import com.ljd.aidl.client.R; import butterknife.ButterKnife; import butterknife.OnClick; public class Demo1Activity extends AppCompatActivity { private final String TAG = "DEMO1"; //是否已经绑定service private boolean mIsBindService; private ICalculate mCalculate; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG,"bind success"); Toast.makeText(Demo1Activity.this,"bind service success",Toast.LENGTH_SHORT).show(); mCalculate = ICalculate.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { //重新绑定Service防止系统将服务进程杀死而产生的调用错误。 bindService(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_demo1); ButterKnife.bind(this); mIsBindService = false; } @Override protected void onDestroy() { unbindService(); ButterKnife.unbind(this); super.onDestroy(); } @OnClick({ R.id.bind_demo1_btn,R.id.unbind_demo1_btn,R.id.calculate_btn}) public void onClickButton(View v) { switch (v.getId()){ case R.id.bind_demo1_btn: bindService(); break; case R.id.unbind_demo1_btn: Toast.makeText(this,"unbind service success",Toast.LENGTH_SHORT).show(); unbindService(); break; case R.id.calculate_btn: if (mIsBindService && mCalculate != null ){ try { int result = mCalculate.add(2,4); Log.d(TAG,String.valueOf(result)); Toast.makeText(this,String.valueOf(result),Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { e.printStackTrace(); } } else { Toast.makeText(this,"not bind service",Toast.LENGTH_SHORT).show(); } break; } } private void bindService(){ Intent intent = new Intent(); intent.setAction("com.ljd.aidl.action.CALCULATE_SERVICE"); bindService(intent,mConnection, Context.BIND_AUTO_CREATE); mIsBindService = true; } private void unbindService(){ if(mIsBindService){ mIsBindService = false; unbindService(mConnection); } } }

AIDL高级用法

  对于上面的例子,在AIDL接口中只是使用了一些Java的基本类型,对于AIDL文件并不是所有的类型都是可用的,那么在AIDL中究竟有哪些类型可以使用呢?

AIDL语法规则

默认情况下AIDL支持以下数据类型:

  • 所有Java的基本数据类型(例如: int, long,double, char, boolean等)
  • String和CharSequence
  • List:AIDL实际接收到的是ArrayList,并且List里面所有元素都必须被AIDL支持
  • Map: AIDL实际接收到的是HashMap,并且Map里面所有元素都必须被AIDL支持

如果不是上面所述类型,我们必须要显示import进来,即使他们在同一个包中。当我们使用自定义的对象时必须实现Parcelable接口,Parcelable为对象序列化接口,效率比实现Serializable接口高。并且新建一个与该类同名的AIDL文件,声明他为Parcelable类型。

我们定义AIDL接口还需要注意以下几点:

  • 方法可以有多个或没有参数,可以有返回值也可以为void
  • 在参数中,除了基本类型以外,我们必须为参数标上方向in, out, 或者 inout
  • 在AIDL文件中只支持方法,不支持静态常量

演示

  在计算机商店中需要采购笔记本进行销售,在服务端中我们添加两台笔记本,在客户端中我们为商店加购一台dell笔记本。 
这里写图片描述 
  

实体类代码

  我们首先构建一个计算机实体类,包含笔记本的id,品牌,型号,并且实现Parcelable接口,在AndroidStudio中会为我们自动构造代码。 
  

package com.ljd.aidl.entity;import android.os.Parcel;
import android.os.Parcelable;public class ComputerEntity implements Parcelable{ public int computerId; //id public String brand; //品牌 public String model; //型号 public ComputerEntity(int computerId, String brand, String model) { this.brand = brand; this.computerId = computerId; this.model = model; } protected ComputerEntity(Parcel in) { computerId = in.readInt(); brand = in.readString(); model = in.readString(); } public static final Creator<ComputerEntity> CREATOR = new Creator<ComputerEntity>() { @Override public ComputerEntity createFromParcel(Parcel in) { return new ComputerEntity(in); } @Override public ComputerEntity[] newArray(int size) { return new ComputerEntity[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(computerId); dest.writeString(brand); dest.writeString(model); } }

AIDL代码

  在AIDL中对实体类进行声明,包名和文件名必须与实体类一致。在AndroidStudio中新建一个与实体类同名的AIDL文件会报错,需要先用一个其它名字,然后修改与实体类名一致即可。

package com.ljd.aidl.entity; //包名必须和对用实体类的包名一致 // Declare any non-default types here with import statements parcelable ComputerEntity;

  添加两个接口分别为添加一台笔记本和获取全部笔记本,在该文件中使用到了ComputerEntity类,显示的import进来。

package com.ljd.aidl;import com.ljd.aidl.entity.ComputerEntity;
// Declare any non-default types here with import statementsinterface IComputerManager {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void addComputer(in ComputerEntity computer); List<ComputerEntity> getComputerList(); }

服务端代码

package com.ljd.aidl.service;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException; import com.ljd.aidl.IComputerManager; import com.ljd.aidl.entity.ComputerEntity; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class ComputerService extends Service { private CopyOnWriteArrayList<ComputerEntity> mComputerList = new CopyOnWriteArrayList<>(); public ComputerService() { } private final IComputerManager.Stub mBinder = new IComputerManager.Stub() { @Override public void addComputer(ComputerEntity computer) throws RemoteException { mComputerList.add(computer); } @Override public List<ComputerEntity> getComputerList() throws RemoteException { return mComputerList; } }; @Override public void onCreate() { super.onCreate(); mComputerList.add(new ComputerEntity(0,"apple","macbookpro")); mComputerList.add(new ComputerEntity(1,"microsoft","surfacebook")); mComputerList.add(new ComputerEntity(2,"dell","XPS13")); } @Override public IBinder onBind(Intent intent) { return mBinder; } }

  注意:在该类中使用了CopyOnWriteArrayList,CopyOnWriteArrayList能够自动进行线程同步。可是在AIDL中接收和返回的只能是ArrayList,其实AIDL支持的是抽象的List,在Binder中会按照List访问数据并最终形成一个ArrayList,所以在AIDL中返回的还是一个ArrayList。

客户端代码

package com.ljd.aidl.activity;import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.ljd.aidl.IComputerManager; import com.ljd.aidl.client.R; import com.ljd.aidl.entity.ComputerEntity; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; public class Demo2Activity extends AppCompatActivity{ @Bind(R.id.show_linear) LinearLayout mShowLinear; private boolean mIsBindService; private IComputerManager mRemoteComputerManager; private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { if(mRemoteComputerManager != null){ mRemoteComputerManager.asBinder().unlinkToDeath(mDeathRecipient,0); mRemoteComputerManager = null; bindService(); } } }; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mIsBindService = true; Toast.makeText(Demo2Activity.this,"bind service success",Toast.LENGTH_SHORT).show(); mRemoteComputerManager = IComputerManager.Stub.asInterface(service); try { mRemoteComputerManager.asBinder().linkToDeath(mDeathRecipient,0); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mRemoteComputerManager = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_demo2); ButterKnife.bind(this); mIsBindService = false; } @Override protected void onDestroy() { unbindService(); ButterKnife.unbind(this); super.onDestroy(); } @OnClick({R.id.bind_demo2_btn,R.id.unbind_demo2_btn,R.id.test_demo2_btn,R.id.clear_demo2_btn}) public void onClickButton(View v) { switch (v.getId()){ case R.id.bind_demo2_btn: bindService(); break; case R.id.unbind_demo2_btn: Toast.makeText(this,"unbind service success",Toast.LENGTH_SHORT).show(); unbindService(); break; case R.id.test_demo2_btn: if (!mIsBindService || mRemoteComputerManager == null){ Toast.makeText(this,"not bind service",Toast.LENGTH_SHORT).show(); return; } try { List<ComputerEntity> computerList = mRemoteComputerManager.getComputerList(); for (int i =0;i<computerList.size();i++){ String str = "computerId:" + String.valueOf(computerList.get(i).computerId) + " brand:" + computerList.get(i).brand + " model:" + computerList.get(i).model ; TextView textView = new TextView(this); textView.setText(str); mShowLinear.addView(textView); } } catch (RemoteException e) { e.printStackTrace(); } break; case R.id.clear_demo2_btn: mShowLinear.removeAllViews(); break; } } private void bindService(){ Intent intent = new Intent(); intent.setAction("com.ljd.aidl.action.COMPUTER_SERVICE"); mIsBindService = bindService(intent,mConnection, Context.BIND_AUTO_CREATE); } private void unbindService(){ if(!mIsBindService){ return; } mIsBindService = false; unbindService(mConnection); } }

  由于Binder是有可能会意外死亡的,也就是Service所在进程被系统杀死,这时候我们调用Service的方法就会失败。在第一个例子中我们通过onServiceDisconnected方法中重新绑定服务。在这个例子中我们采用了另外一种方法,由于在Binder中提供了两个配对的方法linkToDeath和unlinkToDeath,通过linkToDeath可以给Binder设置一个死亡代理,Binder死亡时回调binderDied方法,在binderDied方法中我们重新绑定服务即可。

AIDL用法拓展

  当我们需要一种笔记本的时候,由于商店缺货,这时候我们会给卖家说一声,我所需要的这款笔记本到货后通知我。也就成了所谓的观察者模式。 
  在Android系统中为我们提供了一个RemoteCallbackList,RemoteCallbackList是系统专门用来删除跨进程的listener接口,并且在RemoteCallbackList中自动实现了线程同步功能,下面看一下它的用法。

演示

  客户端注册服务以后,服务端每隔三秒会添加一台笔记本,并通知给客户端显示。 
这里写图片描述

AIDL代码

  到货后的AIDL监听接口 
  

package com.ljd.aidl;import com.ljd.aidl.entity.ComputerEntity;
// Declare any non-default types here with import statementsinterface IOnComputerArrivedListener {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void onComputerArrived(in ComputerEntity computer); }

  在IComputerManager接口中添加两个方法。显示importIOnComputerArrivedListener ,即使在同一个包下面。 
  

// IComputerManagerObserver.aidl
package com.ljd.aidl;import com.ljd.aidl.entity.ComputerEntity;
import com.ljd.aidl.IOnComputerArrivedListener;
// Declare any non-default types here with import statements interface IComputerManagerObserver { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void addComputer(in ComputerEntity computer); List<ComputerEntity> getComputerList(); void registerUser(IOnComputerArrivedListener listener); void unRegisterUser(IOnComputerArrivedListener listener); }

服务端代码

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteCallbackList; import android.os.RemoteException; import com.ljd.aidl.IComputerManagerObserver; import com.ljd.aidl.IOnComputerArrivedListener; import com.ljd.aidl.entity.ComputerEntity; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; public class ComputerObserverService extends Service{ public ComputerObserverService() { } private CopyOnWriteArrayList<ComputerEntity> mComputerList = new CopyOnWriteArrayList<>(); private RemoteCallbackList<IOnComputerArrivedListener> mComputerArrivedListenerList = new RemoteCallbackList<>(); private AtomicBoolean mIsServiceDestroy = new AtomicBoolean(false); private Binder mBinder = new IComputerManagerObserver.Stub(){ @Override public void addComputer(ComputerEntity computer) throws RemoteException { mComputerList.add(computer); } @Override public List<ComputerEntity> getComputerList() throws RemoteException { return mComputerList; } @Override public void registerUser(IOnComputerArrivedListener listener) throws RemoteException { mComputerArrivedListenerList.register(listener); } @Override public void unRegisterUser(IOnComputerArrivedListener listener) throws RemoteException { mComputerArrivedListenerList.unregister(listener); } }; @Override public void onCreate() { super.onCreate(); mComputerList.add(new ComputerEntity(0,"apple","macbookpro")); mComputerList.add(new ComputerEntity(1,"microsoft","surfacebook")); mComputerList.add(new ComputerEntity(2,"dell","XPS13")); new Thread(new Runnable() { @Override public void run() { while (!mIsServiceDestroy.get()){ try { Thread.currentThread().sleep(3000); ComputerEntity computer = new ComputerEntity(mComputerList.size(),"******","******"); mComputerList.add(computer); final int COUNT = mComputerArrivedListenerList.beginBroadcast(); //通知所有注册过的用户 for (int i=0;i<COUNT;i++){ IOnComputerArrivedListener listener = mComputerArrivedListenerList.getBroadcastItem(i); if (listener != null){ listener.onComputerArrived(computer); } } mComputerArrivedListenerList.finishBroadcast(); } catch (InterruptedException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } } } }).start(); } @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onDestroy() { super.onDestroy(); mIsServiceDestroy.set(true); } }

  注意:RemoteCallbackList并不是一个List,所以我们不能像操作List一样操作RemoteCallbackList。并且遍历RemoteCallbackList时,beginBroadcast和finishBroadcast是配对使用的。

客户端代码


import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.ljd.aidl.IComputerManagerObserver; import com.ljd.aidl.IOnComputerArrivedListener; import com.ljd.aidl.client.R; import com.ljd.aidl.entity.ComputerEntity; import java.util.List; import butterknife.Bind; import butterknife.ButterKnife; import butterknife.OnClick; public class Demo3Activity extends AppCompatActivity { @Bind(R.id.show_demo3_linear) LinearLayout mShowLinear; private boolean mIsBindService; private static final int MESSAGE_COMPUTER_ARRIVED = 1; private IComputerManagerObserver mRemoteComputerManager; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what){ case MESSAGE_COMPUTER_ARRIVED: ComputerEntity computer = (ComputerEntity)msg.obj; String str = "computerId:" + String.valueOf(computer.computerId) + " brand:" + computer.brand + " model:" + computer.model ; TextView textView = new TextView(Demo3Activity.this); textView.setText(str); mShowLinear.addView(textView); break; default: super.handleMessage(msg); break; } } }; private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { if(mRemoteComputerManager != null){ mRemoteComputerManager.asBinder().unlinkToDeath(mDeathRecipient,0); mRemoteComputerManager = null; bindService(); } } }; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mIsBindService = true; Toast.makeText(Demo3Activity.this,"bind service success",Toast.LENGTH_SHORT).show(); mRemoteComputerManager = IComputerManagerObserver.Stub.asInterface(service); try { mRemoteComputerManager.asBinder().linkToDeath(mDeathRecipient,0); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mRemoteComputerManager = null; } }; private IOnComputerArrivedListener mOnComputerArrivedListener = new IOnComputerArrivedListener.Stub(){ @Override public void onComputerArrived(ComputerEntity computer) throws RemoteException { mHandler.obtainMessage(MESSAGE_COMPUTER_ARRIVED,computer).sendToTarget(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_demo3); ButterKnife.bind(this); mIsBindService = false; } @Override protected void onDestroy() { unbindService(); ButterKnife.unbind(this); super.onDestroy(); } @OnClick({R.id.bind_demo3_btn,R.id.unbind_demo3_btn,R.id.test_demo3_btn,R.id.clear_demo3_btn}) public void onClickButton(View v){ switch (v.getId()){ case R.id.bind_demo3_btn: bindService(); break; case R.id.unbind_demo3_btn: Toast.makeText(this,"unbind service success",Toast.LENGTH_SHORT).show(); unbindService(); break; case R.id.test_demo3_btn: if (!mIsBindService || mRemoteComputerManager == null){ Toast.makeText(this,"not bind service",Toast.LENGTH_SHORT).show(); return; } try { ComputerEntity computer = new ComputerEntity(3,"hp","envy13"); mRemoteComputerManager.addComputer(computer); List<ComputerEntity> computerList = mRemoteComputerManager.getComputerList(); for (int i =0;i<computerList.size();i++){ String str = "computerId:" + String.valueOf(computerList.get(i).computerId) + " brand:" + computerList.get(i).brand + " model:" + computerList.get(i).model ; TextView textView = new TextView(this); textView.setText(str); mShowLinear.addView(textView); } mRemoteComputerManager.registerUser(mOnComputerArrivedListener); } catch (RemoteException e) { e.printStackTrace(); } break; case R.id.clear_demo3_btn: mShowLinear.removeAllViews(); break; } } private void bindService(){ Intent intent = new Intent(); intent.setAction("com.ljd.aidl.action.COMPUTER_OBSERVER_SERVICE"); mIsBindService = bindService(intent,mConnection, Context.BIND_AUTO_CREATE); } private void unbindService(){ if(!mIsBindService){ return; } if (mRemoteComputerManager != null && mRemoteComputerManager.asBinder().isBinderAlive()){ try { mRemoteComputerManager.unRegisterUser(mOnComputerArrivedListener); } catch (RemoteException e) { e.printStackTrace(); } } unbindService(mConnection); mIsBindService = false; } }

源码下载

转载于:https://www.cnblogs.com/android-blogs/p/5443666.html

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

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

相关文章

Netty:透明地使用SPDY和HTTP

大多数人已经从谷歌那里听说过SPDY&#xff0c;该协议被提议作为老化的HTTP协议的替代品。 Web服务器是浏览器正在缓慢地实现该协议&#xff0c;并且支持正在增长。 在最近的文章中&#xff0c;我已经写过SPDY的工作方式以及如何在Jetty中启用SPDY支持。 由于Netty&#xff08;…

selenium 等待页面加载完成

一、隐形加载等待&#xff1a; file:///C:/Users/leixiaoj/Desktop/test.html 该页面负责创建一个div <html> <head><title>Set Timeout</title><style>.red_box {background-color: red; width 20%; height:100px; border: none;}</style&…

linux nfsnobody用户,处理CentOS 5.5 x64 配置NFS服务过程中nfsnobody用户造成的问题

4、我们编译一下这个NFS的配置文件。[rootNFS /]# vi /etc/exports/share 192.168.60.0/24(rw,sync,all_squash,root_squash) (我们允许这个共享对192.168.60.0/24网段可读可写&#xff0c;且将所有访问者包括root的身份都改为nfsnobody)[rootNFS /]# /etc/init.d/nfs resta…

c语言空格有什么作用,空格在c语言中怎么表示 C语言中的空格字符怎么表示

c语言中表示空格的是什么代码&#xff1f;分析如下&#xff1a; 不是所有字符都需要转义的&#xff0c;空格直接就敲空格&#xff0c;或者使用ASCII码值赋值为32。 空格没有转义字符。合法转义字符如下&#xff1a;\a 响铃(BEL) 、\b 退格(BS)、\f 换页(FF)、\n 换行(LF)、\r 回…

StringMVC 中如何做数据校验

步骤一&#xff1a;引入四个jar包 步骤二&#xff1a;注册类型转换器 <context:component-scan base-package"cn.happy.controller"></context:component-scan><!-- 配置验证器 --><bean id"myvalidator" class"org.springframe…

ibm+x3650+m4+linux+raid驱动,IBM X3650M4阵列卡驱动下载

ibm X3650M4raid阵列卡驱动适合安装windowsserver2008,windowsserver2008R2,系统问题&#xff0c;服务器问题&#xff0c;可以联系我们也可以到5分享论坛发帖求助。IBM System x3650 M4服务器是一款应用最为广泛的2U机架服务器&#xff0c;支持Xeon E5-2600机架服务器的所有产品…

UML类图与类的关系详解

在画类图的时候&#xff0c;理清类和类之间的关系是重点。类的关系有泛化(Generalization)、实现&#xff08;Realization&#xff09;、依赖(Dependency)和关联(Association)。其中关联又分为一般关联关系和聚合关系(Aggregation)&#xff0c;合成关系(Composition)。下面我们…

python之路-SQLAlchemy

SQLAchemy SQLAlchemy是Python编程语言下的一款ORM框架&#xff0c;该框架建立在数据库API之上&#xff0c;使用关系对象映射进行数据库操作&#xff0c;简言之便是&#xff1a;将对象转换成SQL&#xff0c;然后使用数据API执行SQL并获取执行结果。 安装&#xff1a; pip3 inst…

Linux中vim编辑器的缩进的功能键

vim编程时,经常需要对代码进行缩进处理,以增加程序的可读性和后期的代码维护. 可以采用多种方式达到缩进的目的: 1) 命令模式(command mode) 2) Visual模式&#xff08;visual mode&#xff09; 2) 输入模式(entry mode) 3) 末行模式(last-line mode) 4) 在/etc/vimrc有给予vim…

JSF 2,PrimeFaces 3,Spring 3和Hibernate 4集成项目

本文展示了如何集成JSF2&#xff0c;PrimeFaces3&#xff0c;Spring3和Hibernate4技术。 它为Java开发人员提供了一个通用的项目模板。 另外&#xff0c;如果Spring不用于业务和数据访问层&#xff0c;则可以提供JSF – PrimeFaces和Hibernate集成项目。 二手技术&#xff1a…

初识openstack

一、 什么是openstack&#xff1f; OpenStack是一个由NASA&#xff08;美国国家航空航天局&#xff09;和Rackspace合作研发并发起的&#xff0c;以Apache许可证授权的自由软件和开放源代码项目。 二、openstack前世今身 openstack是一个跟Eucalyptus,AWS(Amazon web Service)类…

Arquillian 1.0.0.Final正式发布! 准备使用GlassFish和WebLogic! 杀死所有虫子!

红帽公司和JBoss社区今天宣布的1.0.0.Final发布的Arquillian &#xff0c;其屡获殊荣的建在Java虚拟机&#xff08;JVM&#xff09;运行测试平台。 Arquillian大大减少了编写和执行Java中间件集成和功能测试所需的工作。 它甚至使测试工程师能够解决以前认为无法测试或测试成本…

qq五笔linux,QQ五笔 - 五笔小字典 QQ绑定很实用

九、 智能调频、空码检索、词序固定在QQ五笔中还有一些小亮点&#xff0c;比如它可以根据“最近输入”、“输入次数”对候选词排序。同时为了加快检索速度&#xff0c;默认只在常用字库(GB2312)中检索&#xff0c;只有出现空码后才会继续搜索容量更大的GBK字库&#xff0c;很好…

android 关闭蓝牙打电话功能,Android蓝牙开发【八】hfp接听、挂断电话

继续研究hfp相关功能。蓝牙耳机可以控制手机接听、拒接、挂断电话&#xff0c;拨打电话等功能。本文主要分析下起这些操作的大致流程。在系统应用Bluetooth中com_android_bluetooth.cpp提供了多个回调方法&#xff0c;由hardware、协议栈回调过来。蓝牙耳机的一些控制命令都会发…

将状态机模式实现为流处理器

在我的上一个博客中&#xff0c;我说我真的以为某些“四人行”&#xff08;GOF&#xff09;模式已经过时了&#xff0c;如果不是过时的话肯定不受欢迎。 特别是我说过StateMachine不是那么有用&#xff0c;因为您通常会想到另一种更简单的方式来执行您正在执行的事情&#xff0…

android 自定义actionbar,如何让android的actionbar浮动且透明

如上图所示&#xff0c;谷歌地图的actionbar是透明的&#xff0c;且浮动在整个布局之上&#xff0c;没有占用布局空间。其实要做到这样的效果&#xff0c;我们首先想到的是两个方面&#xff1a;1.将让actionbar浮动起来。2.给actionbar一个背景&#xff0c;可以为颜色也可以为图…

Ajax与CustomErrors的尴尬

在ASP.NET程序中&#xff0c;为了给用户显示友好的错误信息&#xff0c;通常在web.config中进行如下的设置&#xff1a; <customErrors mode"RemoteOnly" defaultRedirect"/error/error.htm"> </customErrors> 但如果是一个ajax请求在服务端发…

Java创建WebService服务及客户端实现

简介 WebService是一种服务的提供方式&#xff0c;通过WebService&#xff0c;不同应用间相互间调用变的很方便&#xff0c;网络上有很多常用的WebService服务&#xff0c;如&#xff1a;http://developer.51cto.com/art/200908/147125.htm&#xff0c;不同的语言平台对…

Java静态方法可能会产生代码异味

代码气味的定义 &#xff08;来自维基百科&#xff09;&#xff1a; “程序源代码中任何可能表明存在更深层问题的症状。” 在Java中&#xff0c; 静态方法允许您在“类范围”内执行代码&#xff0c;而不是像成员方法这样的实例范围。 这意味着&#xff0c;它们依赖于类级别的变…

Node Express4.x 片段视图 partials

1.在Express 4.x使用片段视图&#xff0c;需要引入partials模块 步骤&#xff1a; 1.在全局中安装express-partials模块&#xff1a; 2.在本地模块中安装express-partials,将模块安装到package.json中&#xff1a; 3.在入口文件(如&#xff1a;app.js)中引入模块&#xff1a; v…