یک کار گروهی برای یادگیری Reflection
بعضی از دوستان هستند که من بهشون این راه رو یاد دادم، پس اونها چیزی ننویسن، کسانی که تحقیق می کنن بنویسن تا با تحقیق به نتیجه برسید.
داخل متد parseGui رو به نحوی پر کنید که خودش بره برای شما عناصر UI نام برده شده در کلاس Ui رو بگیره، به نوع مناسبش Cast کنه و داخل فیلد بریزه. نصف راه رو من می نویسم:
public SampleActivity extends Activity {
public Ui ui;
public class Ui {
public TextView txtTitle;
public Button btnAction;
public Ui(View view){
HelperUi.parseGui(view);
}
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.some_layout);
ui = new Ui(getWindow().getDecoreView());
ui.btnAction.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
ui.txtTitle.setText("Sample");
}
});
}
}
این راه رو پیشنهاد میدم
public class ReflectionSampleActivity extends Activity {
public TextView txtSample;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
UiParser.parse(this);
txtSample.setText("Hi! from java reflection ...");
}
}
با داشتن اکتیویتی و ارسالش به parser میشه به این مقصود رسید
public class UiParser {
private static Hashtable<Class<? extends Activity>, StructCachedActivity> _cacheViews =
new Hashtable<Class<? extends Activity>, StructCachedActivity>();
public static void parse(Activity activity) {
if (_cacheViews.containsKey(activity.getClass())) {
loadFields(_cacheViews.get(activity.getClass()), activity);
return;
}
StructCachedActivity cachedActivity = new StructCachedActivity();
cachedActivity.activity = activity.getClass();
cachedActivity.view = activity.getWindow().getDecorView();
Field[] fields = activity.getClass().getDeclaredFields();
for (Field field : fields)
cachedActivity.fields.put(field.getName(), field);
cachedActivity.context = activity.getBaseContext();
if (cachedActivity.context != null)
cachedActivity.resources = cachedActivity.context.getResources();
getAllViews(cachedActivity, cachedActivity.view);
_cacheViews.put(activity.getClass(), cachedActivity);
loadFields(cachedActivity, activity);
}
private static void loadFields(StructCachedActivity cachedActivity,
Activity activity) {
try {
for (String key : cachedActivity.fields.keySet()) {
Field field = cachedActivity.fields.get(key);
View control = cachedActivity.controls.containsKey(key) ? cachedActivity.controls
.get(key) : null;
if (control.equals(null))
continue;
field.set(activity, cachedActivity.controls.get(key));
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void getAllViews(StructCachedActivity activity, View root) {
String id = getId(activity, root);
if (!id.equals(""))
activity.controls.put(getId(activity, root), root);
if (root instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) root;
for (int i = 0; i < viewGroup.getChildCount(); i++)
getAllViews(activity, viewGroup.getChildAt(i));
}
}
private static String getId(StructCachedActivity activity, View view) {
String entryName = "";
int id = view.getId();
if (id == 0xffffffff)
return entryName;
if (activity.resources != null)
entryName = activity.resources.getResourceEntryName(id);
return entryName;
}
}
به این خاطر که اکتیویتی های برنامه در زمان اجرا تغییری نمیکنن یه سیستم کش در نظر میگیریم که سربار رو به حد اقل برسونیم. سیستم کش این ساختار رو داره :
public class StructCachedActivity {
public StructCachedActivity() {
controls = new Hashtable<String, View>();
fields = new Hashtable<String, Field>();
}
public Class<? extends Activity> activity;
public View view;
public Context context;
public Resources resources;
public Hashtable<String, Field> fields;
public Hashtable<String, View> controls;
}
تنها نکته اینه که فیلد همنام آیدی کنترل و به صورت public تعریف میشه
با توجه به تدوین شدن موضوع سئوال در آموزشها ویدئویی، ابتدا آنرا مطالعه و تمرین کنید و سپس برای تمرین خودتان به اهداف زیر برسید:
اهداف قابل رسیدن
- دسترسی به فیلدهای هر کلاسی که خواستید و نه تنها کلاسی که از آن extends شده است.
- دسترسی به فیلدهای Private هر کلاسی که خواستید.
- صدا زدن یک متد static و یک متد non-static از یک کلاس دلخواه.
- گرفتن لیست متدهای داخل یک کلاس.
- گرفتن لیست متدهای final شده یک کلاس.
- ساخت یک annotation اختصاصی.
- پیدا کردن تمامی فیلدهایی که دارای annotation خاصی هستند.
- پیدا کردن تمامی متدهایی که دارای annotaion خاصی هستند.
- ذکر چند parameter برای annotation و دسترسی با reflection به خواص آن.
- ...
زمان معقول برای پیاده سازی تمامی امکانات بالا و مسلط شدن به آن
حدود 3 ماه روزی 8 ساعت
تمرینی که استاد تعریف کردند رو من به صورت زیر نوشتم اما احتمالا مشکلاتی داره یا اصلا اون چیزی نیست که استاد مدنظرشون بود چون خیلی زودتر از اون زمانی که استاد تعیین کردند نوشتم. خوشحال میشم مشکلاتش رو بگید یا اگر راه بهتری هست معرفی کنید.
public class Helper {
private static Object classInstance = null;
private static String string = null;
// 1, 2
public Object getMyField(Class<?> clazz, String fieldName) {
Object myField = null;
try {
for (Field field: clazz
.getClassLoader()
.loadClass(clazz.getName())
.getDeclaredFields()) {
field.setAccessible(true);
if (field.getName().equals(fieldName)) {
if (classInstance == null || !string.equals(clazz.getSimpleName())) {
string = clazz.getSimpleName();
classInstance = clazz.newInstance();
}
myField = field.get(classInstance);
}
}
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InstantiationException e) {
e.printStackTrace();
}
return myField;
}
// 1, 2
public void setMyField(Class<?> clazz, String fieldName, Object newValue) {
try {
for (Field field: clazz
.getClassLoader()
.loadClass(clazz.getName())
.getDeclaredFields()) {
field.setAccessible(true);
if (field.getName().equals(fieldName)) {
if (classInstance == null || !string.equals(clazz.getSimpleName())) {
string = clazz.getSimpleName();
classInstance = clazz.newInstance();
}
field.set(classInstance, newValue);
}
}
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InstantiationException e) {
e.printStackTrace();
}
}
// 3
public void invokeMyMethod(Class<?> clazz, String methodName, Object[] methodParameters) {
try {
for (Method method: clazz
.getClassLoader()
.loadClass(clazz.getName())
.getDeclaredMethods()) {
method.setAccessible(true);
if (method.getName().equals(methodName)) {
method.invoke(clazz.newInstance(), methodParameters);
}
}
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
catch (IllegalArgumentException e) {
e.printStackTrace();
}
catch (IllegalAccessException e) {
e.printStackTrace();
}
catch (InvocationTargetException e) {
e.printStackTrace();
}
catch (InstantiationException e) {
e.printStackTrace();
}
}
// 4
public String getMyMethodList(Class<?> clazz) {
String methodsName = "No Method Found";
try {
for (Method method: clazz
.getClassLoader()
.loadClass(clazz.getName())
.getDeclaredMethods()) {
method.setAccessible(true);
methodsName = methodsName + method.getName() + ",";
}
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return methodsName;
}
// 5
public String getMyFinalMethodList(Class<?> clazz) {
String methodsName = "No Method Found";
try {
for (Method method: clazz
.getClassLoader()
.loadClass(clazz.getName())
.getDeclaredMethods()) {
method.setAccessible(true);
if (Modifier.isFinal(method.getModifiers())) {
methodsName = methodsName + method.getName() + ",";
}
}
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return methodsName;
}
// 7
public String findMyFieldAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClazz) {
String fieldsName = "No Field Found";
try {
for (Field field: clazz
.getClassLoader()
.loadClass(clazz.getName())
.getFields()) {
field.setAccessible(true);
if (field.isAnnotationPresent(annotationClazz)) {
try {
fieldsName = fieldsName + field.getName() + ",";
}
catch (Throwable e) {
e.printStackTrace();
}
}
}
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return fieldsName;
}
// 8
public String findMyMethodAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClazz) {
String methodsName = "No Method Found";
try {
for (Method method: clazz
.getClassLoader()
.loadClass(clazz.getName())
.getDeclaredMethods()) {
method.setAccessible(true);
if (method.isAnnotationPresent(annotationClazz)) {
try {
methodsName = methodsName + method.getName() + ",";
}
catch (Throwable e) {
e.printStackTrace();
}
}
}
}
catch (SecurityException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return methodsName;
}
}
پاسخگویی و مشاهده پاسخ های این سوال تنها برای اعضای ویژه سایت امکان پذیر است .
چنانچه تمایل دارید به همه بخش ها دسترسی داشته باشید میتوانید از این بخش لایسنس این آموزش را خریداری نمایید .