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,一经查实,立即删除!

相关文章

python学习笔记(python介绍)

为什么要学python&#xff1f; python和shell的比较&#xff0c;和PHP、和JAVA比较 运维开发只是用到python的很小一部分 python在一些知名公司的应用&#xff1a; 谷歌&#xff1a;python的创始人原来在谷歌工作。 CIA&#xff1a;美国中情局网站用python开发的 NASA&#xff…

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…

计算机语言

软件&#xff1a;是一系列按照特定顺序组织的计算机数据和指令的集合。一般来讲软件被划分为系统软件、应用软件和介于这两者之间的中间件。 系统软件 系统软件是各类操作系统&#xff0c;如windows、Linux、UNIX等&#xff0c;还包括操作系统的补丁程序及硬件驱动程序&#xf…

Apache Shiro第2部分–领域,数据库和PGP证书

这是致力于Apache Shiro的系列文章的第二部分。 我们从简单的不安全Web应用程序开始了上一部分 。 完成后&#xff0c;该应用程序具有基本的身份验证和授权。 用户可以登录和注销。 所有网页和按钮均已分配和实施访问权限。 授权和身份验证数据都已存储在静态配置文件中。 正如…

js中变量作用域的小理解

一&#xff1a;变量作用域 在js代码中每个变量都是有自己的作用域的&#xff0c;js中不像C语言有块级作用域的概念&#xff0c;取而代之的是函数作用域&#xff0c;看如下代码&#xff1a; var scope"global"; function init(){ alert(scope);var scope "local…

安卓linux开机画面,Android系统的开机画面显示过程分析(1)

好几个月都没有更新过博客了&#xff0c;从今天开始&#xff0c;老罗将尝试对Android系统的UI实现作一个系统的分析&#xff0c;也算是落实之前所作出的承诺。提到Android系统的UI&#xff0c;我们最先接触到的便是系统在启动过程中所出现的画面了。Android系统在启动的过程中&…

如果你的NavigationDrawer里面的Item没有响应,Drawer不能左滑关闭

如果你的NavigationDrawer里面的Item没有响应&#xff0c;Drawer不能左滑关闭&#xff0c;应该是因为你没有把主要内容放在DrawerLayout标签下的第一位。 The main content view (the FrameLayout above) must be the first child in the DrawerLayout because the XML order i…

JAXB和未映射的属性

JAXB&#xff08;JSR-222&#xff09;是例外配置&#xff0c;这意味着存在默认映射应用于域对象。 这意味着有时您需要显式排除字段/属性。 在本文中&#xff0c;我将讨论如何使用XmlTransient或XmlAccessorType&#xff08;XmlAccessType.NONE&#xff09;以及何时使用每个选项…

sublime text3 使用SVN插件

Simon在项目中经常使用SVN&#xff0c;每次都要切换提交&#xff0c;很麻烦&#xff0c;有了这个SVN插件就很方便了&#xff0c;使用快捷方式提交&#xff0c;更新。 安装: Ctrl Shift P 调用出Sublime Text的包管理工具&#xff0c;输入TortoiseSVN&#xff0c;回车进行安装…

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

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

二维数组实现八皇后问题

之前关八皇后的问题全部使用的是一维数组进行实现(http://www.cnblogs.com/SeaSky0606/p/4604955.html)&#xff0c;现改一种数据存储方式&#xff0c;按照8x8的二维棋盘存储皇后。基本逻辑不变&#xff0c;可参见如下代码&#xff1a; #include<cstdio> #include<alg…

Java的深度:通过协方差暴露的API泄漏

Java有时可能非常棘手&#xff0c;特别是在API设计中。 让我们看一个非常有趣的展示柜。 jOOQ强烈地将API与实现分开。 所有API都在org.jooq包中&#xff0c;并且是公共的。 大多数实现都在org.jooq.impl包和package-private中。 只有工厂和一些专用的基础实现是公开的。 这允许…

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机架服务器的所有产品…

为什么在Java 6上Math.round(0.499999999999999917)舍入为1

总览 错误表示错误和算术舍入错误有两种类型&#xff0c;它们在浮点计算中很常见。 在此简单示例中&#xff0c;这两个错误组合在一起&#xff0c;在Java 6中Math.round&#xff08;0.4999999999999999999917&#xff09;舍入为1。 表示错误 浮点数是以2为底的格式&#xff0c…

单利模式

class Singleton{ public:static Singleton* GetInstance(){if (m_pInstance nullptr){m_pInstance new Singleton;}return m_pInstance;} private:Singleton(){}//需要将构造和析构定义成私有的防止外界构造和析构~Singleton(){}static Singleton* m_pInstance;//static所有…

C语言switch中break的作用,C语言中switch...case语句中break的重要性

在C语言中switch...case语句是经常用到的&#xff0c;下面我介绍一下在使用该语句时候需要注意的一个细节问题。话不多说&#xff0c;直接举例子&#xff1a;例子1&#xff1a;switch(fruit){case 1:printf("apple"); break;case 2:printf("banana"); brea…

BZOJ 1898: [Zjoi2005]Swamp 沼泽鳄鱼 [矩阵乘法]

1898: [Zjoi2005]Swamp 沼泽鳄鱼 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1082 Solved: 602[Submit][Status][Discuss]Description 潘塔纳尔沼泽地号称世界上最大的一块湿地&#xff0c;它地位于巴西中部马托格罗索州的南部地区。每当雨季来临&#xff0c;这里碧波荡漾…