ps:阅读本文 需要对android 多进程编程有一定了解。

1.Android中总共有几种方式进行IPC?

答:一共有两种,一种是binder 还有一种是socket。Binder 大家用的比较多。Socket很少有人用,这里给出一个利用Socket进行ipc通信的例子。

服务端代码:

 package com.example.administrator.socketipcdemo;

 import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log; import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket; public class ServerService extends Service { public static final int SERVER_PORT_NUMBER = 5678;
private boolean mServiceDestroyed = false; @Override
public void onCreate() {
new Thread(new ServerRunnable()).start();
super.onCreate();
} @Override
public void onDestroy() {
mServiceDestroyed = true;
super.onDestroy();
} public ServerService() {
} @Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
} //这个线程 用于监听端口号
class ServerRunnable implements Runnable {
@Override
public void run() { ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(SERVER_PORT_NUMBER);
} catch (IOException e) {
e.printStackTrace();
}
while (!mServiceDestroyed) {
try {
final Socket client = serverSocket.accept();
new Thread() {
@Override
public void run() {
try {
responseClientRequest(client);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start(); } catch (IOException e) {
e.printStackTrace();
}
}
}
} private void responseClientRequest(Socket client) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())), true);
while (!mServiceDestroyed) {
String str = in.readLine();
if (str == null) {
break;
}
String reponseStr = "我是服务器端,我收到了来自客户端的消息:" + str;
out.println(reponseStr);
}
out.close();
in.close();
client.close();
}
}

客户端代码:

 package com.example.administrator.socketipcdemo;

 import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast; import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket; public class MainActivity extends AppCompatActivity { private Button bt, bt2;
private TextView tv;
private EditText et; private Socket socket;
private PrintWriter mPrintWriter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, ServerService.class);
startService(intent);
tv = (TextView) findViewById(R.id.tv);
et = (EditText) findViewById(R.id.et);
bt = (Button) this.findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
tryToLinkServer();
}
}.start(); }
}); bt2 = (Button) this.findViewById(R.id.bt2);
bt2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendMessageToServer(et.getText().toString());
}
}); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
} @Override
protected void onDestroy() {
if(socket!=null)
{
try {
socket.shutdownInput();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
super.onDestroy();
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); //noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
} return super.onOptionsItemSelected(item);
} private void sendMessageToServer(final String str) {
if (mPrintWriter != null) {
mPrintWriter.println(str);
}
} private void tryToLinkServer() {
while (socket == null) {
try {
socket = new Socket("localhost", ServerService.SERVER_PORT_NUMBER);
mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
} catch (IOException e) {
//每次连不上就等待1秒再重新连
SystemClock.sleep(1000);
e.printStackTrace();
}
}
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "和服务器进程成功链接", Toast.LENGTH_SHORT).show();
}
});
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (!MainActivity.this.isFinishing()) {
final String msg = br.readLine();
runOnUiThread(new Runnable() {
@Override
public void run() {
tv.setText(msg);
}
});
}
mPrintWriter.close();
br.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
} }

最后看一下运行效果:

2.android:process 属性值的书写有什么讲究?

答::remote 这种写法 其实就等于 包名:remote 而且这种写法 属于当前app的私有进程, 其他app 不可以和这个进程跑在一起的。

如果是直接 把android:process 写成字符串形式的话, 那这种进程就是全局进程了,谁都可以用。哪怕是其他app 只要是shareUid一样

就可以和这个进程跑在一起。当然了,签名也必须一样!

3.多进程编程的时候 我们需要注意哪些坑?

答:一定要记住 多进程的时候 实际上 一个进程就是一个虚拟机,所以 会引发如下几个问题:

a:所有静态变量和单例模式之类的 全部没用了。因为你多进程么,假设你的app代码里面 开启了2个进程,同时你的代码里面 有一个静态变量,这个时候注意 你的静态变量虽然在代码里只有一份,

但是此时是2个进程在跑 ,有2个虚拟机,所以你这个静态变量也是会变成两份的!

b:SharedPreferences 会失去同步效果。因为sp这个东西 你们看下源码就知道了,实际上他的底层就是个xml。。。并且android 对这个xml的读写自己弄了一套缓存,注意这个缓存是运行在内存中的,

所以你就知道 一旦多个进程的话,这个缓存就是多份了。。。。所以记住 不要在多进程里面使用sp

c:Application 会创建多次。这个你们打下log就知道了,所以如果你们application 有特殊处理的话 记得考虑下多进程的情况。

上面3个是我们需要注意的点,其实也很好理解,对于同一个app的 多个进程来说 ,他就等于 多个app 在运行,只不过这些app的uid和签名都一样!你想明白这点 就懂了android 多进程了。

4.android中有哪几种序列化方式?分别要注意什么?

答:两种。Serializable和Parcelable

Serializable:这种方式 就是要注意serialVersionUID,一般ide 给你生成的值 都是根据你class的结构来做的,假设你在版本1.0.1 里面 创建了class A,并且序列化了一个对象a 在sd卡里。

过了一段时间 你在1.0.2 版本里 把A的代码 改了很多,此时ide 会把你的serialVersionUID 值也随之改掉。那如果你在1.0.2版本里 还想反序列化这个对象a的话 就会出错了。

所以serialVersionUID 就是一个记录class 版本号的标示,我们最好还是把他写死。。。。这样不会影响我们的客户端。此外 transient 这个标记的变量也不会被序列化。

Parcelable:write方法就是序列化的时候 执行的方法 creator 就是反序列化的过程。Intent bundle bitmap 都实现了这个接口。List Map 也可以序列化 提前是 元素是这个接口对象。

两者基本上是差不多的,只不过Parcelable效率更高,一般在内存中使用时 我们用Parcelable,如果是 序列化到本地或者网络 这种流里的时候 我们就用Serializable 因为比较方便。

5.当遇到一个数据 无法放在Bundle里时,如何进行进程间通讯?

答:假设我们有一个需求,让A进程 计算一个东西以后 把 结果 result 传递给B进程。但是这个result结果 没有实现Parcelable 接口也无法放在bundle里。此时 该如何传递这个result到B?

其实可以让A进程 启动B进程 的一个intentService。让这个service 去计算出来这个结果result,这时候 我们会发现 此时这个service和b进程 在一个进程里。 result当然就随便传递了。不需要ipc来传递

6.Messenger 使用时,要注意哪些,他的原理是什么?

答:原理的话 其实看一下 源码就知道了:

 /**
* Create a Messenger from a raw IBinder, which had previously been
* retrieved with {@link #getBinder}.
*
* @param target The IBinder this Messenger should communicate with.
*/
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}

一看到这个代码我们就明白 原理就是AIDL么。要注意的话 就是Messenger只能用于单向通信,不能用于双向的 。如果你要用双向通信并且还要用Messenger来完成的话  就必须用2个Messenger。

Messenger传递对象就是传递的Message对象。其中我们注意了,在进程通信的时候,Message里的object 字段 只能传递 系统的parceable对象。也就是intent bitmap 这种系统自己实现的parceable接口对象。

如果是我们自己写的parceable 是无法放在object里面 用于进程通信的,如果你要用,请放在bundle里。此外Messenger 在内部 是串行处理请求的,大量消息 一起发给服务端这种业务模型

最好就别用Messenger了。直接自己写一个AIDL 最合适。

7.使用AIDL的时候 有哪些注意事项?

答:有下面几个注意事项:

a:aidl文件里不是所有数据类型都可以使用。只支持 基本数据类型,string,charSequence,List(只支持ArrayList,且里面的元素都能被AIDL支持),Map(只支持hashMap,并且元素必须是AIDL支持的),Parcelable,AIDL自己。

b:自定义的parceable对象要在aidl中 import 进来。并且自定义的parceable 要在aidl里 也额外声明一下,具体的看我前面的那篇blog即可。

c:aidl 里面只能写方法 不能写静态常量。

8.in out inout 这三个参数 在aidl 到底有啥用,不写有什么危害么?

答:据我观察 你不写其实没什么危害,但是你写明白了 传输效率会增加。其实这3个参数很好理解,简单建立一个方法模型:

假设你的aidl文件里有一个方法  void addPerson(Person person),这方法一看 就是客户端传一个person 到服务端 所以这个地方参数就是in。

如果你有一个方法叫 void getList(List a) 你看这个方法 就是把服务端的list 传递给这个参数a的list 那你就把参数写成out即可。

inout 就更好理解了,实际就是 void modifyList(List b),意思就是 先把b 这个list 传递给服务端,然后还要修改这个list。

9.CopyOnWriteArrayList 可以在aidl中使用吗?为什么?

答:可以使用。

 public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, Serializable {

虽然看声明 他并没有实现Parceable这个接口。也不是ArrayList的子类,但实际上AIDL支持的是抽象的List,所以在底层的时候 Binder 会把CopyOnWriteArrayList

转换成ArrayList 传递给客户端的。ConcurrentHashMap 也是一样。

10.Android 进程通信时候 能传递对象吗?

答:严格意义上 是不能的,实际上binder 会把客户端传递过来的对象 重新转换为一个新的对象 传递给服务端。对象的跨进程传输 本质上就是序列化和反序列化的过程。

11.RemoteCallBackList 干嘛的?使用时注意哪些?

答:具体可看http://www.cnblogs.com/punkisnotdead/p/5158016.html。 实际上这个东西讲明白了 就是用于 android中管理 跨进程listener接口的。

你想明白这个道理 就都懂了。而且他特别方便的是,客户端进程终止以后 他可以自动删除listenr。使用注意点就是begin和finish要成对出现。就算你是遍历listenrer操作

也要用这2个方法

12.aidl运行时的 线程模型?

答:http://www.cnblogs.com/punkisnotdead/p/5163464.html 这篇分析binder代码的时候 已经讲的很清楚了。这里再总结一次。

client 调用 server的方法a,client本身是会挂起的, 会一直等待server的方法a的 执行结果。

同时这个方法a 是运行在binder线程池中,所以server的方法  可以执行耗时操作。只不过 client调用的server方法时

注意不要在ui线程里调用,不然会anr的。同时如果你的业务是 一个server 多种client ,那你的server端 方法 要支持同步,不然会数据错乱的!

13.服务端 调用 客户端listener 方法有什么讲究?

答:实际上 和12问题是一样的,server 想调用 client的方法b,b也是会执行在 client所属进程的 binder线程池内的。同时我们也要避免 如果方法b执行时间很长,

记得server调用的时候 不要在主线程里调用。此外我们一般client 都是在activity里,记得 listener调用的方法 如果涉及到ui,请用handler切换到ui线程来做。

14.如何做权限认证?

答:两种方法,可以在onBind里 检查权限,也可以在server的onTransact里验证,验证失败返回false即可。后者方法更好 还可以验证uid pid等 可以支持复杂的多进程业务模型,

尤其是安全相关的。

15.一个aidl 就必须对应一个service吗?多种aidl 是不是只能多个service?

答:不是的,aidl 只不过是帮你书写binder用的工具,你当然可以只启动一个service 但是对应多个binder。要知道 service 资源是有限的 假设你app复杂 10个业务 开启10个service

那不是就乱套了。完全可以只开启一个service 但是这一个service 可以控制多种aidl 对应的binder,你要用哪个 就取那个binder 即可。

下面给出实例。

首先看一下 代码结构和运行效果,实际上就是一个加法binder 和一个乘法binder 只不过 这2个binder 都由一个service来控制而已。

然后来看一下加法和乘法的 aidl以及对应的binder 对象:

 // IAddition.aidl
package com.example.administrator.bindermanager; // Declare any non-default types here with import statements interface IAddition { int add(int a,int b);
}
 package com.example.administrator.bindermanager;

 import android.os.RemoteException;

 /**
* Created by Administrator on 2016/1/29.
*/
public class AdditionImpl extends IAddition.Stub {
@Override
public int add(int a, int b) throws RemoteException {
return a + b;
}
}
 // IMultiplication.aidl
package com.example.administrator.bindermanager; // Declare any non-default types here with import statements interface IMultiplication { int multip(int a,int b);
}
 package com.example.administrator.bindermanager;

 import android.os.RemoteException;

 /**
* Created by Administrator on 2016/1/29.
*/
public class MultiplicationImpl extends IMultiplication.Stub {
@Override
public int multip(int a, int b) throws RemoteException {
return a * b;
}
}

然后看看我们最为关键的binder manger 如何设计:

 // IBinderManger.aidl
package com.example.administrator.bindermanager; // Declare any non-default types here with import statements interface IBinderManger {
IBinder queryBinder(int binderCode);
}
 package com.example.administrator.bindermanager;

 import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log; /**
* Created by Administrator on 2016/1/29.
*/
public class BinderMangerImpl extends IBinderManger.Stub { public BinderMangerImpl() {
super();
} @Override
public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
switch (binderCode) {
case BinderManger.BINDER_ADDITION:
binder = new AdditionImpl();
break;
case BinderManger.BINDER_MULTIPLICATION:
binder = new MultiplicationImpl();
break;
default:
break;
}
return binder;
}
}
 package com.example.administrator.bindermanager;

 import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log; public class BinderMangerService extends Service { private IBinder mBinderManger = new BinderMangerImpl(); public BinderMangerService() {
} @Override
public IBinder onBind(Intent intent) {
return mBinderManger;
}
}
 package com.example.administrator.bindermanager;

 import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException; /**
* Created by Administrator on 2016/1/29.
*/
public class BinderManger { public static final int BINDER_ADDITION = 0;
public static final int BINDER_MULTIPLICATION = 1;
private Context mContext;
private IBinderManger mBinderManger;
private static BinderManger sInstance; private BinderManger(Context mContext) {
this.mContext = mContext.getApplicationContext();
connectBinderService();
} public static BinderManger getInstance(Context context) {
if (sInstance == null) {
sInstance = new BinderManger(context);
}
return sInstance;
} private synchronized void connectBinderService() {
Intent service = new Intent(mContext, BinderMangerService.class);
mContext.bindService(service, mServiceConnection, Context.BIND_AUTO_CREATE);
} private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinderManger = IBinderManger.Stub.asInterface(service);
} @Override
public void onServiceDisconnected(ComponentName name) { }
}; public IBinder queryBinder(int binderCode) throws RemoteException {
IBinder binder = null;
binder = mBinderManger.queryBinder(binderCode);
return binder;
}
}

最后看一下 我们的clinet端:

 package com.example.administrator.bindermanager;

 import android.os.Bundle;
import android.os.RemoteException;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView; import org.w3c.dom.Text; public class MainActivity extends AppCompatActivity { private Button bt, bt2, bt3;
private EditText et1, et2;
private TextView tv;
private BinderManger binderManger; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv2);
et1 = (EditText) findViewById(R.id.et);
et2 = (EditText) findViewById(R.id.et2);
bt = (Button) this.findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
binderManger = BinderManger.getInstance(MainActivity.this);
}
}); bt2 = (Button) this.findViewById(R.id.bt2);
bt2.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
try {
final IMultiplication multiplicationImpl =
(IMultiplication) MultiplicationImpl.asInterface(binderManger.queryBinder(BinderManger.BINDER_MULTIPLICATION)); runOnUiThread(new Runnable() {
@Override
public void run() {
try {
tv.setText(multiplicationImpl.multip(Integer.parseInt(et1.getText().toString()), Integer.parseInt(et2.getText().toString())) + "");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}); } catch (RemoteException e) {
e.printStackTrace();
}
}
}); bt3 = (Button) this.findViewById(R.id.bt3);
bt3.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
try {
final IAddition additionImpl =
(IAddition) AdditionImpl.asInterface(binderManger.queryBinder(BinderManger.BINDER_ADDITION));
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
tv.setText(additionImpl.add(Integer.parseInt(et1.getText().toString()), Integer.parseInt(et2.getText().toString())) + "");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}); } catch (RemoteException e) {
e.printStackTrace();
}
}
}); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).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.menu_main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); //noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
} return super.onOptionsItemSelected(item);
}
}

Android 多进程编程 15问15答!的更多相关文章

  1. Android 线程与消息 机制 15问15答

    1.handler,looper,messagequeue三者之间的关系以及各自的角色? 答:MessageQueue就是存储消息的载体,Looper就是无限循环查找这个载体里是否还有消息.Handl ...

  2. Android View绘制13问13答

    1.View的绘制流程分几步,从哪开始?哪个过程结束以后能看到view? 答:从ViewRoot的performTraversals开始,经过measure,layout,draw 三个流程.draw ...

  3. 《编程人生:15位软件先驱访谈录》【PDF】下载

    <编程人生:15位软件先驱访谈录>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382231 内容简介 本书适合所有程序员,也适合 ...

  4. Android BaseAdapter加载多个不同的Item布局时出现UncaughtException in Thread main java.lang.ArrayIndexOutOfBoundsException: length=15; index=15

    java.lang.ArrayIndexOutOfBoundsException: length=15; index=15 异常出现的场景:在做聊天界面时,需要插入表情,图片,文字,名片,还有几种较为 ...

  5. 并发编程学习笔记(15)----Executor框架的使用

    Executor执行已提交的 Runnable 任务的对象.此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节.调度等)分离开来的方法.通常使用 Executor 而不是显式地创建 ...

  6. Android零基础入门第15节:掌握Android Studio项目结构,扬帆起航

    原文:Android零基础入门第15节:掌握Android Studio项目结构,扬帆起航 经过前面的学习,Android Studio开发环境已准备OK,运行Android应用程序的原生模拟器和Ge ...

  7. 《Qt on Android核心编程》介绍

    <Qt on Android核心编程>最终尘埃落定.付梓印刷了. 2014-11-02更新:china-pub的预售链接出来了.折扣非常低哦. 封面 看看封面的效果吧,历经几版,最终就成了 ...

  8. Java 面试题问与答:编译时与运行时

    Java 面试题问与答:编译时与运行时 2012/12/17 | 分类: 基础技术, 职业生涯 | 5 条评论 | 标签: RUNTIME, 面试 分享到:58 本文作者: ImportNew - 朱 ...

  9. Android 网络编程 记录

    简单介绍 看了深入理解Android网络编程感觉不错.今天对Android网络编程进行了要点记录. 内容 Android基于网络技术和编程实践 要点 定义 描写叙述 IP协议 用于报文交换网络的一种面 ...

随机推荐

  1. Understanding node.js

    Node.js has generally caused two reactions in people I've introduced it to. Basically people either ...

  2. MySQL数据库的基本操作命令

    MySQL数据库的基本操作命令 [mysql]mysql 常用建表语句 一.mysql服务操作 net start mysql //启动mysql服务 net stop mysql //停止mysql ...

  3. spring定时器,5步完成

    spring定时器,5步完成,我们开发的时候会用定时执行任务. 用spring框架时,可以直接使用spring定时功能 1.创建任务调度类,里面一个方法,方法名为work 2. spring配置文件, ...

  4. 一起简单写一下AIDL,入个门

    前话 最近接触了Android开发的一个新知识,AIDL(¬_¬因为到现在都没用过) 因此不断谷歌找资料找Demo,自己尝试写一下. 因为用AndroidStudio作为开发环境,期间遇到过许多问题, ...

  5. Echarts事件

    Echart饼图.柱状图.折线图(pie.bar.line)添加点击事件发布日期:2014年08月10日   来源:PHP1.CN     点击:250638摘要:var myChart= echar ...

  6. Activity Recognition行为识别

    暑假听了computer vision的一个Summer School,里面Jason J. Corso讲了他们运用Low-Mid-High层次结构进行Video Understanding 和 Ac ...

  7. 《Java编程那点事儿》读书笔记(六)——异常处理

    1.抛出异常:throw 异常对象; 下面的代码是一个进制转换代码,可以转换为2进制和8进制,如果输入其他参数,则抛出异常. public static String transform(int va ...

  8. rqnoj-106-最大加权矩形-dp

    和我之前做的那个切西瓜的题目相比就是小巫见大巫了.. 运用最长字段和的原理把O(n^4)转化成O(n^3) #include<stdio.h> #include<string.h&g ...

  9. Delphi遍历文件夹

    /// <remarks> /// 遍历文件夹 (引用SysUtils单元) /// </remarks> procedure TfrmMusicMenu.SearchInDi ...

  10. BZOJ 3172 单词(ac自动机)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3172 题意:给出n个单词.输出每个单词在所有单词中一共出现多少次? 思路:首先将所有单词 ...