Android中的跨进程通信方法实例及特点分析(一):AIDL Service
转载请注明出处:http://blog.csdn.net/bettarwang/article/details/40947481
近期有一个需求就是往程序中增加大数据的採集点,可是由于我们的Android程序包括两个进程,所以涉及到跨进程通信的问题。现将Android中的跨进程通信方式总结例如以下。
Android中有4种跨进程通信方式,各自是利用AIDL Service、ContentProvider、Broadcast、Activity实现。
1.利用AIDL Service实现跨进程通信
这是我个人比較推崇的方式,由于它相比Broadcast而言,尽管实现上略微麻烦了一点。可是它的优势就是不会像广播那样在手机中的广播较多时会有明显的时延,甚至有广播发送不成功的情况出现。
注意普通的Service并不能实现跨进程操作,实际上普通的Service和它所在的应用处于同一个进程中,并且它也不会专门开一条新的线程,因此假设在普通的Service中实如今耗时的任务,须要新开线程。
要实现跨进程通信,须要借助AIDL(Android Interface Definition Language)。Android中的跨进程服务事实上是採用C/S的架构。因而AIDL的目的就是实现通信接口。
首先举一个简单的栗子。
服务端代码例如以下:
首先是aidl的代码:
package com.android.service; interface IData
{
int getRoomNum();
}
RoomService的代码例如以下:
package com.android.service; import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException; public class RoomService extends Service{ private IData.Stub mBinder=new IData.Stub() { @Override
public int getRoomNum() throws RemoteException {
return 3008;
}
}; @Override
public IBinder onBind(Intent intent) {
return mBinder;
} }
AndroidManifest例如以下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.aidlsampleservice"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" /> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<service android:name="com.android.service.RoomService">
<intent-filter>
<action android:name="com.aidl.service.room"/>
</intent-filter>
</service>
</application> </manifest>
然后执行该Service所在的Project就可以。
client代码例如以下:
注意client也要有aidl文件,所以最简单的办法就是将Service端中aidl所在的包直接复制过去。
另外要注意的是在onDestroy中要解除和Service的绑定。
MainActivity.java的代码例如以下:
package com.example.aidlsampleclient; import com.android.service.IData; import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.widget.Button;
import android.widget.Toast;
import android.view.View; public class MainActivity extends Activity implements View.OnClickListener{ private static final String TAG="MainActivity";
private static final String ROOM_SERVICE_ACTION="com.aidl.service.room"; private Button bindServiceButton;
private Button getServiceButton; IData mData; private ServiceConnection conn=new ServiceConnection()
{ @Override
public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG,"----------------onServiceConnected--------");
mData=IData.Stub.asInterface(service);
} @Override
public void onServiceDisconnected(ComponentName name) { Log.i(TAG,"----------------onServiceDisconnected-------------");
mData=null; } }; private void initView()
{
bindServiceButton=(Button)findViewById(R.id.bindServiceButton);
getServiceButton=(Button)findViewById(R.id.getServiceButton);
bindServiceButton.setOnClickListener(this);
getServiceButton.setOnClickListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId())
{
case R.id.bindServiceButton:
bindService();
break;
case R.id.getServiceButton:
getService();
break;
default:
break;
}
} private void bindService()
{
Intent intent=new Intent();
intent.setAction(ROOM_SERVICE_ACTION);
bindService(intent,conn,BIND_AUTO_CREATE);
} private void getService()
{
try
{
if(mData!=null)
{
int roomNum=mData.getRoomNum();
showLongToast("RoomNum:"+roomNum);
} }
catch(RemoteException ex)
{
ex.printStackTrace();
} } private void showLongToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_LONG).show();
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unbindService(conn);
}
}
activity_main.xml的代码例如以下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" > <Button
android:id="@+id/bindServiceButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="BindService"
/>
<Button
android:id="@+id/getServiceButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="GetService"
android:layout_below="@id/bindServiceButton"
/> </RelativeLayout>
执行结果例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQmV0dGFyd2FuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">
然后举一个略微复杂一点的栗子,注意假设*.aidl文件里含有自己定义的对象,那么该对象的类要实现Parcelable接口,而且要新建一个该类的aidl文件,否则会出现could not find import for class com.android.service.XX的错误。当中XX为类名。还是上面的栗子。可是aidl文件里加入了一些新的方法。仍以上面的RoomService为例。
Service端的代码例如以下:
Room类的代码为:
package com.android.service; import android.os.Parcel;
import android.os.Parcelable; public class Room implements Parcelable{ //房间号
private int roomNum;
//房间大小
private float roomSpace;
//是否有空调
private boolean hasAirConditioner;
//是否有Wifi
private boolean hasWifi;
//房间内的装饰风格
private String decorativeStyle; public static final Parcelable.Creator<Room>CREATOR=new Parcelable.Creator<Room>() { @Override
public Room createFromParcel(Parcel source) {
return new Room(source);
} @Override
public Room[] newArray(int size) {
// TODO Auto-generated method stub
return null;
} }; public Room(int roomNum,float roomSpace,boolean hasAirConditioner,boolean hasWifi,String decorativeStyle)
{
this.roomNum=roomNum;
this.roomSpace=roomSpace;
this.hasAirConditioner=hasAirConditioner;
this.hasWifi=hasWifi;
this.decorativeStyle=decorativeStyle;
} private Room(Parcel source)
{
roomNum=source.readInt();
roomSpace=source.readFloat();
boolean[]tempArray=new boolean[2];
source.readBooleanArray(tempArray);
hasAirConditioner=tempArray[0];
hasWifi=tempArray[1];
decorativeStyle=source.readString();
} @Override
public String toString()
{
StringBuilder sb=new StringBuilder();
sb.append("Basic info of room is as follows:\n");
sb.append("RoomNum:"+roomNum+"\n");
sb.append("RoomSpace:"+roomSpace+"\n");
sb.append("HasAirConditioner:"+hasAirConditioner+"\n");
sb.append("HasWifi:"+hasWifi+"\n");
sb.append("Decorative Style:"+decorativeStyle);
return sb.toString(); } @Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
} @Override
public void writeToParcel(Parcel dest,int flags) {
dest.writeInt(roomNum);
dest.writeFloat(roomSpace);
dest.writeBooleanArray(new boolean[]{hasAirConditioner,hasWifi});
dest.writeString(decorativeStyle);
} }
Room的声明为:
package com.android.service;
parcelable Room;
IRoom.aidl的代码为:
package com.android.service;
import com.android.service.Room; interface IRoom
{
Room getRoom();
}
RoomService的代码为:
package com.android.service; import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException; public class RoomService extends Service{ private IRoom.Stub mBinder=new IRoom.Stub() { @Override
public Room getRoom() throws RemoteException {
Room room=new Room(3008,23.5f,true,true,"IKEA");
return room;
}
}; @Override
public IBinder onBind(Intent intent) {
return mBinder;
} }
因为AndroidManifest.xml的代码不变。因而此处不再贴出。以下是client的代码:
package com.example.aidlsampleclient;
import com.android.service.IRoom;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.widget.Button;
import android.widget.Toast;
import android.view.View; public class MainActivity extends Activity implements View.OnClickListener{ private static final String TAG="MainActivity";
//private static final String SERVICE_ACTION="com.aidl.service.data";
private static final String ROOM_SERVICE_ACTION="com.aidl.service.room"; private Button bindServiceButton;
private Button getServiceButton; IRoom mRoom; private ServiceConnection conn=new ServiceConnection()
{ @Override
public void onServiceConnected(ComponentName name, IBinder service) { Log.i(TAG,"----------------onServiceConnected--------");
showLongToast("onServiceConnected");
mRoom=IRoom.Stub.asInterface(service);
} @Override
public void onServiceDisconnected(ComponentName name) { Log.i(TAG,"----------------onServiceDisconnected-------------");
mRoom=null; } }; private void initView()
{
bindServiceButton=(Button)findViewById(R.id.bindServiceButton);
getServiceButton=(Button)findViewById(R.id.getServiceButton);
bindServiceButton.setOnClickListener(this);
getServiceButton.setOnClickListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId())
{
case R.id.bindServiceButton:
bindService();
break;
case R.id.getServiceButton:
getService();
break;
default:
break;
}
} private void bindService()
{
Intent intent=new Intent();
intent.setAction(ROOM_SERVICE_ACTION);
bindService(intent,conn,BIND_AUTO_CREATE);
} private void getService()
{
if(mRoom!=null)
{
try
{
showLongToast(mRoom.getRoom().toString());
}
catch (RemoteException e)
{
e.printStackTrace();
}
} } private void showLongToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_LONG).show();
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unbindService(conn);
}
}
注意首先仍然是要将Room,IRoom的代码复制过去,否则会出错。
执行结果例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQmV0dGFyd2FuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
显然。client已经成功读取到服务信息。
注意。上面的所举的栗子事实上不仅仅是跨进程。还是跨应用。要注意的是。跨应用一定跨进程。可是跨进程不一定是跨应用。
对于跨应用的情况。利用AIDL基本上是较好的攻克了问题,但也仅仅是“较好”而已。实际上并不完美,比方。假设要添加一个服务,假设利用AIDL的话,那么又要改写aidl文件,假设是涉及自己定义对象,则还要添加自己定义对象的声明,并且这样的改变不仅仅是Service端的改变。client也要跟着改变,显然这样的解决方式不够优雅。
那么。有没有更优雅的方法呢?
当然有。那就是利用Service的onStartCommand(Intent intent, int flags, int startId)方法。
服务端代码例如以下:
package com.android.service; import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast; public class RoomService extends Service{ private static final String TAG="RoomService";
private static final int CLEAN_SERVICE=0x1;
private static final int ORDER_SERVICE=0x2;
private static final int PACKAGE_SERVICE=0x3;
private static final String SERVICE_KEY="ServiceName";
@Override
public void onStart(Intent intent, int startId) {
showLog("onStart");
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
//String action=intent.getAction();
Log.i(TAG,"onStartCommand"); int actionFlag=intent.getIntExtra(SERVICE_KEY, -1);
switch(actionFlag)
{
case CLEAN_SERVICE:
showShortToast("Start Clean Service Right Now");
break;
case ORDER_SERVICE:
showShortToast("Start Order Service Right Now");
break;
case PACKAGE_SERVICE:
showShortToast("Start Package Service Right Now");
break;
default:
break;
}
return super.onStartCommand(intent, flags, startId);
} private void showLog(String info)
{
Log.i(TAG,info);
} private void showShortToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_SHORT).show();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
showLog("onDestroy");
super.onDestroy();
} @Override
public void onCreate() {
// TODO Auto-generated method stub
showLog("onCreate");
super.onCreate();
} @Override
public IBinder onBind(Intent intent) {
showLog("onBind");
return null;
} @Override
public boolean onUnbind(Intent intent) {
showLog("onUnbind");
return super.onUnbind(intent);
} }
client代码例如以下:
package com.example.aidlsampleclient;
import com.android.service.IRoom;
import com.android.service.RoomService; import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;
import android.view.Menu;
import android.widget.Button;
import android.widget.Toast;
import android.view.View; public class MainActivity extends Activity implements View.OnClickListener{ private static final String TAG="MainActivity";
private static final String ROOM_SERVICE_ACTION="com.aidl.service.room"; private static final int CLEAN_SERVICE=0x1;
private static final int ORDER_SERVICE=0x2;
private static final int PACKAGE_SERVICE=0x3; private static final String SERVICE_KEY="ServiceName"; private Button cleanButton;
private Button orderButton;
private Button packageButton; private void initView()
{
cleanButton=(Button)findViewById(R.id.cleanButton);
orderButton=(Button)findViewById(R.id.orderButton);
packageButton=(Button)findViewById(R.id.packageButton); cleanButton.setOnClickListener(this);
orderButton.setOnClickListener(this);
packageButton.setOnClickListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId())
{
case R.id.cleanButton:
cleanAction();
break;
case R.id.orderButton:
orderAction();
break;
case R.id.packageButton:
packageAction();
break;
default:
break;
}
} private void cleanAction()
{
startAction(ROOM_SERVICE_ACTION,CLEAN_SERVICE);
} private void orderAction()
{
startAction(ROOM_SERVICE_ACTION,ORDER_SERVICE);
} private void packageAction()
{
startAction(ROOM_SERVICE_ACTION,PACKAGE_SERVICE);
} private void startAction(String actionName,int serviceFlag)
{
//Intent intent=new Intent(this,RoomService.class);
Intent intent=new Intent();
intent.setAction(actionName);
intent.putExtra(SERVICE_KEY, serviceFlag);
this.startService(intent);
} private void showLongToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_LONG).show();
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}
执行结果例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQmV0dGFyd2FuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQmV0dGFyd2FuZw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">
显然。此时client顺利获取了服务。
上面举的是跨应用的样例。假设是在同一个应用的不同进程的话,则有更简单的实现方法。
RoomService的代码例如以下:
<span style="font-size:18px;">package com.android.service; import com.android.actions.Actions; import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast; public class RoomService extends Service{ private static final String TAG="RoomService";
@Override
public void onStart(Intent intent, int startId) {
showLog("onStart");
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
//String action=intent.getAction();
Log.i(TAG,"onStartCommand");
String action=intent.getAction();
if(Actions.CLEAN_ACTION.equals(action))
{
showShortToast("Start Clean Service Right Now");
}
else if(Actions.ORDER_ACTION.equals(action))
{
showShortToast("Start Order Service Right Now");
}
else if(Actions.PACKAGE_ACTION.equals(action))
{
showShortToast("Start Package Service Right Now");
}
else
{
showShortToast("Wrong action");
}
return super.onStartCommand(intent, flags, startId);
} private void showLog(String info)
{
Log.i(TAG,info);
} private void showShortToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_SHORT).show();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
showLog("onDestroy");
super.onDestroy();
} @Override
public void onCreate() {
// TODO Auto-generated method stub
showLog("onCreate");
super.onCreate();
} @Override
public IBinder onBind(Intent intent) {
showLog("onBind");
return null;
} @Override
public boolean onUnbind(Intent intent) {
showLog("onUnbind");
return super.onUnbind(intent);
} }</span>
MainActivity的代码例如以下:
package com.android.activity;
import com.android.activity.R;
import com.android.service.RoomService; import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.widget.Button;
import android.widget.Toast;
import android.view.View;
import com.android.actions.Actions; public class MainActivity extends Activity implements View.OnClickListener{ private static final String TAG="MainActivity"; private static final String SERVICE_KEY="ServiceName"; private Button cleanButton;
private Button orderButton;
private Button packageButton; private void initView()
{
cleanButton=(Button)findViewById(R.id.cleanButton);
orderButton=(Button)findViewById(R.id.orderButton);
packageButton=(Button)findViewById(R.id.packageButton); cleanButton.setOnClickListener(this);
orderButton.setOnClickListener(this);
packageButton.setOnClickListener(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId())
{
case R.id.cleanButton:
cleanAction();
break;
case R.id.orderButton:
orderAction();
break;
case R.id.packageButton:
packageAction();
break;
default:
break;
}
} private void cleanAction()
{
startAction(Actions.CLEAN_ACTION);
} private void orderAction()
{
startAction(Actions.ORDER_ACTION);
} private void packageAction()
{
startAction(Actions.PACKAGE_ACTION);
} private void startAction(String actionName)
{
Intent intent=new Intent(this,RoomService.class);
intent.setAction(actionName);
this.startService(intent);
} private void showLongToast(String info)
{
Toast.makeText(getBaseContext(), info, Toast.LENGTH_LONG).show();
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}
执行结果同上。此处不再贴图。
那AIDL还有存在的必要吗?当然有!最重要的一点是代价问题,从打印的log可看出,client每调用一次Context.startService(Intent),Service就会又一次运行一次onStartCommand---->onStart。而使用AIDL的话。绑定服务之后,不会反复运行onStart。显然后者的代价更小。
最后再讲一个Service的重点应用:前台Service,像我们经经常使用的天气、音乐事实上都利用了前台Service来实现。 实例到明天再补上吧。
转载请注明出处:http://blog.csdn.net/bettarwang/article/details/40947481
Android中的跨进程通信方法实例及特点分析(一):AIDL Service的更多相关文章
- Android中的跨进程通信方法实例及特点分析(二):ContentProvider
1.ContentProvider简单介绍 在Android中有些数据(如通讯录.音频.视频文件等)是要供非常多应用程序使用的.为了更好地对外提供数据.Android系统给我们提供了Content P ...
- Android随笔之——跨进程通信(一) Activity篇
在Android应用开发中,我们会碰到跨进程通信的情况,例如:你用QQ通讯录打电话的时候会调用系统的拨号应用.某些新闻客户端可以将新闻分享到QQ.微信等应用,这些都是跨进程通信的情况.简而言之,就是一 ...
- Android中的跨进程调用技术AIDL
什么是AIDL Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信. 为了使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用 ...
- Android四种跨进程通信
由于android系统中应用程序之间不能共享内存.因此,在不同应用程序之间交互数据(跨进程通讯)就稍微麻烦一些.在android SDK中提供了4种用于跨进程通讯的方式.这4种方式正好对应于andro ...
- android自动化测试解决跨进程通信问题
大概用这些吧: IPC Handler Messager Bundle service(binder) messageconnection ,thead.getXXX.getId 注 ...
- 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇
前言 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Andro ...
- 图文详解 Android Binder跨进程通信机制 原理
图文详解 Android Binder跨进程通信机制 原理 目录 目录 1. Binder到底是什么? 中文即 粘合剂,意思为粘合了两个不同的进程 网上有很多对Binder的定义,但都说不清楚:Bin ...
- android 远程Service以及AIDL的跨进程通信
在Android中,Service是运行在主线程中的,如果在Service中处理一些耗时的操作,就会导致程序出现ANR. 但如果将本地的Service转换成一个远程的Service,就不会出现这样的问 ...
- 【Chromium中文文档】跨进程通信 (IPC)
跨进程通信 (IPC) 转载请注明出处:https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//General_Architecture/I ...
随机推荐
- 【BZOJ 1297】[SCOI2009]迷路
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 如果点与点之间的距离都是1的话. 那么T次方之后的矩阵上a[1][n]就是所求答案了. 但是这一题的边权可能会大于1 但最多为10 ...
- Nginx Zabbix
https://www.cnblogs.com/wangxiaoqiangs/archive/2016/04/20/5412111.html
- ruby on rails错误undefined method `title' for nil:NilClass
首先搞清楚这句话,在 Ruby 中,方法分为 public.private 和 protected 三种,仅仅有 public 方法才干作为控制器的动作. 我的出错的代码例如以下: controlle ...
- Android-Volley网络通信框架(自己定义Request 请求:实现 GsonRequest)
1.回想 上篇学习了android 通过 volley 网络通信框架 实现 请求图片的三种方法! 2.重点 (1)复习和熟悉 StringRequest ,JsonObjectRequest 方法 ( ...
- 【LeetCode】Palindrome Partitioning 解题报告
[题目] Given a string s, partition s such that every substring of the partition is a palindrome. Retur ...
- CxImage 简单配置与使用
CxImage 简单配置与使用 如果本篇文章还不能解决你在生成解决方案以及便宜过程中的问题 请参阅: http://blog.csdn.net/afterwards_/article/details/ ...
- [luogu P1776] 宝物筛选 解题报告(单调队列优化DP)
题目链接: https://www.luogu.org/problemnew/show/P1776 题目: 终于,破解了千年的难题.小FF找到了王室的宝物室,里面堆满了无数价值连城的宝物……这下小FF ...
- java算法数据结构
原文地址:github.com/kdn251/interviews 译文出自:掘金翻译计划 译者:王下邀月熊 校对者:PhxNirvana.根号三 这个 链接 用来查看本翻译与英文版是否有差别(如果你 ...
- 解决IE下的li中img多余4px的问题--IE6有的问题
为了对比明显,这里用img标签占位,但是背景用纯黑色 <ul> <li> <img src="" alt="" />< ...
- 51nod 1435 位数阶乘 (手动计算)
题目: 1435 位数阶乘 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 X是一个n位数的正整数 (x=a0a1...an−1) ...