首先要知道如何访问图片文件,这是最基本的。
一种是资源文件目录下的图片访问,这种可以直接通过Resources.getDrawable(/*resources.id*/),这样就取得了图片的drawable,比较简单。
第二种是从给定路径的某个目录下的图片文件获取,这里需要用到BitmapFactory来创建,Bitmap bm = BitmapFacotry.decodeFile(path);这里decodeFile是个静态方法。
一、本地保存 即 把 Bitmap 保存在sdcard中:
//创建目标文件的File
File fImage = new File("/sdcard/dcim","beijing.jpeg");
//取出Bitmap oriBmp
oriBmp.compress(CompressFormat.JPEG, 100, iStream);
可以保存为几种格式:png,gif等貌似都可以,自己写的:
1 public void saveMyBitmap(String bitName) throws IOException { 2 File f = new File("/sdcard/Note/" + bitName + ".png"); 3 f.createNewFile(); 4 FileOutputStream fOut = null; 5 try { 6 fOut = new FileOutputStream(f); 7 } catch (FileNotFoundException e) { 8 e.printStackTrace(); 9 } 10 mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); 11 try { 12 fOut.flush(); 13 } catch (IOException e) { 14 e.printStackTrace(); 15 } 16 }
二、得到网络图片的方式:
1 public static Bitmap returnBitMap(String path) { 2 URL url = null; 3 Bitmap bitmap = null; 4 try { 5 url = new URL(path); 6 } catch (MalformedURLException e) { 7 e.printStackTrace(); 8 } 9 try { 10 HttpURLConnection conn = (HttpURLConnection) url.openConnection();//利用HttpURLConnection对象,我们可以从网络中获取网页数据. 11 conn.setDoInput(true); 12 conn.connect(); 13 InputStream is = conn.getInputStream(); //得到网络返回的输入流 14 bitmap = BitmapFactory.decodeStream(is); 15 is.close(); 16 } catch (IOException e) { 17 e.printStackTrace(); 18 } 19 return bitmap; 20 }
三、Drawable->Bitmap
1 public static Bitmap drawableToBitmap(Drawable drawable) { 2 Bitmap bitmap = Bitmap.createBitmap( 3 drawable.getIntrinsicWidth(), 4 drawable.getIntrinsicHeight(), 5 drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888: Bitmap.Config.RGB_565); 6 Canvas canvas = new Canvas(bitmap); 7 drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); 8 drawable.draw(canvas); 9 return bitmap; 10 }
PS:首先建立一个和drawable同样大小的bitmap对象,同时,通过getOpacity获得源drawable的编码风格,是Bitmap.Config.ARGB_8888还是Bitmap.Config.RGB_565,接着把这个bitmap作为画布,最终把drawable画到画布上,传回bitmap,搞定!
四、Bitmap <->byte[]
其实bitmap都是由一个byte数据来决定的,每个像素点由一个4字节整型决定的,所以一个bitmap可以转换成一个byte数组,同样,对bitmap的处理就是由这个原理引入的,先将图片导出到一个byte数组里,再处理这个byte数组,最后写回bitmap对象里,就完成了bitmap的处理。
1 private byte[] Bitmap2Bytes(Bitmap bm){ 2 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 3 bm.compress(Bitmap.CompressFormat.PNG, 100, baos); 4 return baos.toByteArray(); 5 } 6 private Bitmap Bytes2Bimap(byte[] b){ 7 if(b.length!=0){ 8 return BitmapFactory.decodeByteArray(b, 0, b.length); 9 } else { 10 return null; 11 } 12 }
五、Handler:
当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。当主线程正在做一些比较耗时的操作的时候,如正从网络上下载一个大图片,或者访问数据库,由于主线程被这些耗时的操作阻塞住,无法及时的响应用户的事件,从用户的角度看会觉得程序已经死掉。如果程序长时间不响应,用户还可能得重启系统。
为了避免这样的情况,Android设置了一个5秒的超时时间,一旦用户的事件由于主线程阻塞而超过5秒钟没有响应,Android会弹出一个应用程序没有响应的对话框。在单线程模型下,为了解决类似的问题,Android设计了一个Message Queue(消息队列),线程间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。
通过Handler你可以发布或者处理一个消息或者是一个Runnable的实例。每个Handler都会与唯一的一个线程以及该线程的消息队列管理。当你创建一个新的Handler时候,默认情况下,它将关联到创建它的这个线程和该线程的消息队列。也就是说,如果你通过Handler发布消息的话,消息将只会发送到与它关联的这个消息队列,当然也只能处理该消息队列中的消息。
Looper扮演着一个Handler和消息队列之间通讯桥梁的角色。程序组件首先通过Handler把消息传递给Looper,Looper把消息放入队列。Looper也把消息队列里的消息广播给所有的Handler,Handler接受到消息后调用handleMessage进行处理。
1) 可以通过Looper类的静态方法Looper.myLooper得到当前线程的Looper实例,如果当前线程未关联一个Looper实例,该方法将返回空。
2) 可以通过静态方法Looper. getMainLooper方法得到主线程的Looper实例。
六、Canvas中的save和restore:save和restore是对canvas的一种锁定,锁定其他项目不受这之间的操作的影响,也就是说在save和restore之间的操作,对已绘制的图形或者在restore后绘制的图形是没有影响的:
1 canvas = mHolder.lockCanvas(); 2 Paint mPaint = new Paint(); 3 mPaint.setColor(Color.BLUE); 4 canvas.drawRect(100, 200, 200, 300, mPaint); 5 canvas.save(); // 注释1 6 canvas.rotate(45); 7 mPaint.setColor(Color.RED); 8 canvas.drawRect(150, 10, 200, 60, mPaint); 9 canvas.restore(); // 注释2 10 mPaint.setColor(Color.GREEN); 11 canvas.drawRect(200, 10, 250, 100, mPaint); 12 mHolder.unlockCanvasAndPost(canvas);