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();
}
}