我使用BeanShell来动态管理我的android应用程序中的界面和内容。今天我遇到了以下问题:我需要为应用程序处理一个结构未知的类,即服务器发送代码,应用程序处理它。
下面是我的一个代码处理程序。错误报告给">公共类LastNews{":
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.graphics.Color;
import android.view.ViewGroup;
import android.util.TypedValue;
import android.graphics.Typeface;
import java.util.Random;
import android.view.View;
import android.widget.Toast;
import apppackege.ViewCreator;
import apppackege.Calculate;
import android.widget.GridView;
import android.widget.BaseAdapter;
import apppackege.AdapterCreator;
import apppackege.IconName;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import apppackege.WrappingGridView;
import java.util.ArrayList;
import apppackege.Decoder;
import apppackege.LoadImage;
import android.widget.ImageView;
LinearLayout topPanel = ViewCreator.linearLayout(context, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
Calculate.dpToPixel(context, 40)), LinearLayout.HORIZONTAL);
topPanel.setBackgroundColor(Color.parseColor("#1E88E5"));
LinearLayout bottomPanel = ViewCreator.linearLayout(context, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
Calculate.dpToPixel(context, 40)), LinearLayout.HORIZONTAL);
bottomPanel.setBackgroundColor(Color.parseColor("#EFEFEF"));
ScrollView scrollView = ViewCreator.scrollView(context, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, 1.0f));
scrollView.setBackgroundColor(Color.WHITE);
parent.addView(topPanel);
parent.addView(scrollView);
parent.addView(bottomPanel);
LinearLayout scrollLayout = ViewCreator.linearLayout(context,
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT), -1);
scrollView.addView(scrollLayout);
ImageView topImage = ViewCreator.imageView(context, null, null);
new LoadImage(topImage, "https://url.com/9tVFtRoOCIQ.jpg");
scrollLayout.addView(topImage);
WrappingGridView wrappingGridView = ViewCreator.wrappingGridView(context, null, 3);
scrollLayout.addView(wrappingGridView);
String jsonIconName = "[{"icon":"https://url.com/thumb-up.png","name":"ГОЛОС","iconColor":"#1E88E5"},{"icon":"https://url.com/news.png","name":"НОВОСТИ","iconColor":"#1E88E5"},{"icon":"https://url.com/camping-tent.png", "name": "ТУРИЗМ","iconColor":"#1E88E5"},{"icon":"https://url.com/image.png","name":"ФОТО","iconColor":"#1E88E5"},{"icon":"https://url.com/cafe.png","name":"МЕСТА","iconColor":"#1E88E5"},{"icon":"https://url.com/user.png","name":"АККАУНТ","iconColor":"#1E88E5"},{"icon":"https://url.com/cinema-.png","name":"АФИША","iconColor":"#1E88E5"},{"icon":"https://url.com/focal-length.png","name":"КОНТРОЛЬ","iconColor":"#1E88E5"},{"icon":"https://url.com/chase.png","name":"ОХОТА","iconColor":"#1E88E5"}]";
BaseAdapter baseAdapter = AdapterCreator.baseAdapterIconName(context, Decoder.fromJsonArray(jsonIconName, IconName.class));
wrappingGridView.setAdapter(baseAdapter);
((BaseAdapter)wrappingGridView.getAdapter()).notifyDataSetInvalidated();
TextView lineActual = ViewCreator.textView(context, "АКТУАЛЬНО",
null, 10, 14, "#1E88E5", new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(context, "АКТУАЛЬНО", Toast.LENGTH_SHORT).show();
}
});
scrollLayout.addView(lineActual);
TextView lineNews = ViewCreator.textView(context, "СВЕЖИЕ НОВОСТИ",
null, 10, 14, "#1E88E5", new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(context, "СВЕЖИЕ НОВОСТИ", Toast.LENGTH_SHORT).show();
}
});
scrollLayout.addView(lineNews);
String jsonNews = " [ { "id": "89e94f07-2939-11ec-a3ee-e145f6ad5670", "head": "Белорус сделал предложение Бузовой в прямом эфире X Factor", "icon": "http://url.com/73fde9f1-a72f-43c0-a6e7-10957e216a9b.jpg", "type": "http://url.com/info.png", "location": "Беларусь" }, { "id": "c2833cf1-2928-11ec-a3ee-e145f6ad5670", "head": "Жители Приморья стоят в очередях за белорусскими продуктами - Богданов", "icon": "http://url.com/77e75355-4255-4cae-9962-fdb7394986c5.jpg", "type": "http://url.com/info.png", "location": "Беларусь" }, { "id": "c2833cf0-2928-11ec-a3ee-e145f6ad5670", "head": "Помолодел и стал жестким – глава Минздрава о четвертой волне коронавируса", "icon": "http://url.com/f28b5349-e639-4250-9391-7ad88fcf4946.jpg", "type": "http://url.com/info.png", "location": "Беларусь" }, { "id": "c2833cef-2928-11ec-a3ee-e145f6ad5670", "head": "Так было или не было? Серега ответил о своем романе с Бузовой", "icon": "http://url.com/10-2021/60cc9d51-f570-4e68-bada-4ba4aab92bcb.jpg", "type": "http://url.com/info.png", "location": "Минск" }, { "id": "6088c966-2920-11ec-a3ee-e145f6ad5670", "head": "Работа ТЭЦ в Минске восстановлена - Минэнерго", "icon": "http://url.com/01b6db5f-8305-4e86-9d9a-f59cc2be2787.jpg", "type": "http://url.com/info.png", "location": "Минск" } ]";
public class LastNews{
@SerializedName("id")
public String id;
@SerializedName("head")
public String head;
@SerializedName("icon")
public String icon;
@SerializedName("type")
public String type;
@SerializedName("location")
public String location;
}
LinearLayout listNews = ViewCreator.linearLayout(context, null, -1);
ArrayList<Object> news = Decoder.fromJsonArray(jsonNews, LastNews.class);
for(int i = 0; i < news.size(); i++){
LastNews lastNews = (LastNews) news.get(i);
//crate view and add to "listNews"
}
错误信息是:
Sourced file: inline evaluation of: ``import android.widget.LinearLayout; import android.widget.ScrollView; . . . '' unknown error: can't load this type of class file : at Line: 75 : in file: inline evaluation of: ``import android.widget.LinearLayout; import android.widget.ScrollView; . . . '' : public class LastNews {
你能告诉我这样的实现是否可能使用BeanShell吗?如果是这样的话,有可能有一个例子,这样的功能吗?
可能,但不是通过发送类文件的文本。Java是一种编译语言。您需要发送.class文件,或者最新的android Java解释器使用的等效文件(它仍然是.dex吗?)然后需要通过自定义类加载器加载它。基本上你要做的是黑魔法,真的需要了解Java,它的类结构,以及解释器是如何工作的。
关于这个的几个警告:
1)它将不允许在Google play。Google不允许在应用程序中动态加载代码。
这是一个巨大的安全漏洞。这就是为什么#1是这样的原因之一。
3)随着时间的推移,随着代码的变化,它成为bug的主要来源。现在你要担心的不仅仅是"我的释放是否有效"。但是,"我的发布是否可以与下载代码的每个可能版本进行交互?"还有"如果跳过了一个版本,即使跳过了一个版本,数据结构是否仍然兼容"。这里有额外的安全漏洞的可能性。
根据提供给我的信息。我做了最方便的决定。我将类本身排除在处理之外。
因此,现在我将使用"Object"本身,为其进一步加工。如果将来有人需要类似的解决方案,那么在我看来,最简洁的方法就是使用"object"这样的对象。和"LinkedTreeMap".
这是我最终绘制的结果,下面我将展开修改后的示例代码:
//...here is all the imported data
//...the code from my first example
String jsonNews = " [{"id":"89e94f07-2939-11ec-a3ee-e145f6ad5670","head":"Белорус сделал предложение Бузовой в прямом эфире X Factor", "icon": "http://45.147.199.147/IMAGES/FOTO/10-2021/73fde9f1-a72f-43c0-a6e7-10957e216a9b.jpg", "type": "http://45.147.199.147/IMAGES/FOTO/ICONS/info.png", "location": "Беларусь" }, { "id": "c2833cf1-2928-11ec-a3ee-e145f6ad5670", "head": "Жители Приморья стоят в очередях за белорусскими продуктами - Богданов", "icon": "http://45.147.199.147/IMAGES/FOTO/10-2021/77e75355-4255-4cae-9962-fdb7394986c5.jpg", "type": "http://45.147.199.147/IMAGES/FOTO/ICONS/info.png", "location": "Беларусь" }, { "id": "c2833cf0-2928-11ec-a3ee-e145f6ad5670", "head": "Помолодел и стал жестким – глава Минздрава о четвертой волне коронавируса", "icon": "http://45.147.199.147/IMAGES/FOTO/10-2021/f28b5349-e639-4250-9391-7ad88fcf4946.jpg", "type": "http://45.147.199.147/IMAGES/FOTO/ICONS/info.png", "location": "Беларусь" }, { "id": "c2833cef-2928-11ec-a3ee-e145f6ad5670", "head": "Так было или не было? Серега ответил о своем романе с Бузовой", "icon": "http://45.147.199.147/IMAGES/FOTO/10-2021/60cc9d51-f570-4e68-bada-4ba4aab92bcb.jpg", "type": "http://45.147.199.147/IMAGES/FOTO/ICONS/info.png", "location": "Минск" }, { "id": "6088c966-2920-11ec-a3ee-e145f6ad5670", "head": "Работа ТЭЦ в Минске восстановлена - Минэнерго", "icon": "http://45.147.199.147/IMAGES/FOTO/10-2021/01b6db5f-8305-4e86-9d9a-f59cc2be2787.jpg", "type": "http://45.147.199.147/IMAGES/FOTO/ICONS/info.png", "location": "Минск" } ]";
LinearLayout listNews = ViewCreator.linearLayout(context, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT), LinearLayout.VERTICAL);
ArrayList news = Decoder.fromJsonArray(jsonNews, null);
for(int i=0; i < news.size(); i++){
TextView newsHead = ViewCreator.textView(context, news.get(i).get("head"),
null, 10, 14, "#1E88E5", new View.OnClickListener() {
public void onClick(View v) {
Toast.makeText(context, news.get(i).get("id"), Toast.LENGTH_SHORT).show();
}
});
listNews.addView(newsHead);
}
scrollLayout.addView(listNews);
请注意json的转换方式,它被转换成一个对象数组,其中每个对象都是一个"LinkedTreeMap"
public class Decoder {
public static ArrayList<Object> fromJsonArray(String json, Class typeClass){
try{
if(typeClass != null) {
return new Gson().fromJson(json, TypeToken.getParameterized(List.class, typeClass).getType());
}
return new Gson().fromJson(json, new TypeToken<List<Object>>() {}.getType());
} catch (Exception ex){
return new ArrayList<>();
}
}
}
最初,我的测试类有这样一个任务:
public class LastNews{
@SerializedName("id")
public String id;
@SerializedName("head")
public String head;
@SerializedName("icon")
public String icon;
@SerializedName("type")
public String type;
@SerializedName("location")
public String location;
}
现在,当使用"LinkedTreeMap"元素中,要获取其变量,可以使用以下代码(类似于"[]")括号中):
news.get(i).get("head")
总之,我想说这个解决方案有一个更紧凑的形式,因为不需要传输和存储类。我想补充的是,应用程序的任务是尽可能地安全,以尽可能地排除黑客攻击的可能性。毕竟,应用程序将处于状态级别。
也许目前我的决定是不正确的。我以后很可能会面临很多问题。