1.要实现动态接口必须了解几个定义:
注解:
定义注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
元注解:负责描述注解的注解
1.@Target :标记注解用于描述什么,可以使方法,属性等等…
2.@Retention:定义注解保留的时间
3.@Documented:用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
4.@Inherited:元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。- 反射:通过.class类的描述类,直接生成对象,直接查找修改类的属性,方法,静态变量.
2.动态接口
目标:在通过网络 访问数据接口,并且对返回的json处理,添加在安卓控件过程中,封装一个工具类,将需要传递的url写在一个自定义的接口(内含一个传参方法)里传入(通过注解传入固定不变的部分,通过接口中某个方法传递进一个可变参数),通过工具类实例化接口,并在调用接口方法的时候执行代理invoke方法,实现网络加载,具体代码如下.
- 代理类:
public class Tools {
public static<T> T getInstance(Class<T> type){
Object o = Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, new MyHandler());
return ((T) o);
}
private static class MyHandler implements InvocationHandler{
/**
* invoke 方法在生成的接口对象调用其中方法的时候调用
* @param proxy 代理:通过代理把下面方法加载进去
* @param method 要加载的方法
* @param args 要加载的方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
UrlString annotation = method.getAnnotation(UrlString.class);
if (annotation != null) {
String url = String.format(Locale.CHINA, annotation.value(), args);
Class<?> returnType = method.getReturnType();
if (returnType.equals(DownWebTask.class)) {
ParameterizedType type = (ParameterizedType) method.getGenericReturnType();
Type entryType = type.getActualTypeArguments()[0];
return new DownWebTask<>(url, ((Class) entryType));
}
}
return null;
}
}
}
2.网络加载工具:
public class DownWebTask<T> extends AsyncTask<DownWebTask.Callback<T>,Void,Object> {
private static final String TAG = DownWebTask.class.getSimpleName();
//传入参数 中间过程数据 返回值
private String url;
private Callback callback;
private Class<T> t;
public interface Callback<S>{
void onSuccess(S t);
void onFail(Exception e);
}
public DownWebTask(String url, Class<T> t) {
this.url = url;
this.t = t;
}
@Override
protected Object doInBackground(Callback<T>... params) {
callback=params[0];
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("GET");
connection.setDoInput(true);
int responseCode = connection.getResponseCode();
if (responseCode==200){
InputStream inputStream = connection.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int len;
byte[] bytes = new byte[102400];
while ((len=inputStream.read(bytes))!=-1){
byteArrayOutputStream.write(bytes, 0, len);
}
String s = byteArrayOutputStream.toString("UTF-8");
// Log.d(TAG, "doInBackground: "+s);
return new Gson().fromJson(s,t);
}else {
return new RuntimeException("网络错误,responseCode "+responseCode);
}
} catch (IOException e) {
return e;
}
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
if (t.isInstance(o)){
callback.onSuccess(((T) o));
}else if (o instanceof Exception){
callback.onFail(((Exception) o));
}
}
}
3.自定义注解(用于修饰自己的接口)
//修饰注解的注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UrlString {
String value();
}
4.数据实体类
public class Entry {
@SerializedName("message")
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
5.主程序
public class MainActivity extends AppCompatActivity implements DownWebTask.Callback<Entry>{
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text);
Object instance = Tools.getInstance(DataInterface.class);
((DataInterface) instance).getShow(9987).execute(this);
}
@Override
public void onSuccess(Entry t) {
mTextView.setText(t.getMessage());
}
@Override
public void onFail(Exception e) {
Toast.makeText(MainActivity.this, "网络异常", Toast.LENGTH_SHORT).show();
}
}