ppjun's blog

Thanks for your watching


  • 首頁

  • 歸檔

  • 關於

  • 檢索
close

IPC机制基础

發表於 2017-01-19   |  

IPC基础分享

这一章主要讲述多进程的作用,序列化和反序列化,Serializable和Parcelable

​ IPC叫进程间通信,指的是A进程和B进程交换信息。通常一个android应用是一个进程,一个进程有一个主线程和多个子线程组成,在A进程activity定义变量private static int i=1;并且让i+1,输出2,到了B进程activity,获取到的i的值还是1,这是因为Android多进程间不能共享内存。启动多进程期间,会再次启动Application的生命周期,比如application类的oncreate等方法又执行了一次。不过,在android有以下方法进行进程间交换数据

  1. bundle(用bundle和intent在两个进程传递数据)
  2. 操作文件(读写操作同一个文件)
  3. AIDL(基于binder的通信方式,用aidl文件更加方便)
  4. Messenger(封装后的aidl,只需用Messenger.send(message);即可发送信息)
  5. ContentProvider(读写数据库)
  6. Socket(启动本地的套接字来通信)

多进程的作用

  1. 把应用某个单独的功能,单独放在一个进程中。

  2. 能给应用获取多份内存空间

开启多进程

在AndroidManifest.xml文件给对应的activity或者service设置以下属性,其中值为:remote的进程不能共享进程资源,其他两个值能共享,前提条件是在manifest标签配置相同的sharedUserId比如(android:sharedUserId=”com.ppjun.sharedUserId”),还要让两个应用配置相同的签名。

1
2
3
<android:process=":remote"/>     //对应的进程名是包名:remote
<android:process=".remote"/> //对应的进程名是包名.remote
<android:process="com.ppjun.remote"/> //对应的进程名是com.ppjun.remote

序列化和反序列化

  1. 序列化就是永久保存对象数据到文件中。
  2. 在activity或者service之间将对象序列化对象后通过intent等传递。
  3. 在多进程之间也要将对象序列化后才能传递。

序列化是一个将对象变成字节的过程,发序列化是将这些字节重组成一个对象的过程。在Android中提供了Serializable和Parcelable接口序列化对象。

Serializable

让类实现Serializable接口,并且指定一个long类型的serialVersionUID=xxxxL;xxxx为你自定义值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Student implements Serializable {
private static int final long serialVersionUID=213213123L
private String name;

public Student(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

序列化student

1
2
3
4
Student student = new Student("jax");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("aa.txt").getName()));
oos.writeObject(student);
oos.close();

反序列化student

1
2
3
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(new File("aa.txt")));
Student student2= (Student) ois.readObject();
ois.close();

此时的student2已经不是原来的student了,是一个新的Student对象了。当然这里没写serialVersionUID序列化和反序列也能成功运行,系统默认会计算出一个serialVersionUID。

当你要在Student类加入id属性加入,此时系统会计算出新的serialVersionUID,发序列化时,两者serialVersionUID不同,反序列操作时就会报错。所以一定要自定义一个serialVersionUID。

Parcelable

android api为我们提供的序列化类,也是要类实现Parcelable接口,重写带参数的构造方法,writeToParcel方法,describeContents方法和new CREATOR对象呢重写createFromParcel方法和newArray方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class Book implements Parcelable {

public static final Creator<Book> CREATOR = new Creator<Book>() {
@Override
public Book createFromParcel(Parcel source) {
return new Book(source);
}

@Override
public Book[] newArray(int size) {
return new Book[size];
}
};
public int bookId;
public String bookName;

public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}

protected Book(Parcel parcel) {
bookId = parcel.readInt();
bookName = parcel.readString();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
dest.writeString(bookName);
}

@Override
public int describeContents() {
return 0;
}

public int getBookId() {
return bookId;
}

public void setBookId(int bookId) {
this.bookId = bookId;
}

public String getBookName() {
return bookName;
}

public void setBookName(String bookName) {
this.bookName = bookName;
}
}

两者比较

  1. Serializable序列化同时产生大量临时变量,导致gc频繁;Serializable要通过io操作获取获取数据,再写入文件。
  2. Parcelable是以binder为信息载体,在内存传递上开销小。在读写数据时,Parcelable直接在内存读写,所以Parcelable性能比Serializable好。
  3. 将对象序列化写入文件,序列化对象进行网络传输建议选择Serializable,对象要在activity等组件传递时,建议选择Parcelable。

Java硬软弱虚引用,GC回收,内存碎片

發表於 2017-01-19   |  

Java硬软弱虚引用,GC回收,内存碎片

GarBageCollection

首先说一下java的gc垃圾回收机制,到底什么时候回收,在哪里回收。

经常说java分别在栈区和堆区存储变量等。其实还有

程序计数器

它是一个字节码的指示器,告诉当前线程下一步要执行哪一行代码。一个没有OOm的区域

栈区

又叫java虚拟机栈区,是每一个方法被执行的时候,创建出一个栈帧用来放的成员变量,操作链表,动态链接,方法出口。很多个栈帧又存储在栈区。

本地方法栈

如果说栈区是一个java的本地方法栈,那么本地方法栈就就是c++的native栈区

堆区

当类中创建实例变量,就会在堆区中分配内存,堆区又分为新生代,老年代。当新生代没有足够多内存实例对象就是OOM

方法区

用来存放被虚拟机加载的类信息,常量,静态变量。

运行时常量池

运行时常量池用来存放编译期间的常量

什么时候GC

  1. 在类中每当我们实例化一个变量时,都会在新生区申请足够的内存,如果申请的内存不足以实例化对象,这时候就会minor GC 小规模的回收。
  2. 在太多的对象在老年代,导致没有足够的内存空间加入对象时,就会full GC,并且直到老年代能放得下更大的对象。
  3. 每次minor gc都会检查一下进入老年代的对象和老年代剩余空间,如果不够就会full gc
  4. 手动执行System.gc();

内存碎片

内部碎片

分配内存到进程A,内存被进程占据了而不被利用,同时系统也无法利用这块内存,直到进程A被终结,释放内存。

外部碎片

还没被分配出去的内存太少了不足分配给下一个进程,又或者多个不连续的内存总空间长度能满足新申请的进程,但是由于地址是不连续的内存,无法分配给新进程。

Java硬软弱虚引用

硬引用

硬引用是我们用得最普遍的方式,就算应用程序内存不足,需要的内存大于可用的内存发生OOM程序崩溃,也不会去回收这个对象。

软引用

当内存足够就不会去回收这个对象,当内存不够就会去回收这个对象把引用对象加入SoftReference对象,把引用赋值成null,手动调用System.gc(),加不加入ReferenceQueue队列取决于内存够不够用。回收对象都会进入ReferenceQueue。

1
2
3
4
5
6
ReferenceQueue<Object> queue=new ReferenceQueue<Object>();
Object object =new Object();
SoftReference<Object> softReference=new SoftReference<>(object,queue);
obj=null;
System.gc();
System.out.println(queue.poll());//查看队列元素

弱引用

当回收器扫描出弱引用不管内存是否够用,都会回收这个对象。把弱引用对象加入WeakReference对象,把引用赋值成null,手动调用System.gc(),到最后的才会加入ReferenceQueue队列。回收对象都会进入ReferenceQueue。

1
2
3
4
5
6
ReferenceQueue<Object> queue=new ReferenceQueue<Object>();
Object object =new Object();
WeakReference<Object> softReference=new WeakReference<>(object,queue);
obj=null;
System.gc();
System.out.println(queue.poll());//查看队列元素

虚引用

当GC发现了虚引用对象把对象加到PhantomReference对象中,最后将虚引用赋值为null,再手动调用System.gc(),到最后的才会加入ReferenceQueue队列。回收对象都会进入ReferenceQueue。

1
2
3
4
5
6
ReferenceQueue<Object> queue=new ReferenceQueue<Object>();
Object object =new Object();
PhantomReference<Object> softReference=new PhantomReference<>(object,queue);
obj=null;
System.gc();
System.out.println(queue.poll());//查看队列元素

帧动画

發表於 2017-01-17   |  

帧动画

下面我们来说什么是帧动画。小时候有一种书的右下角把每一个动作画好,再快速的翻看,就可以看到一连串的动画了,这就是帧动画。
帧动画只要几张图片就能加载出动画效果了。其中帧动画是按照一定时间间隔显示一张图片。

在xml设置帧动画

具体实现在drawable下(而不是anim下),新建xml文件,用animation-list标签包着多个item标签,设置item标签的drawable和duration值。以imageview为载体可以在xml设置src和在类中用iamgeview.getDrawable获取AnimationDrawable,再调用start方法或者stop方法。

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="utf-8"?>
<!--android:oneshot="true"设置为true则播放一次动画,false则一直循环播放-->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">
<item android:drawable="@mipmap/ic_launcher"
android:duration="200"
/>
<item android:drawable="@mipmap/ic_launcher"
android:duration="200"
/>
</animation-list>
调用帧动画

写好xml文件我们就可以在类中通过以下方法来调用动画

1
2
3
mImageView.setImageResource(R.drawable.frame);
AnimationDrawable drawable = (AnimationDrawable) mImageView.getDrawable();
drawable.start();

属性动画第一话

發表於 2017-01-17   |  

Android属性动画(第一话)

3.0前的帧动画,补间动画

Android动画能给界面带来很炫的效果,如果我们要实现这些效果,在android3.0版本前实现动画主要有2种方式,帧动画(frame animation)和补间动画(tweened animation)。

帧动画加载大量图片,对性能有很大要求效率不高,补间动画是对view进行包括缩放,移动,旋转,透明度的绘制。因为补间动画实现不了动画操作后的view的点击等操作,只是简单在操作后的地方显示一个,并不会加上view原来的属性,比如一个button从父容器左上角移动到右下角,他的点击事件还在左上角。

介绍属性动画

为了解决上述问题,新推出了View的属性动画,原理是改变view的属性,所以我们可以操作缩放移动透明度旋转后的view,原理是在一段时间内不断设置View.setRotation(),下面我们来介绍一下ValueAnimator。

ValueAnimator

1
2
3
4
5
6
7
8
9
10
11
12
 //动画是200毫秒内view由0过渡到1
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);
valueAnimator.setDuration(200);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//监听输出动画移动的值
float value = (float) animation.getAnimatedValue();

}
});
valueAnimator.start();

生成ValueAnimator的方法除了ValueAnimator.ofFloat(float);参数要精确到小数点后几位,还有ValueAnimator.ofInt(int);参数是整型比如1,100。

ValueAnimator还有其他属性,比如设置延迟时间ValueAnimator.setStartDelay(200);设置延时200毫秒,还有循环次数
ValueAnimator.setRepeatCount(5);动画循环5次,又或者是动画播放模式正常ValueAnimator.RESTART还是反向播放的
ValueAnimator.setRepeatMode(ValueAnimator.REVERSE);发向播放动画。

ObjectAnimator

ObjectAnimator继承了ValueAnimator,所以ValueAnimator有的方法ObjectAnimator都有。ObjectAnimator是操作具体的控件比如button,imageview的动画,举几个例子:

图片从x轴的-500的位置移动到100的位置

1
2
3
4

ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(mImageView,"translationX",-500f,100f);
objectAnimator.setDuration(500);
objectAnimator.start();

透明度由1变成0再变成1的动画

1
2
3
4

ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(mImageView,"alpha",1f,0f,1f);
objectAnimator.setDuration(500);
objectAnimator.start();

旋转360度的动画

1
2
3
4

ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(mImageView,"rotation",0f,360f);
objectAnimator.setDuration(500);
objectAnimator.start();

y轴上缩放3倍的动画

1
2
3
4

ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(mImageView,"scaleY",1f,3f);
objectAnimator.setDuration(500);
objectAnimator.start();

如果你觉得单单实现一种动画还不够炫,如果你想同时实现多个动画,你要用到动画组合AnimatorSet

AnimatorSet

把多个ObjectAnimator按顺序连接起来,比如把上面的缩放,移动,设置透明度组合起来

1
2
3
4
5
6
7
8

ObjectAnimator scaleYAnimator=ObjectAnimator.ofFloat(mImageView,"scaleY",1f,3f);
ObjectAnimator translationXAnimator=ObjectAnimator.ofFloat(mImageView,"translationX",0f,100f);
ObjectAnimator alphaAnimator=ObjectAnimator.ofFloat(mImageView,"alpha",1f,0f,1f);
AnimatorSet animatorSet=new AnimatorSet();
animatorSet.play(scaleYAnimator).with(translationXAnimator).with(alphaAnimator);
animatorSet.setDuration(500);
animatorSet.start();

这里Animator.after将其他动画加到这个动画之后,还可以传入动画设置两个动画的间隔,Animator.with两个动画一起播放,Animator.before插入动画放在这个动画之前。

动画监听器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(mImageView,"scaleY",1f,3f);
objectAnimator.addListener(new Animator.AnimatorListener() {

@Override
public void onAnimationStart(Animator animation) {
//动画的时候
}

@Override
public void onAnimationEnd(Animator animation) {
//动画结束的时候
}

@Override
public void onAnimationCancel(Animator animation) {
//动画取消时
}

@Override
public void onAnimationRepeat(Animator animation) {
//动画循环时
}
});
objectAnimator.setDuration(500);
objectAnimator.start();

你也可以单独实现一个监听方法,这里的AnimatorListener改为AnimatorListenerAdapter就可以了

1
2
3
4
5
6
7
objectAnimator.addListener(new AnimatorListenerAdapter() {

@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});

设置XML动画

如果有多个界面的控件要实现相同的动画效果,我们可以通过xml更加有效率来设置动画。
在res/animator文件夹下新建animator.xml
(注意,res/anim这个文件夹是补间动画,res/drawable放帧动画)
根标签是一个 代表一个ObjectAnimator,标签内有duration动画时间,propertyName动画属性translationX,valueFrom原来的值,valueTo变化后的值,valueType值的类型是floatType还是intType这些属性.

标签代表一个AnimatorSet,在set标签内默认按照从上到下顺序加载不同的动画(就是在set设置android:ordering=”sequentially”),如果你想同步进行就设置android:ordering=”together”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially">
<objectAnimator
android:duration="500"
android:propertyName="scaleY"
android:valueFrom="100f"
android:valueTo="1f"
android:valueType="floatType"
/>
<set android:ordering="together">
<objectAnimator
android:duration="500"
android:propertyName="scaleY"
android:valueFrom="1f"
android:valueTo="100f"
android:valueType="floatType"
/>
</set>
</set>

xml代码写好了,然后实现可以在类中调用

1
2
3
Animator animator = AnimatorInflater.loadAnimator(mContext, R.animator.animator);
animator.setTarget(mImageView);
animator.start();

最后通过够用AnimatorInflate.loadAnimator,参数分别是Context和R.animator.animator

ViewPropertyAnimator

在android3.1系统推出了view通过调用animator方法来设置不同的动画

1
2
mImageView.animate().alpha(0f).setDuration(500);//这时候不用start即可
mImageView.animate().x(100).y(100).setDuration(500);//这时候不用start即可

但是这时候的链接不支持透明度从1f到0f再到1f。就算一个控件多次调用animate().alpha也会以最后一次动画为准。有点鸡肋。

总结

  1. 上述分别讲述了帧动画,补间动画,属性动画的ValueAnimator,ObejectAnimator 和AnimatorSet,还有属性动画的xml写法。

  2. 从性能效率上来看,优先考虑使用属性动画。

greenDAO

發表於 2016-11-22   |  

GreenDao

GreenDao3.1.0使用案例包含(增删查改,升级数据库),3.+版本比2.+更加便捷生成DaoMaster和DaoSession
本文项目地址

##首先让你的android studio配置Greendao数据库
在build.gradle目录下

1
2
3
4
5
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'org.greenrobot:greendao-gradle-plugin:3.1.0'

}

在app/build.gradle目录下设置

1
2
3
4
5
6
7
8
9
10
11
12
apply plugin: 'org.greenrobot.greendao'
android {
greendao{
schemaVersion 1 //数据库 版本号
targetGenDir 'src/main/java' //生成DaoMaster类文件夹
daoPackage 'com.ppjun.greendaotest.db' //生成DaoMaster类包名
}

}
dependencies {
compile 'org.greenrobot:greendao:3.1.0'
}

新建一个User类

1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
public class User {
@Id(autoincrement = true)
private Long id;
@Property(nameInDb = "username")
private String userName;
@Property(nameInDb = "password")
private String passWord;


//generate set和get方法 toString方法
...
}
  1. @Entity 代表数据库里面的USER表
  2. @Id 主键 ,autoincrement=true 从0开始自增长。
  3. @Property 表里面的内容
  4. @Unique 唯一的
  5. @Transient 不会被数据库持久化写进数据库
  6. @NotNull 不为空

到此为止,sync gradle来执行greendao配置,下面开始讲解怎么使用

##GreenDao使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static final String DB_NAME = "ppjun.db";//数据库名称
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context, DB_NAME, null);//实例化一个DevOpenhelper,相当于sqlit的SQliteOpenHelper
DaoMaster daoMaster = new DaoMaster(helper.getWritableDb());//实例化DaoMaster
DaoSession daoSession = daoMaster.newSession();//实例化DaoSession
UserDao userDao =daoSession.getUserDao(); //获取UserDao实例来对表user进行操作


//add,这里的null 代表自增长的id,你还可以为user表插入unique的userid
User user1 = new User(null, "ag1", "123456");
User user2 = new User(null, "ag2", "123456");
User user3 = new User(null, "ag3", "123456");
userDao.insert(user1);
userDao.insert(user2);
userDao.insert(user3);

//update,这里更新id是3的user的名字,id从1开始的,在where来添加匹配条件
User user4 = userDao.queryBuilder().where(UserDao.Properties.Id.eq(3)).build().unique();
user4.setUserName("kk");
userDao.update(user4);

//delete,这里删除id是2的user
List<User> userList2 = userDao.queryBuilder().where(UserDao.Properties.Id.eq(2)).build().list();
for (User user5 : userList2)
userDao.delete(user5);

//query,重新user表全部user
List<User> userList = userDao.queryBuilder().build().list();
for (User user : userList)
Log.i(TAG, user.toString());

上面完成数据库基本操作。

##下面来说GreenDao的升级数据库,在user表插入age

1、修改build.gradle下面的schemaVersion 2

2、在user类,新增age对象

1
2
3
4
5
6
7
public class User {
@Id(autoincrement = true)
private Long id;
@Property(nameInDb = "age")
private int age;
//generate getter and setter & toString
}

3、你要新建一个类MyDBHelper继承DaoMaster.OpenHelper,在类的构造函数传入Context,super(context,DB_NAME,null);还要重写onUpgrade方法(注意这里的参数一是Database),然后创建表(传入true,这里使用IF NOT EXISTS)不用担心表不存在,还有执行增加age列sql语句 db.exeSQL(“ALTER TABLE USER ADD COLUMN age”);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyDBHelper extends DaoMaster.OpenHelper {
public MyDBHelper(Context context) {
super(context, DB_NAME,null);
}

@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
super.onUpgrade(db, oldVersion, newVersion);
NoteDao.createTable(db,true);
db.execSQL("ALTER TABLE NOTE ADD COLUMN age");
}


}

这时候的DaoMaster.DevOpenHelper改为自定义DBHelper,这样子升级数据库就不会丢失原来的数据了

1
2
DBHelper dbHelper = new DBHelper(context);
DaoMaster daoMaster = new DaoMaster(dbHelper.getWritableDb());

本文项目地址

How to use retrofit2?

發表於 2016-11-21   |  

retrofit2.1

retrofit安全的http客户端for Android和java.

如何使用Retrofit

在app/build.gradle

1
2
3
4
5
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.2.1'

新建Git包,含括Git.java ,GitApi.java 和GitService.java

1
2
3
Git.java(单例类,包括retrofit GitService的实例化)
GitApi.java (请求需要的URl)
GitService.java (各种get post方法)

Git.java

  1. 新建单例类Git 私有化构造函数, 新建public static final Git mGit; 和public static Git getInstane()的方法

  2. 新建全局变量mGitService ,和getService的方法返回mGitService???

  3. 在Git的构造函数需要实例化 retrofit主要用到几个参数包括url,okhttpClient,new GsonConverterFactory?RxJavaCallAdapterFactory ,还要实例化GitService。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public class Git {
    private static volatile Git mInstance = new Git();
    private GitService mGitService;

    private Git() {

    OkHttpClient.Builder client= new OkHttpClient().newBuilder();
    OkHttpClient c= setCertificates(client,new Buffer().writeUtf8(GitApi.CER).inputStream()).build();
    Retrofit retrofit = new Retrofit.Builder().baseUrl(GitApi.BASE_URL)
    .client(c)
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .build();
    mGitService = retrofit.create(GitService.class);
    }

    public static Git getInstance() {

    if (mInstance == null) {
    Git mIns = mInstance;
    synchronized (Git.class) {

    if (mIns == null) {

    mIns = new Git();
    mInstance = mIns;
    }
    }
    }
    return mInstance;
    }

    public GitService getGitService() {
    return mGitService;
    }
    }

    ​

GitApi.java

这里的URL需要注意要以/结尾 要以/结尾 要以/结尾。这样子GitService注解里面的就不用/开头了

1
public static final String BASE_URL="https://api.github.com/";

GitService.java

要写这个类首先学会@GET @POST @FormUrlEncoded这些注解。

1
2
3
4
5
6
7
8
9
10
11
12
@GET("users/{user}/repos")
Call<List<Repos>> listRepos(@Path("user") String user);

@GET
Call<String> get(@Url String url);


@POST
@FormUrlEncoded
Call<GitReturnCode> init(@Url String url,
@Field("id") String id,
@Field("key") String key);

详细的各种注解要看这里retrofit注解的使用

最后在Presenter层调用方法,返回List

1
2
3
4
5
6
7
8
9
10
11
12
Git.getInstance().getGitService().listRepos("gdmec07120731").enqueue(new Callback<List<Repos>>() {
@Override
public void onResponse(Call<List<Repos>> call, Response<List<Repos>> response) {

Log.i("TAG", response.body().get(0).getName());
}

@Override
public void onFailure(Call<List<Repos>> call, Throwable t) {
Log.i("TAG", t.toString());
}
});
1234…6
区汇君

区汇君

34 文章
26 標籤
GitHub Weibo
© 2015 - 2017 区汇君
由 Hexo 強力驅動
主題 - NexT.Pisces