zoukankan      html  css  js  c++  java
  • 从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等属性呢?

  • 相关阅读:
    shell-bash学习01基础、打印、环境变量
    css/js(工作中遇到的问题)-2
    git学习 git-flow
    js正则表达式练习
    12 链
    11数据访问
    10访问者,解释器
    08中介者,装饰者
    09 状态,适配器
    调试 scrapy 文件报错:line 48, in _load_handler、line 44, in load_object、 line 37, in import_module
  • 原文地址:https://www.cnblogs.com/JD85/p/2315660.html
Copyright © 2011-2022 走看看