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

mac2022-06-30  21

  相册这玩意儿用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 stub44 try45 {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 stub52 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 try68 {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 ImageCallback79 {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等属性呢?

 

转载于:https://www.cnblogs.com/JD85/archive/2012/01/30/2315660.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)