Android:确定代码应该驻留在活动视图还是自定义视图中
随着我对活动和自定义视图的熟悉,我一直在决定与视图及其父活动相关的代码应该放在哪里。需要两者都访问的附加自定义对象,关于如何构造代码的选项是无穷无尽的。以下是我的问题的细节:Android:确定代码应该驻留在活动视图还是自定义视图中,android,Android,随着我对活动和自定义视图的熟悉,我一直在决定与视图及其父活动相关的代码应该放在哪里。需要两者都访问的附加自定义对象,关于如何构造代码的选项是无穷无尽的。以下是我的问题的细节: 相关类/文件: GameActivity扩展活动:它使用的布局包含一些自定义视图 MapView扩展视图:这包含在GameActivity使用的布局中 世界:定义自定义世界对象的自定义类 预期结果: GameActivity调出包含MapView的布局。MapView的onDraw()函数使用来自世界对象的信息在画布上绘制
相关类/文件:
GameActivity扩展活动:它使用的布局包含一些自定义视图
MapView扩展视图:这包含在GameActivity使用的布局中
世界:定义自定义世界对象的自定义类
预期结果:
GameActivity调出包含MapView的布局。MapView的onDraw()函数使用来自世界对象的信息在画布上绘制地图
问题:
MapView所需的世界对象是从以前保存的文件加载的。我可以通过多种不同的方式将该对象放到地图视图中,这就是我犹豫不决的地方。我已经经历了以下迭代。(注意,它们都是有效的。我要寻找的是一种方法优于另一种方法的理由。)
版本1:
游戏活动:它所做的只是设置内容布局(layout_.xml中带有映射视图的布局)
MapView:具有从文件加载世界对象的所有代码,并使用它引用所需的图形参数
World:一个简单的自定义类,其构造函数中有3个参数
然后,我决定从文件加载World对象应该是World类本身的一个方法,而不是MapView的onCreate()方法。由于加载世界文件是在没有世界对象的情况下永远不会做的事情,所以它应该是类方法。因此,我在世界类中创建了一个loadWorld(stringworld\u name)方法。现在文件看起来像这样: 版本2:
游戏活动:它所做的只是设置内容布局(layout_.xml中带有映射视图的布局)
MapView:使用构造函数创建一个新的世界对象,然后调用它的loadWorld()方法以使用文件信息更新它
World:一个简单的自定义类,在其构造函数中包含3个参数,以及一个loadWorld()方法
最后,我决定MapView中只应包含绘图活动。拥有一个世界物体的全部意义就是能够传递它,对吗?因此,我将World construction/loading从视图中移到活动中。这导致必须在MapView中创建setter方法,以便能够从创建World对象的父活动传递该对象 版本3:
GameActivity:设置布局,创建一个世界对象,并调用它的loadWorld()方法从文件中加载它。按Id引用MapView,然后调用MapView的setWorld()方法,以通过传递World对象的实例
地图视图:从外部设置世界对象。使用此对象的信息绘制地图
World:一个简单的自定义类,在其构造函数中包含3个参数,以及一个loadWorld()方法。
好的,这就是我目前的处境。我的问题是,尽管我喜欢我所选择的约定,即视图只包含与绘图相关的代码,并将与类相关的方法保留在它们自己的类中——似乎当我切换到该方法时,我突然更频繁地创建临时对象,并将对象从一个活动传递到另一个活动,再到视图等等。这看起来开销要大得多,但同时这也是整个抽象点,对吗?抽象出一个类,这样您就可以从中实例化一个对象并传递它。然而,在我看来,抽象出的东西越多,处理对象就变得越复杂 我想我想问的是,我不从MapView本身的文件中加载世界,是否会让事情变得更复杂?我只是固执地不想让代码涉及到从视图类中的文件读取对象吗?把它放在自己的课堂上或活动中会更好吗?在做出这些决定时,我需要考虑什么?有没有一个我甚至都不知道的解决我进退两难的办法 我认为答案将是个人偏好,但我想知道是否存在以这种或那种方式做这件事的惯例,或者是否有确凿的理由来构建某种方式。我一直在试图寻找这个问题的答案,但我认为我使用了错误的搜索词。我经常遇到一些描述如何构造活动/视图结构的东西,但对其中的代码一无所知。当有代码时,不可避免地会有人教你如何在活动之间传递数据,或者在活动和视图之间传递数据,等等。我知道所有这些方法。我只是不知道该用哪一个 我一直在看的一些链接:
编辑:包含有关应用程序结构和代码示例的更多详细信息 游戏活动:
/*IMPORT STATEMENTS REMOVED*/
public class GameActivity extends Activity implements OnTouchListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
Log.d("LOGCAT", "GameActivity Started");
//get the world_name from MenuActivity
Intent intent = getIntent();
String world_name = intent.getStringExtra(MenuActivity.EXTRA_MESSAGE);
//load the world
World world = loadWorld(world_name);
//create a tilemap and get the tile translator array from it
//need to convert this to a static Map
TileMap tileMap = new TileMap(this);
Map<Integer,Bitmap> tileTranslator = tileMap.getTileTranslator();
//Create a reference to the MapView object and set the translator
MapView mapView = (MapView) findViewById(R.id.map_view);
mapView.setArgs(world, tileTranslator);
//implement the OnTouchSwipeListener
mapView.setOnTouchListener(new OnSwipeTouchListener() {
/*CODE REMOVED*/
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
public World loadWorld(String world_name) {
//Create a dummy world to load into - why?!
World dummy_world = new World();
//load the world
Log.d("LOGCAT", "Loading the World");
try {
World world = dummy_world.loadWorld(this, world_name);
return world;
} catch (IOException e) {
//do nothing!
} catch (ClassNotFoundException f) {
//do nothing!
}
return dummy_world; //if world load fails, send back the default world
// NOTE: it's not saved!!!
}
}
/*已删除导入语句*/
公共类GameActivity扩展了活动实现OnTouchListener{
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
Log.d(“LOGCAT”,“游戏活动开始”);
//从MenuActivity获取世界名称
Intent=getIntent();
String world_name=intent.getStringExtra(MenuActivity.EXTRA_消息);
//载入世界
世界世界=负荷世界(世界名称);
//创建一个tilemap并从中获取tile转换器数组
//需要将其转换为静态映射
TileMap TileMap=新TileMap(此);
Map TiletTranslator=tileMap.getTileTranslator();
//创建对MapView对象的引用并设置转换器
MapView MapView=(MapView)findViewB
/*IMPORT STATEMENTS REMOVED*/
public class MapView extends View implements OnClickListener {
protected Context context;
public World world;
public Map<Integer,Bitmap> tileTranslator;
//hardcoded variables for testing
private int tile_width = 50;
private int tile_height = 50;
public int screen_width = 12;
public int screen_height = 6;
public int playerX = 4;
public int playerY = 7;
public MapView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
Log.d("LOGCAT", "MapView created");
setOnClickListener(this);
}
@Override
public void onDraw(Canvas canvas) {
/*CODE REMOVED*/
}
//ugly method, need to break it out into individual setters
public void setArgs(World world, Map<Integer,Bitmap> tileTranslator){
this.world = world;
this.tileTranslator = tileTranslator;
}
}
/*IMPORT STATEMENTS REMOVED*/
public class World implements Serializable {
public String world_name;
public int world_width;
public int world_height;
public int[][] world_map;
public World() { //default world - I don't even want this constructor here!
world_name = "default_world";
world_width = 1;
world_height = 1;
world_map = createWorld(world_width, world_height);
}
public World(String world_name, int world_width, int world_height) {
//set the world attributes
this.world_name = world_name;
this.world_width = world_width;
this.world_height = world_height;
//generate the map
world_map = createWorld(world_width, world_height);
}
private int[][] createWorld(int world_width, int world_height) {
//create a local tile map
int[][] world_map = new int[world_width][world_height];
//get a randomizer to fill the array with - {temporary solution}
Random rand = new Random();
//fill the tile map array with random numbers between 0 and 2
for(int row = 0; row < world_map.length; row++) {
for (int col = 0; col < world_map[row].length; col++) {
world_map[row][col] = rand.nextInt(3); //static number, needs variable!
//3 is the number of tile types
}
}
return world_map;
}
public void saveWorld(Context context, String world_name, World world) throws IOException {
FileOutputStream fos = context.openFileOutput(world_name, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(world);
oos.close();
}
public World loadWorld(Context context, String world_name) throws IOException, ClassNotFoundException {
FileInputStream fis = context.openFileInput(world_name);
ObjectInputStream ois = new ObjectInputStream(fis);
World world = (World)ois.readObject();
/*this.world_name = world.world_name;
this.world_width = world.world_width;
this.world_height = world.world_height;
this.world_map = world.world_map;*/ //why doesn't this work?
return world;
}
}
public class World {
private Rect mWorldAABB;
private static World sInstance = null;
private World() {
// Put your code to read whatever you want from file
};
private static World getInstance() {
if (sInstance == null) {
sInstance = new World();
}
return sInstance;
}
private Rect getWorldRect() {
return mWorldAABB;
}
public static Rect getWorldDimensions() {
return getInstance().getWorldRect();
}
public class WorldBuilder {
private File worldFile;
private String name = "default_world";
private int width = 1;
private int height = 1;
public static WorldBuilder fromFile(File worldFile){
WorldBuilder worldBuilder = new WorldBuilder();
worldBuilder.worldFile = worldFile;
return worldBuilder;
}
public WorldBuilder withName(String name){
this.name= name;
return this;
}
public WorldBuilder withWidth(int width){
this.parameter2 = param2;
return this;
}
public WorldBuilder withHeight(int height){
this.height = height;
return this;
}
public World build(){
World world = new World(name,width,height);
if(worldFile!=null)
world.loadWorld(worldFile);
return world;
}
}
World world = WorldBuilder.fromFile(worldFile)
.withName(p1)
.withWidth(p2)
.withHeight(p3)
.build();
World world = WorldBuilder.fromFile(null).build();