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.pswp.cn/news/373154.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/373154.shtml
英文地址,請注明出處:http://en.pswp.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;這里碧波蕩漾…