从0开始写个Android相册应用(1)

  相册这玩意儿用AS写过几个,这回用android写,目前对于java的理解完全是根据as来的,对于android几乎是一窍不通,从没做过这方面的项目,公司有个后台同事稍微懂点,本打算跟着他学学的,在他刚教会我安装android开发环境后,他就辞职闪人了。好吧,买书自学。找到了当初在西安一个人拿着殿堂之路死磕的感觉。

 

  技术要点:

  1,如何创建一个android项目;

  2,如何创建一个可见的显示对象类;

  3,如何让显示对象从A点移动到B点,且可控制速度;

  4,如何访问本地文件,包括手机存储空间和SD卡存储空间;

  5,如何把本地路径的图片加载到自己应用的内存空间里;

  6,如何把图片添加到显示对象作为其子对象;

    7,如果通过网络加载服务器里存储的图片。

 

==================================================================

1,eclipse安装好ADT和Android SDK后,就可创建android项目,Ctrl+N ,选择"Android"目录,第一个是"Android Icon Set",这个东西貌似是专门给自己的应用创建logo Icon的,不管他,点第二个,新建“Android Project”,这里用的android版本是2.3.3。

 

项目目录下默认有src,gen,android2.3.3,assets,bin,res这六个目录,和AndroidManifest.xml ,proguard.cfg, progect.properties这三个文件。

(1)src:

项目里所有代码都在这里,由于创建项目时勾选了”Create Activity“,会自动创建一个继承自Activity的类,这里叫    PhotoAlbumActivity.java。

   Activity:

   An Activity is an application component that provides a screen with which users can interact in order to do something, such as dial the phone, take a photo, send an email, or view a map. An activity can start other activities, including activities that live in separate applications.

   官方文档里的原话,大意是Activity是一个供用户交互的应用组件,一个用户界面。比如用户拨号,拍照,发送邮件或者查看地图。可以通过一个activity对象启动其他的activiety对象,甚至是存在与其他独立的应用里的activity对象。

(2)gen:

  项目一旦编译之后就会在gen目录里创建一个类R.java,此类对应的是res目录里所有的资源文件,项目中新添加一张图放到了res-drawable目录后就会在R.java里自动生成一个新的对应索引。项目中使用资源的地方可便捷地通过R.java使用。

 

(3)Android 2.2.3

   android库目录,android.jar文件指向Android SDK,所有官方API

(4)assets

  存放外部资源,和同样是存放资源的res目录的区别就在于res里的资源文件会自动在R.java里生成对应资源ID,asset则不会。

(5)bin

  项目编译成功后会在bin里面存放用到了的资源,以及生成一个apk文件。

(6)res

  res,用来存放项目中用到的资源文件,有5个子目录:

  drawable_hdpi,存放高分辨的图片,WVGA(480*800),FWVGA(480*854)

  drawable_ldpi,存放中等分辨率的图片,HVGA(320*480)

  drawable_mdpi,存放低分辨率的图片,QVGA(240*320)

  layout,存放布局文件

  values,放置项目需要显示的各种文字,颜色等文字信息。

(7)AndroidManifest.xml

  当前项目的配置文件,包含有项目中用到的Activity,如果新添加了一个Activity,需要在这个进行相应的配置才能被调用。

(8)proguard.cfg

  貌似是一个用与混淆代码放置反编译的东西

(9)project.properies

  貌似是跟android版本信息有关。

 =================================================================

2,要想创建一个显示对象,就不得不说说三种常用视图类,View,surfaceView,GLSurfaceView

view,内置画布canvas,提供图形绘制函数,触屏事件,按键事件函数等;

surfaceView,继承自view.

 

====================================

 2012年,1月24日大年初二晚,继续写这篇文章。之前写的技术要点有些了解了有些还没了解。

之前偶尔抽时间在网上找了些资料,目前算是可以复制网上的代码搞个根据设定的线程数来加载图片,代码还真是好多地方都没看懂。这算是之前的测试结果把。

DrawableLoader
 1 package com.jd.net;
2
3 import java.lang.ref.SoftReference;
4 import java.net.URL;
5 import java.util.HashMap;
6 import java.util.Map;
7 import java.util.concurrent.ExecutorService;
8 import java.util.concurrent.Executors;
9
10 import android.graphics.drawable.Drawable;
11 import android.os.Handler;
12
13 public class DrawableLoader
14 {
15 public Map<String, SoftReference<Drawable>> imageCache =
16 new HashMap<String, SoftReference<Drawable>>();
17
18 private ExecutorService executorService = Executors.newFixedThreadPool(2);
19
20 private final Handler handler = new Handler();
21
22
23 public DrawableLoader()
24 {
25
26 }
27
28 public Drawable loadDrawable(final String imageUrl,
29 final ImageCallback callback)
30 {
31 if(imageCache.containsKey(imageUrl))
32 {
33 SoftReference<Drawable> softReference = imageCache.get(imageUrl);
34 if(softReference.get() != null)
35 {
36 return softReference.get();
37 }
38 }
39
40 executorService.submit(new Runnable() {
41
42 public void run() {
43 // TODO Auto-generated method stub
44 try
45 {
46 final Drawable drawable = loadImageFromUrl(imageUrl);
47 imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
48 handler.post(new Runnable() {
49
50 public void run() {
51 // TODO Auto-generated method stub
52 callback.imageLoaded(drawable);
53 }
54 });
55 }
56 catch(Exception e)
57 {
58 throw new RuntimeException(e);
59 }
60 }
61 });
62 return null;
63 }
64
65 protected Drawable loadImageFromUrl(String imageUrl)
66 {
67 try
68 {
69 // SystemClock.sleep(3000);
70 return Drawable.createFromStream(new URL(imageUrl).openStream(),"image.png");
71 }
72 catch(Exception e)
73 {
74 throw new RuntimeException(e);
75 }
76 }
77
78 public interface ImageCallback
79 {
80 public void imageLoaded(Drawable imageDrawable);
81 }
82 }



接下来的测试目标步骤:

    1,根据给定的url,加载一张图片到一个ImageView对象里,并且显示出来;

    2,让这个ImageView对象从一个点移动到另一个点;

  3,让这个ImageView对象在加载好后就显示为小图,点击后等比例放大

===========================================

昨天也就是1月23号在网上找了好久资料发现无法在不使用layout配置文件的情况下把一个ImageView对像添加到了View对象里。用位图Bitmap的话倒是可以通过android.graphics.Canvas的drawBitmap方法把一张bitmap添加到view, 然后发现之前利用线程加载图片是用的android.graphics.drawable.Drawable,而网上有提到Bitmap和Drawable这个抽象类的互相转换,那么就不用ImageView而改用Bitmap试试。

 

======================================

1月30号

到目前为止可以从网上加载一张位图显示到surfaceview里了。通过一个Thread可以让这张图片移动,每一帧都重绘canvas.drawBitmap()以达到移动的目的。

 

MainSurfaceView
  1 package com.jd.view;
2
3 import android.content.Context;
4
5 import android.graphics.Bitmap;
6 import android.graphics.Canvas;
7 import android.graphics.Color;
8 import android.graphics.Paint;
9 import android.graphics.drawable.Drawable;
10 import android.view.MotionEvent;
11 import android.view.SurfaceHolder;
12 import android.view.SurfaceHolder.Callback;
13 import android.view.SurfaceView;
14
15 import com.jd.net.DrawableLoader;
16
17 public class MainSurfaceView extends SurfaceView implements Callback,Runnable
18 {
19
20 private SurfaceHolder holder;
21 private Paint paint;
22 private DrawableLoader drawableLoader;
23 private Bitmap bitmap;
24 private int bitmapPosX;
25 private int bitmapPosY;
26
27 private boolean flag;
28 private Thread th;
29
30 public MainSurfaceView(Context context)
31 {
32 super(context);
33 System.out.println("surfaceview new");
34 holder = this.getHolder();
35 holder.addCallback(this);
36 paint = new Paint();
37 paint.setColor(Color.WHITE);
38
39 bitmapPosX = 10;
40 bitmapPosY = 10;
41
42 }
43
44 @Override
45 public boolean onTouchEvent(MotionEvent event)
46 {
47 // TODO Auto-generated method stub
48 // bitmapPosX = (int) event.getX();
49 // bitmapPosY = (int) event.getY();
50 flag = true;
51 th = new Thread(this);
52 th.start();
53 // myDraw();
54 return true;
55 }
56
57 @Override
58 public void surfaceCreated(SurfaceHolder holder)
59 {
60 System.out.println("surfaceview created");
61
62 loadImage();
63 }
64
65 @Override
66 public void run()
67 {
68 // TODO Auto-generated method stub
69 while(flag)
70 {
71 long start = System.currentTimeMillis();
72 bitmapPosY++;
73
74 myDraw();
75 long end = System.currentTimeMillis();
76 try {
77 if (end - start < 50) {
78 Thread.sleep(50 - (end - start));
79 }
80 } catch (InterruptedException e) {
81 e.printStackTrace();
82 }
83 }
84 }
85
86 public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
87 {
88 System.out.println("surfaceview changed");
89 }
90 public void surfaceDestroyed(SurfaceHolder arg0)
91 {
92
93 }
94
95 private void loadImage()
96 {
97 String imageUrl = "http://i1.sinaimg.cn/dy/FocusPic/124/2008-03-24/U4708P1T124D2F2633DT20120129110520.jpg";
98 drawableLoader = new DrawableLoader();
99 //如果内存中没有加载过这张图片,那么就开始用线程加载,通过回调拉倒加到的图片
100 Drawable cacheImage = drawableLoader.loadDrawable(imageUrl,
101 new DrawableLoader.ImageCallback()
102 {
103
104 public void imageLoaded(Drawable imageDrawable)
105 {
106 int w = imageDrawable.getIntrinsicWidth();
107 int h = imageDrawable.getIntrinsicHeight();
108 String wStr = String.valueOf(w);
109 String hStr = String.valueOf(h);
110
111 System.out.println("image loaded success");
112 System.out.println("图片宽为"+wStr);
113 System.out.println("图片高为"+hStr);
114
115 bitmap = BitmapTool.drawableToBitmap(imageDrawable);
116 myDraw();
117 }
118 });
119
120 //如果内存中曾经加载过此图,就不会调用回调方法,而是把cacheImage给返回
121 if(cacheImage != null)
122 {
123 System.out.println("内存中存在此图");
124 int w = cacheImage.getIntrinsicWidth();
125 int h = cacheImage.getIntrinsicHeight();
126 String wStr = String.valueOf(w);
127 String hStr = String.valueOf(h);
128
129 System.out.println("image loaded success");
130 System.out.println("图片宽为"+wStr);
131 System.out.println("图片高为"+hStr);
132
133 bitmap = BitmapTool.drawableToBitmap(cacheImage);
134 myDraw();
135 }
136 }
137
138 private void myDraw()
139 {
140 if(bitmap == null)
141 {
142 return;
143 }
144
145 Canvas canvas = holder.lockCanvas();
146 canvas.drawColor(Color.BLACK);
147 // canvas.save();
148 // canvas.scale(0.5f, 0.5f,bitmap.getWidth() / 2,bitmap.getHeight() / 2);
149 canvas.drawBitmap(bitmap, bitmapPosX,bitmapPosY, paint);
150 // canvas.restore();
151 // canvas.drawBitmap(bitmap, 20,50, paint);
152 holder.unlockCanvasAndPost(canvas);
153 }
154 }

 

BitmapTool
 1 package com.jd.view;
2
3 import android.graphics.Bitmap;
4
5 import android.graphics.drawable.BitmapDrawable;
6 import android.graphics.drawable.Drawable;
7
8 public class BitmapTool
9 {
10 public static Bitmap drawableToBitmap(Drawable drawable)
11 {
12 BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
13 return bitmapDrawable.getBitmap();
14 }
15 }

总结一下,根据这几天在网上和书上的有限的资料里了解到,要想改变位图的位置,大小,并不是像ActionScrtipt里bitmap.x,bitmap.y,bitmap.scaleX,bitmap.scaleY等等属性直接改变位图的显示属性,而是要通过代码反复重绘位图所在的view的画布canvas,官方文档没有怎么瞅,不知是否有更方便的方法。

 

哈,虽说AS把显示对象封装地比较好用,什么.addChild,.x,.y,.scale之类的,但底层我觉得也因该是一样的机制,重绘呗。

留下来两个问题:

1,AS里一张位图被添加到舞台上,若再添加一张位图并想让前者不可见,那么就要把前者removeChild掉,而android里重绘时直接给canvas绘制一下颜色就貌似移除之前的位图了,然后再绘制新图。前面的位图不可见了,那么这时前一张位图所占的内存是否可以被自动回收了呢,是否要通过代码做些销毁处理?

2,Canvas,一个SurfaceView是否就只有一张画图?如果要在一个Activity里显示多张位图,那么这些位图是必须在同一个canvas里?还是可以被绘制在不同的canvas里?canvas是否有x,y,width,height等属性呢?

 

posted @ 2012-01-30 12:40  居家懒人  阅读(2207)  评论(0编辑  收藏  举报