Prolog101(12)

谓词repeat,相当于循环,根据最后一句语句判断是否退出循环。

sayhi:-
write('What is your name?'),
read(X),write('Hi '),write(X).

sayhito(X):-
write('Hi '),write(X).
do(sayhito(X)):-sayhito(X),!. 

loop_test:-
repeat, 
write('Enter command (end to exit): '), 
read(X), 
write(">>"), 
write(X), 
nl, 
X=end. 

用纯逻辑方法改写一下nani的例子

% a nonassertive version of nani search  

nani :- 
write('Welcome to Nani Search'), 
nl, 
initial_state(State), 
control_loop(State). 

control_loop(State) :- 
end_condition(State). 
control_loop(State) :- 
repeat, 
write('> '), 
read(X), 
constraint(State, X), 
do(State, NewState, X), 
control_loop(NewState). 

% initial dynamic state  
initial_state([ 
here(kitchen), 
have([]), 
location([ 
kitchen/apple, 
kitchen/broccoli, 
office/desk, 
office/flashlight, 
cellar/nani ]), 
status([ 
flashlight/off, 
game/on]) ]). 

% static state  
rooms([office, kitchen, cellar]). 
doors([office/kitchen, cellar/kitchen]). 

connect(X,Y) :- 
doors(DoorList), 
member(X/Y, DoorList). 
connect(X,Y) :- 
doors(DoorList), 
member(Y/X, DoorList). 

% list utilities  
member(X,[X|Y]). 
member(X,[Y|Z]) :- member(X,Z). 

delete(X, [], []). 
delete(X, [X|T], T). 
delete(X, [H|T], [H|Z]) :- delete(X, T, Z). 

% state manipulation utilities
get_state(State, here, X) :- 
member(here(X), State). 
get_state(State, have, X) :- 
member(have(Haves), State), 
member(X, Haves). 
get_state(State, location, Loc/X) :- 
member(location(Locs), State), 
member(Loc/X, Locs). 
get_state(State, status, Thing/Stat) :- 
member(status(Stats), State), 
member(Thing/Stat, Stats). 

del_state(OldState, [location(NewLocs) | Temp], location, Loc/X):- 
delete(location(Locs), OldState, Temp), 
delete(Loc/X, Locs, NewLocs). 

add_state(OldState, [here(X)|Temp], here, X) :- 
delete(here(_), OldState, Temp). 
add_state(OldState, [have([X|Haves])|Temp], have, X) :- 
delete(have(Haves), OldState, Temp). 
add_state(OldState, [status([Thing/Stat|TempStats])|Temp], status, Thing/Stat) :- 
delete(status(Stats), OldState, Temp), 
delete(Thing/_, Stats, TempStats). 

% end condition  
end_condition(State) :- 
get_state(State, have, nani), 
write('You win'). 

end_condition(State) :- 
get_state(State, status, game/off), 
write('quitter'). 

% constraints and puzzles together  
constraint(State, goto(cellar)) :- 
!, can_go_cellar(State). 
constraint(State, goto(X)) :- 
!, can_go(State, X). 
constraint(State, take(X)) :- 
!, can_take(State, X). 
constraint(State, turn_on(X)) :- 
!, can_turn_on(State, X). 
constraint(_, _). 

can_go(State,X) :- 
get_state(State, here, H), 

connect(X,H). 
can_go(_, X) :- 
write('You can''t get there from here'), 
nl, fail. 

can_go_cellar(State) :- 
can_go(State, cellar), 
!, cellar_puzzle(State). 

cellar_puzzle(State) :- 
get_state(State, have, flashlight), 
get_state(State, status, flashlight/on). 
cellar_puzzle(_) :- 
write('It''s dark in the cellar'), 
nl, fail. 

can_take(State, X) :- 
get_state(State, here, H), 
get_state(State, location, H/X). 
can_take(State, X) :- 
write('it is not here'), 
nl, fail. 

can_turn_on(State, X) :- 
get_state(State, have, X). 
can_turn_on(_, X) :- 
write('You don''t have it'), 
nl, fail. 

% commands  
do(Old, New, goto(X)) :- goto(Old, New, X), !. 
do(Old, New, take(X)) :- take(Old, New, X), !. 
do(Old, New, turn_on(X)) :- turn_on(Old, New, X), !. 
do(State, State, look) :- look(State), !. 
do(Old, New, quit) :- quit(Old, New). 
do(State, State, _) :- 
write('illegal command'), nl. 

look(State) :- 
get_state(State, here, H), 
write('You are in  '), write(H), nl, 
write('You can see'), list_things(State, H), nl,
write('You have'), list_bag(State, H), nl,
write('You can go'), list_rooms(H), nl. 

list_things(State, H) :- 
get_state(State, location, H/X), 
tab(2), write(X), 
fail. 
list_things(_, _). 

list_rooms(H) :- 
connect(X,H),tab(2),write(X),fail.
list_rooms(_).

list_bag(State, H) :- 
get_state(State, have, X), 
tab(2), write(X), 
fail. 
list_bag(_, _). 

goto(Old, New, X) :- 
add_state(Old, New, here, X), 
look(New). 

take(Old, New, X) :- 
get_state(Old, here, H), 
del_state(Old, Temp, location, H/X), 
add_state(Temp, New, have, X). 

turn_on(Old, New, X) :- 
add_state(Old, New, status, X/on). 

quit(Old, New) :- 
add_state(Old, New, status, game/off).

试一下

?- nani().
Welcome to Nani Search
> look.
You are in  kitchen
You can see  apple  broccoli
You have
You can go  office  cellar
> |: take(apple).
> |: take(broccoli).
> |: goto(office).
You are in  office
You can see  desk  flashlight
You have  broccoli  apple
You can go  kitchen
> |: take(desk).
> |: take(flashlight).
> |: goto(kitchen).
You are in  kitchen
You can see
You have  flashlight  desk  broccoli  apple
You can go  office  cellar
> |turn_on(flashlight).
> |: goto(cellar).
You are in  cellar
You can see  nani
You have  flashlight  desk  broccoli  apple
You can go  kitchen
> |: take(nani).
You win
true .

Prolog101(11)

使用Prolog时,有时需要人为的终止回溯,此时会用到谓词cut,使用符号!来表示。

data(one).  
data(two). 
data(three).

cut_test_a(X) :- data(X).
cut_test_a('last clause').

cut_test_b(X) :- data(X), !.  
cut_test_b('last clause').

cut_test_c(X,Y) :- data(X), !, data(Y).
cut_test_c('last clause'). 

来测试一下

1- cut_test_a(X), write(X), nl, fail. 
one
two
three
last clause
false.

2- cut_test_b(X), write(X), nl, fail. 
one
false.

3- cut_test_c(X,Y), write(X-Y), nl, fail.
one-one
one-two
one-three
false.

此外,可以用not谓词判断条件是否成立

not(X) :- call(X), !, fail. 
not(X)

下面两种方式是等效的:

have(apple).

eat():-
write('yummy...').

eat_fruit_a(X):- 
have(X), 
!,
eat().

eat_fruit_b(X):-  not(can_not_eat(X)),eat().
can_not_eat(X):-  
not(have(X)).

eat_fruit_c(X):-  can_eat(X),eat().
can_eat(X):- have(X).
can_eat(X):- fail.
1- eat_fruit_a(apple).
yummy...
true.

2- eat_fruit_a(pear).
false.

3- eat_fruit_b(apple).
yummy...
true.

4- eat_fruit_b(pear).
false.

5- eat_fruit_c(apple).
yummy...
true .

6- eat_fruit_c(pear).
false.

Prolog101(10)

可以用op/3把任何谓词定义为操作符,每个操作符有不同的优先权值,从1到1200。当某句中有多个操作符时,优先权高的将先被考虑,优先权值越小优先权越高。

Prolog操作符有三种形式,其结合性如下:
中缀(infix):例如3+4
xfx 没有结合性
xfy 从右向左
yfx 从左向右

前缀(prefix):例如-7
fx 没有结合性
fy 从右向左

后缀(postfix):例如8f
xf 没有结合性
yf 从右向左

op/3需要三个参数,分别是:优先权、结合性、操作符名称。

其实Prolog程序的子语句也是使用操作符书写的Prolog数据结构。这里的操作符是”:-“,它是中缀操作符,有两个参数。
:-(Head, Body).

Body也是由操作符书写的数据结构。这里的操作符为”,”,它表示并且的意思,所以Body的形式如下:
,(goal1, ,(goal2,,goal3))

好像看不明白,操作符”,”与分隔符”,”无法区别,所以我们就是用”&”来代替操作符”,”,于是上面的形式就变成了下面这个样子了。
&(goal1, &(goal2, & goal3))

下面的两种形式表达的意思是相同的。
head :- goal1 & goal2 & goal3.
:-(head, &(goal1, &(goal2, & goal3))).

实际上是下面的形式:
head :- goal1 , goal2 , goal3.
:-(head, ,(goal1, ,(goal2, , goal3))).

下面用操作符改写一下roomlist:

%swipl -s operator.pl
%Hansen

%动态函数声明
:-dynamic here/1.
:-dynamic is_in/2.
:-dynamic in_bag/1.
:-dynamic take_thing/2.
:-dynamic put_thing/2.

%定义操作符
:-op(100,fx,is_room).
:-op(101,xfx,is_in).
:-op(101,fx,in_bag).
:-op(101,fx,move).
:-op(101,fx,eat).
:-op(101,f,look).

%房间定义
room(X):- is_room List,member(X,List).
is_room [kitchen,office,hall,diningroom,cellar]. 

%门定义
door(X,Y):- door_list(List),member([X,Y],List).
door_list([[office, hall],[kitchen, office],[hall, diningroom],[kitchen, cellar],[diningroom, kitchen]]).

%规则:有门的两个房间是相通的
connect(X,Y):- door(X,Y).
connect(X,Y):- door(Y,X).

%物品在哪个房间
location(X,Y):- List is_in Y, member(X, List).
[apple, broccoli, crackers] is_in kitchen. 
[desk, computer] is_in office.
[flashlight, envelope] is_in desk.
[stamp, key] is_in envelope.
[] is_in hall.
[] is_in diningroom.
[washingmachine] is_in cellar. 
[nani] is_in washingmachine.

%房间减少物品
take_thing(Thing, Place):- 
retract(List is_in Place),
delete(List,Thing,ThingsLeft),
asserta(ThingsLeft is_in Place). 

%房间增加物品
put_thing(Thing, Place):-  
retract(List is_in Place),
asserta([Thing|List] is_in Place).

%背包有哪些物品
bag(X):-in_bag List, member(X, List).
in_bag [tourch].

%背包增加物品
bag_in(Thing):- 
retract(in_bag List),
asserta(in_bag [Thing|List]).

%背包减少物品
bag_out(Thing):-
retract(in_bag List),
delete(List,Thing,ThingsLeft),
asserta(in_bag ThingsLeft). 

%哪些物品可以吃
edible(X):- 
member(X,[apple,crackers,broccoli]).

%当前位置
here(hall).

%房间之间移动
move(Place):- can_go(Place),retract(here(X)), asserta(here(Place)).
can_go(Place):- here(X), connect(X, Place).
can_go(Place):- write('You can''t go to '),write(Place),write(' from here.'), nl, fail.

%拿起物品
take(X):- can_take(X), here(Place), take_thing(X,Place), bag_in(X), write(X), write(' taken.'), nl.
can_take(Thing):- here(Place), location(Thing, Place).
can_take(Thing):- write('There is no '), write(Thing), write(' here.'), nl, fail.

%放下物品
put(X):- can_put(X), here(Place), bag_out(X), put_thing(X,Place), write(X), write(' put.'), nl.
can_put(Thing):- bag(Thing). 
can_put(Thing):- write('There is no '), write(Thing), write(' in your bag.'), nl, fail. 

%房间物品列表
list_things(Place):- location(X, Place),tab(2),write(X),nl,fail.
list_things(_).

%与Place相连的房间
list_connections(Place):- connect(Place, X),tab(2),write(X),nl,fail.
list_connections(_).

%持有物品列表
list_bag(Thing):- bag(X),tab(2),write(X),nl,fail.
list_bag(_).

%吃东西
eat(Thing):- can_eat(Thing), bag_out(Thing), write(Thing), write(' eaten. Yummy!').
can_eat(Thing):- bag(Thing), edible(Thing).
can_eat(Thing):- not(bag(Thing)), write('There is no '), write(Thing), write(' in your bag.'), nl, fail. 
can_eat(Thing):- bag(Thing), write('You can''t eat the '), write(Thing), write('.'), nl, fail. 

%查看房间情况
look :-
here(Place), write('You are in the '), write(Place), nl,
write('You can see:'),nl,list_things(Place),  
write('You can go to:'), nl, list_connections(Place),
write('You have:'),nl,list_bag(Thing).

%帮助
game :-
write('Look around: look/0'),nl,
write('Move around: move/1'),nl,
write('Take something: take/1'),nl,
write('Eat something: eat/1').

Prolog101(09)

现在我们使用列表,重写一下room.pl文件。

%swipl -s roomlist.pl
%Hansen

%动态函数声明
:-dynamic here/1.
:-dynamic location_list/2.
:-dynamic bag_list/1.
:-dynamic take_thing/2.
:-dynamic put_thing/2.

%房间定义
room(X):- room_list(List),member(X,List).
room_list([kitchen,office,hall,diningroom,cellar]). 

%门定义
door(X,Y):- door_list(List),member([X,Y],List).
door_list([[office, hall],[kitchen, office],[hall, diningroom],[kitchen, cellar],[diningroom, kitchen]]).

%规则:有门的两个房间是相通的
connect(X,Y):- door(X,Y).
connect(X,Y):- door(Y,X).

%物品在哪个房间
location(X,Y):- location_list(List, Y), member(X, List).
location_list([apple, broccoli, crackers], kitchen). 
location_list([desk, computer], office).
location_list([flashlight, envelope], desk).
location_list([stamp, key], envelope).
location_list([], hall).
location_list([], diningroom).
location_list([washingmachine], cellar). 
location_list([nani], washingmachine).

%房间减少物品
take_thing(Thing, Place):- 
retract(location_list(List, Place)),
delete(List,Thing,ThingsLeft),
asserta(location_list(ThingsLeft,Place)). 

%房间增加物品
put_thing(Thing, Place):-  
retract(location_list(List, Place)),
asserta(location_list([Thing|List],Place)).

%背包有哪些物品
bag(X):-bag_list(List), member(X, List).
bag_list([tourch]).

%背包增加物品
bag_in(Thing):- 
retract(bag_list(List)),
asserta(bag_list([Thing|List])).

%背包减少物品
bag_out(Thing):-
retract(bag_list(List)),
delete(List,Thing,ThingsLeft),
asserta(bag_list(ThingsLeft)). 

%哪些物品可以吃
edible(X):- 
member(X,[apple,crackers,broccoli]).

%当前位置
here(hall).

%房间之间移动
move(Place):- can_go(Place),retract(here(X)), asserta(here(Place)).
can_go(Place):- here(X), connect(X, Place).
can_go(Place):- write('You can''t go to '),write(Place),write(' from here.'), nl, fail.

%拿起物品
take(X):- can_take(X), here(Place), take_thing(X,Place), bag_in(X), write(X), write(' taken.'), nl.
can_take(Thing):- here(Place), location(Thing, Place).
can_take(Thing):- write('There is no '), write(Thing), write(' here.'), nl, fail.

%放下物品
put(X):- can_put(X), here(Place), bag_out(X), put_thing(X,Place), write(X), write(' put.'), nl.
can_put(Thing):- bag(Thing). 
can_put(Thing):- write('There is no '), write(Thing), write(' in your bag.'), nl, fail. 

%房间物品列表
list_things(Place):- location(X, Place),tab(2),write(X),nl,fail.
list_things(_).

%与Place相连的房间
list_connections(Place):- connect(Place, X),tab(2),write(X),nl,fail.
list_connections(_).

%持有物品列表
list_bag(Thing):- bag(X),tab(2),write(X),nl,fail.
list_bag(_).

%吃东西
eat(Thing):- can_eat(Thing), bag_out(Thing), write(Thing), write(' eaten. Yummy!').
can_eat(Thing):- bag(Thing), edible(Thing).
can_eat(Thing):- not(bag(Thing)), write('There is no '), write(Thing), write(' in your bag.'), nl, fail. 
can_eat(Thing):- bag(Thing), write('You can''t eat the '), write(Thing), write('.'), nl, fail. 

%查看房间情况
look :-
here(Place), write('You are in the '), write(Place), nl,
write('You can see:'),nl,list_things(Place),  
write('You can go to:'), nl, list_connections(Place),
write('You have:'),nl,list_bag(Thing).

%帮助
game :-
write('Look around: look/0'),nl,
write('Move around: move/1'),nl,
write('Take something: take/1'),nl,
write('Eat something: eat/1').

进行查询

%查找与kitchen相连的房间
1 ?- findall(X, connect(kitchen, X), List).
List = [office, cellar, diningroom].

%查找全部食物与位置
2 ?- findall(foodat(X,Y), (location(X,Y) , edible(X)), L).
L = [foodat(broccoli, kitchen), foodat(crackers, kitchen)].

swipl的奇怪报错

在windows下用swipl命令运行prolog脚本时,经常会遇到下面的错误:

ERROR: char_code/2: Cannot represent due to `character_code'

解决方法有两种:
1、使用swipl-win命令替代swipl命令
2、在macos下使用swipl命令

应该是一个bug,在读入字符时(如;),处理不当导致的。

macOS使用Prolog命令行工具

1、看一下SWI-Prolog的安装说明,发现命令行工具在下面的路径

/Applications/SWI-Prolog.app/Contents/MacOS

2、修改PATH变量,添加SWI-Prolog命令行工具在下面的路径

#查看命令行工具
cd /Applications/SWI-Prolog.app/Contents/MacOS
ls

#查看PATH变量
echo "$PATH"

#修改PATH变量
vi $HOME/.bash_profile
#增加一行
export PATH=${PATH}:/Applications/SWI-Prolog.app/Contents/MacOS

3、重启命令行

#查看PATH变量
echo "$PATH"

#测试一下
swipl hello.pl 

MongoDB查询使用Codec的简单示例(java)

1、数据准备

db.person.insert({"name":"neo","age":"26","sex":"male"})
db.person.insert({"name":"joe","age":"28","sex":"male"})

2、使用Codec

class Person  
{
       public ObjectId _id;
       public double Age;  
       public String Name;  
       public String Sex;  
       
       public Person(ObjectId _id, String Name, double Age, String Sex)
       {
    	   this._id=_id;
    	   this.Name=Name;
    	   this.Age=Age;
    	   this.Sex=Sex;
       }
}

class PersonCodec implements Codec<Person> 
{
    private final CodecRegistry codecRegistry;

    public PersonCodec(final CodecRegistry codecRegistry) {
        this.codecRegistry = codecRegistry;
    }
    
    @Override
    public void encode(BsonWriter writer, Person t, EncoderContext ec) {
    	 writer.writeStartDocument();
         writer.writeName("_id");
         writer.writeObjectId(t._id);
         writer.writeName("name");
         writer.writeString(t.Name);
         writer.writeName("age");
         writer.writeDouble(t.Age);
         writer.writeName("sex");
         writer.writeString(t.Sex);
         writer.writeEndDocument();
    }

    @Override
    public Class<Person> getEncoderClass() {
        return Person.class;
    }

    @Override
    public Person decode(BsonReader reader, DecoderContext dc) 
    {
        reader.readStartDocument();
        reader.readName();
        ObjectId _id = reader.readObjectId();
        reader.readName();
        String name = reader.readString();
        reader.readName();
        double age = reader.readDouble();
        reader.readName();
        String sex =reader.readString();
        reader.readEndDocument();
        return new Person(_id,name,age,sex);
    }
}

class PersonCodecProvider implements CodecProvider 
{
    @Override
    public <T> Codec<T> get(Class<T> type, CodecRegistry cr) 
    {
        if (type == Person.class) 
        {
            return (Codec<T>) new PersonCodec(cr);
        }
        return null;
    }
}

public class CodecTest 
{
	private static void testCodec()
	{
		String[] hosts = {"127.0.0.1"};
		int port = 27017;
		String user = null;
		String password = null;
		String database = "test";
		CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
	            CodecRegistries.fromProviders(new PersonCodecProvider()),
	            MongoClient.getDefaultCodecRegistry());  
		
		MongoClient mongoClient = getConnection(hosts,port,user,password,database,codecRegistry);
		MongoDatabase db = mongoClient.getDatabase("test");
		MongoCollection<Person> collection = db.getCollection("person",Person.class);
		FindIterable<Person> iterable = collection.find();
		MongoCursor<Person> cursor = iterable.iterator();
		while (cursor.hasNext())
		{
        		Person p  = cursor.next();
        		System.out.println("personName: " + p.Name);
		}
	}
	
	private static MongoClient getConnection(String[] hosts, int port, String user, String password, String database, CodecRegistry codecRegistry)
	{
	        MongoClientOptions mongoClientOptions = new MongoClientOptions.Builder()
	        .connectionsPerHost(100)
	        .threadsAllowedToBlockForConnectionMultiplier(5)
	        .maxWaitTime(1000 * 60 * 2)
	        .connectTimeout(1000 * 10)
	        .socketTimeout(0)
	        .socketKeepAlive(false)
	        .readPreference(ReadPreference.primary())
	        .writeConcern(WriteConcern.ACKNOWLEDGED)
	        .codecRegistry(codecRegistry)
	        .build();
		
		List<ServerAddress> mongoAddresses = new ArrayList<ServerAddress>();
		for (String host : hosts) {
		    mongoAddresses.add(new ServerAddress(host, port));
		}
		
		List<MongoCredential> mongoCredentials = null;
		if (user != null && !user.isEmpty() && password != null && !password.isEmpty()) {
		    mongoCredentials = new ArrayList<MongoCredential>();
		    mongoCredentials.add(MongoCredential.createMongoCRCredential(user, database, password.toCharArray()));
		}
		
		if(mongoCredentials==null)
		{
			return new MongoClient(mongoAddresses, mongoClientOptions);
		}
		else
		{
			return new MongoClient(mongoAddresses, mongoCredentials, mongoClientOptions);
		}
	}
}

MongoDB的MapReduce简单示例(java)

1、数据准备

db.sell.insert({"price":8.0,"amount":500.0,"status":"a"})
db.sell.insert({"price":8.0,"amount":450.0,"status":"a"})
db.sell.insert({"price":8.0,"amount":400.0,"status":"a"})
db.sell.insert({"price":9.0,"amount":350.0,"status":"a"})
db.sell.insert({"price":9.0,"amount":300.0,"status":"a"})
db.sell.insert({"price":9.0,"amount":250.0,"status":"a"})
db.sell.insert({"price":9.0,"amount":200.0,"status":"a"})
db.sell.insert({"price":10.0,"amount":150.0,"status":"d"})
db.sell.insert({"price":10.0,"amount":100.0,"status":"d"})
db.sell.insert({"price":10.0,"amount":50.0,"status":"d"})
db.sell.insert({"price":10.0,"amount":0.0,"status":"d"})

2、MapReduce

	private static void testMapReduce3x()
	{
		MongoClient mongoClient = new MongoClient("localhost", 27017);
		MongoDatabase db = mongoClient.getDatabase("test");
		MongoCollection collection = db.getCollection("sell");

		String map = "function(){emit(this.price,this.amount);}";
		String reduce = "function(key, values){return Array.sum(values)}";

		MapReduceIterable out = collection.mapReduce(map, reduce);
		MongoCursor cursor = out.iterator();
		while (cursor.hasNext()) 
		{
			System.out.println(cursor.next());
		}
	}
	
	private static void testMapReduce2x()
	{
		MongoClient mongoClient = new MongoClient("localhost", 27017);
		MongoDatabase db = mongoClient.getDatabase("test");
		BasicDBObject query=new BasicDBObject("status","a");
		DBCollection dbcollection = mongoClient.getDB("test").getCollection("sell");
		
		String map = "function(){emit(this.price,this.amount);}";
		String reduce = "function(key, values){return Array.sum(values)}";
		
		MapReduceCommand cmd = new MapReduceCommand(dbcollection, map, reduce,
		    "outputCollection", MapReduceCommand.OutputType.INLINE, query);
		
		MapReduceOutput out2 = dbcollection.mapReduce(cmd);
		for (DBObject o : out2.results()) 
		{
		   System.out.println(o.toString());
		}
	}

AndroidStudio配置NDK环境

1、新建工程,在工程根目录找到local.properties文件

sdk.dir=C\:/Languages/Android/android-sdk-windows
ndk.dir=C\:/Languages/Android/android-ndk-r10

2、在app\build.gradle文件中的defaultConfig段内增加

       ndk {
            moduleName "yourModuleName"
       }

2、在工程的app\src\main目录下,新增jni文件夹,将你的ndk工程拷进去

3、在app\src\main\java目录下,将你的java文件拷贝进去

4、如果你的ndk工程用到了其他so文件,在app目录下,新建jniLibs文件夹,将so文件拷贝进去

jniLibs\armeabi\xxx.so
jniLibs\armeabi-v7a\xxx.so
....

5、自定义文件夹路径。编辑app\build.gradle文件下的android段

    //自定义引用库路径
    sourceSets.main {
        jniLibs.srcDir 'src/main/cpplibs'
    }

    //自定义源码路径
    sourceSets.main {
        jni.srcDirs 'src/main/cpp'
    }

6、现在就可以用啦

7、另一种方式就是,先把so文件用命令行生成好,然后,android项目中直接引用so文件就好了

PS:
如果你的ndk项目只有一个c文件,用早期的AndroidStudio编译会报错:

make.exe: *** No rule to make target
......

Execution failed for task ':XXXXXX:compileXXXXXXDebugNdk'.
.......

这样的话,在你的c文件目录下,随便建立一个空的c文件,重新编译就好了,好挫。

Android配置NDK环境

准备工作
1、下载NDK
2、直接运行,会解压到当前文件夹
3、剪切到你喜欢的文件夹

第一个项目
1、写一个调用JNI的Java类

package com.neohope.android.jni;

public class JniFunc {
    private native int  addNative(int a, int b);

    static {
        System.loadLibrary("jnifunc");
    }

    public int add(int a, int b)
    {
        return addNative(a,b);
    }
}

2、用你喜欢的方式,编译为class文件

3、用jdk的javah工具生成头文件

#在class文件的顶层路径,比如这个例子,就在com这个文件夹相同目录下
javah com.neohope.android.jni.JniFunc

会输出文件“com_neohope_android_jni_JniFunc.h”:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_neohope_android_jni_JniFunc */

#ifndef _Included_com_neohope_android_jni_JniFunc
#define _Included_com_neohope_android_jni_JniFunc
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_neohope_android_jni_JniFunc
 * Method:    addNative
 * Signature: (II)I
 */
JNIEXPORT jint JNICALL Java_com_neohope_android_jni_JniFunc_addNative
  (JNIEnv *, jobject, jint, jint);

#ifdef __cplusplus
}
#endif
#endif

4、编写“com_neohope_android_jni_JniFunc.c”

#include <jni.h>
#include "com_neohope_android_jni_JniFunc.h"

JNIEXPORT jint JNICALL Java_com_neohope_android_jni_JniFunc_addNative
  (JNIEnv *evn, jobject obj, jint a, jint b)
{
    return a+b;
}

5、编写Android.mk及Application.mk

APP_ABI := all
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := jnifunc
LOCAL_SRC_FILES := com_neohope_android_jni_JniFunc.c \

LOCAL_C_INCLUDES += com_neohope_android_jni_JniFunc.h

include $(BUILD_SHARED_LIBRARY)

6、编译

SET NDK_HOME="C:\Languages\Android\android-ndk-r10d"

SET PATH=%NDK_HOME%;%PATH%

CMD

REM ndk-build