Android实现下载图片并保存到SD卡中

本文介绍了一种在Android平台上实现在线图片下载并保存至本地设备的方法,包括使用线程处理网络请求,以及如何在主线程中更新UI展示图片。同时,文章提供了不同Android版本下(4.0及以上和2.3.3以下)实现图片下载和保存的代码示例,以适应不同版本的Android系统。此外,文章还讨论了在Android中避免在主线程中进行网络操作的重要性,并提供了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.java代码,下载图片的主程序

先实现显示图片,然后点击下载图片按钮,执行下载功能。

从网络上取得的图片,生成Bitmap时有两种方法,一种是先转换为byte[],再生成bitmap;一种是直接用InputStream生成bitmap。

(1)ICS4.0及更高版本中的实现

4.0中不允许在主线程,即UI线程中操作网络,所以必须新开一个线程,在子线程中执行网络连接;然后在主线程中显示图片。

  1. public class IcsTestActivity extends Activity { 
  2.  
  3.     private final static String TAG = "IcsTestActivity"
  4.     private final static String ALBUM_PATH 
  5.             = Environment.getExternalStorageDirectory() + "/download_test/"
  6.     private ImageView mImageView; 
  7.     private Button mBtnSave; 
  8.     private ProgressDialog mSaveDialog = null
  9.     private Bitmap mBitmap; 
  10.     private String mFileName; 
  11.     private String mSaveMessage; 
  12.  
  13.  
  14.     @Override 
  15.     protected void onCreate(Bundle savedInstanceState) { 
  16.         super.onCreate(savedInstanceState); 
  17.         setContentView(R.layout.main); 
  18.  
  19.         mImageView = (ImageView)findViewById(R.id.imgSource); 
  20.         mBtnSave = (Button)findViewById(R.id.btnSave); 
  21.  
  22.         new Thread(connectNet).start(); 
  23.  
  24.         // 下载图片 
  25.         mBtnSave.setOnClickListener(new Button.OnClickListener(){ 
  26.             public void onClick(View v) { 
  27.                 mSaveDialog = ProgressDialog.show(IcsTestActivity.this, "保存图片", "图片正在保存中,请稍等...", true); 
  28.                 new Thread(saveFileRunnable).start(); 
  29.         } 
  30.         }); 
  31.     } 
  32.  
  33.     /**
  34.      * Get image from newwork
  35.      * @param path The path of image
  36.      * @return byte[]
  37.      * @throws Exception
  38.      */ 
  39.     public byte[] getImage(String path) throws Exception{ 
  40.         URL url = new URL(path); 
  41. HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  42.         conn.setConnectTimeout(5 * 1000); 
  43.         conn.setRequestMethod("GET"); 
  44.         InputStream inStream = conn.getInputStream(); 
  45.         if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){ 
  46.             return readStream(inStream); 
  47.         } 
  48.         return null
  49.     } 
  50.  
  51.     /**
  52.      * Get image from newwork
  53.      * @param path The path of image
  54.      * @return InputStream
  55.      * @throws Exception
  56.      */ 
  57.     public InputStream getImageStream(String path) throws Exception{ 
  58.         URL url = new URL(path); 
  59.         HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 
  60.         conn.setConnectTimeout(5 * 1000); 
  61.         conn.setRequestMethod("GET"); 
  62.         if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){ 
  63.             return conn.getInputStream(); 
  64.         } 
  65.         return null
  66.     } 
  67.     /**
  68.      * Get data from stream
  69.      * @param inStream
  70.      * @return byte[]
  71.      * @throws Exception
  72.      */ 
  73.     public static byte[] readStream(InputStream inStream) throws Exception{ 
  74.         ByteArrayOutputStream outStream = new ByteArrayOutputStream(); 
  75.         byte[] buffer = new byte[1024]; 
  76.         int len = 0
  77.         while( (len=inStream.read(buffer)) != -1){ 
  78.             outStream.write(buffer, 0, len); 
  79.         } 
  80.         outStream.close(); 
  81.         inStream.close(); 
  82.         return outStream.toByteArray(); 
  83.     } 
  84.  
  85.     /**
  86.      * 保存文件
  87.      * @param bm
  88.      * @param fileName
  89.      * @throws IOException
  90.      */ 
  91.     public void saveFile(Bitmap bm, String fileName) throws IOException { 
  92.         File dirFile = new File(ALBUM_PATH); 
  93.         if(!dirFile.exists()){ 
  94.             dirFile.mkdir(); 
  95.         } 
  96.         File myCaptureFile = new File(ALBUM_PATH + fileName); 
  97.         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile)); 
  98.         bm.compress(Bitmap.CompressFormat.JPEG, 80, bos); 
  99.         bos.flush(); 
  100.         bos.close(); 
  101.     } 
  102.  
  103.     private Runnable saveFileRunnable = new Runnable(){ 
  104.         @Override 
  105.         public void run() { 
  106.             try
  107.                 saveFile(mBitmap, mFileName); 
  108.                 mSaveMessage = "图片保存成功!"
  109.             } catch (IOException e) { 
  110.                 mSaveMessage = "图片保存失败!"
  111.                 e.printStackTrace(); 
  112.             } 
  113.             messageHandler.sendMessage(messageHandler.obtainMessage()); 
  114.         } 
  115.  
  116.     }; 
  117.  
  118.     private Handler messageHandler = new Handler() { 
  119.         @Override 
  120.         public void handleMessage(Message msg) { 
  121.             mSaveDialog.dismiss(); 
  122.             Log.d(TAG, mSaveMessage); 
  123.             Toast.makeText(IcsTestActivity.this, mSaveMessage, Toast.LENGTH_SHORT).show(); 
  124.         } 
  125.     }; 
  126.  
  127.     /*
  128.      * 连接网络
  129.      * 由于在4.0中不允许在主线程中访问网络,所以需要在子线程中访问
  130.      */ 
  131.     private Runnable connectNet = new Runnable(){ 
  132.         @Override 
  133.         public void run() { 
  134.             try
  135.                 String filePath = "https://img-my.youkuaiyun.com/uploads/201211/21/1353511891_4579.jpg"
  136.                 mFileName = "test.jpg"
  137.  
  138.                 //以下是取得图片的两种方法 
  139.                 //////////////// 方法1:取得的是byte数组, 从byte数组生成bitmap 
  140.                 byte[] data = getImage(filePath); 
  141.                 if(data!=null){ 
  142.                     mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);// bitmap 
  143.                 }else
  144.                     Toast.makeText(IcsTestActivity.this, "Image error!", 1).show(); 
  145.                 } 
  146.                 //////////////////////////////////////////////////////// 
  147.  
  148.                 //******** 方法2:取得的是InputStream,直接从InputStream生成bitmap ***********/ 
  149.                 mBitmap = BitmapFactory.decodeStream(getImageStream(filePath)); 
  150.                 //********************************************************************/ 
  151.  
  152.                 // 发送消息,通知handler在主线程中更新UI 
  153.                 connectHanlder.sendEmptyMessage(0); 
  154.                 Log.d(TAG, "set image ..."); 
  155.             } catch (Exception e) { 
  156.                 Toast.makeText(IcsTestActivity.this,"无法链接网络!", 1).show(); 
  157.                 e.printStackTrace(); 
  158.             } 
  159.  
  160.         } 
  161.  
  162.     }; 
  163.  
  164.     private Handler connectHanlder = new Handler() { 
  165.         @Override 
  166.         public void handleMessage(Message msg) { 
  167.             Log.d(TAG, "display image"); 
  168.             // 更新UI,显示图片 
  169.             if (mBitmap != null) { 
  170.                 mImageView.setImageBitmap(mBitmap);// display image 
  171.             } 
  172.         } 
  173.     }; 
  174.  
public class IcsTestActivity extends Activity {

    private final static String TAG = "IcsTestActivity";
    private final static String ALBUM_PATH
            = Environment.getExternalStorageDirectory() + "/download_test/";
    private ImageView mImageView;
    private Button mBtnSave;
    private ProgressDialog mSaveDialog = null;
    private Bitmap mBitmap;
    private String mFileName;
    private String mSaveMessage;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mImageView = (ImageView)findViewById(R.id.imgSource);
        mBtnSave = (Button)findViewById(R.id.btnSave);

        new Thread(connectNet).start();

        // 下载图片
        mBtnSave.setOnClickListener(new Button.OnClickListener(){
            public void onClick(View v) {
                mSaveDialog = ProgressDialog.show(IcsTestActivity.this, "保存图片", "图片正在保存中,请稍等...", true);
                new Thread(saveFileRunnable).start();
        }
        });
    }

    /**
     * Get image from newwork
     * @param path The path of image
     * @return byte[]
     * @throws Exception
     */
    public byte[] getImage(String path) throws Exception{
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5 * 1000);
        conn.setRequestMethod("GET");
        InputStream inStream = conn.getInputStream();
        if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
            return readStream(inStream);
        }
        return null;
    }

    /**
     * Get image from newwork
     * @param path The path of image
     * @return InputStream
     * @throws Exception
     */
    public InputStream getImageStream(String path) throws Exception{
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5 * 1000);
        conn.setRequestMethod("GET");
        if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
            return conn.getInputStream();
        }
        return null;
    }
    /**
     * Get data from stream
     * @param inStream
     * @return byte[]
     * @throws Exception
     */
    public static byte[] readStream(InputStream inStream) throws Exception{
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while( (len=inStream.read(buffer)) != -1){
            outStream.write(buffer, 0, len);
        }
        outStream.close();
        inStream.close();
        return outStream.toByteArray();
    }

    /**
     * 保存文件
     * @param bm
     * @param fileName
     * @throws IOException
     */
    public void saveFile(Bitmap bm, String fileName) throws IOException {
        File dirFile = new File(ALBUM_PATH);
        if(!dirFile.exists()){
            dirFile.mkdir();
        }
        File myCaptureFile = new File(ALBUM_PATH + fileName);
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));
        bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);
        bos.flush();
        bos.close();
    }

    private Runnable saveFileRunnable = new Runnable(){
        @Override
        public void run() {
            try {
                saveFile(mBitmap, mFileName);
                mSaveMessage = "图片保存成功!";
            } catch (IOException e) {
                mSaveMessage = "图片保存失败!";
                e.printStackTrace();
            }
            messageHandler.sendMessage(messageHandler.obtainMessage());
        }

    };

    private Handler messageHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            mSaveDialog.dismiss();
            Log.d(TAG, mSaveMessage);
            Toast.makeText(IcsTestActivity.this, mSaveMessage, Toast.LENGTH_SHORT).show();
        }
    };

    /*
     * 连接网络
     * 由于在4.0中不允许在主线程中访问网络,所以需要在子线程中访问
     */
    private Runnable connectNet = new Runnable(){
        @Override
        public void run() {
            try {
                String filePath = "https://img-my.youkuaiyun.com/uploads/201211/21/1353511891_4579.jpg";
                mFileName = "test.jpg";

                //以下是取得图片的两种方法
                //////////////// 方法1:取得的是byte数组, 从byte数组生成bitmap
                byte[] data = getImage(filePath);
                if(data!=null){
                    mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);// bitmap
                }else{
                    Toast.makeText(IcsTestActivity.this, "Image error!", 1).show();
                }
                ////////////////////////////////////////////////////////

                //******** 方法2:取得的是InputStream,直接从InputStream生成bitmap ***********/
                mBitmap = BitmapFactory.decodeStream(getImageStream(filePath));
                //********************************************************************/

                // 发送消息,通知handler在主线程中更新UI
                connectHanlder.sendEmptyMessage(0);
                Log.d(TAG, "set image ...");
            } catch (Exception e) {
                Toast.makeText(IcsTestActivity.this,"无法链接网络!", 1).show();
                e.printStackTrace();
            }

        }

    };

    private Handler connectHanlder = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Log.d(TAG, "display image");
            // 更新UI,显示图片
            if (mBitmap != null) {
                mImageView.setImageBitmap(mBitmap);// display image
            }
        }
    };

}
(2)2.3以及以下版本可以在主线程中操作网络连接,但最好不要这样做,因为连接网络是阻塞的,如果5秒钟还没有连接上,就会引起ANR。

  1. public class AndroidTest2_3_3 extends Activity { 
  2.     private final static String TAG = "AndroidTest2_3_3"
  3.     private final static String ALBUM_PATH  
  4.             = Environment.getExternalStorageDirectory() + "/download_test/"
  5.     private ImageView imageView; 
  6.     private Button btnSave; 
  7.     private ProgressDialog myDialog = null
  8.     private Bitmap bitmap; 
  9.     private String fileName; 
  10.     private String message; 
  11.      
  12.      
  13.     @Override 
  14.     protected void onCreate(Bundle savedInstanceState) { 
  15.         super.onCreate(savedInstanceState); 
  16.         setContentView(R.layout.main); 
  17.          
  18.         imageView = (ImageView)findViewById(R.id.imgSource); 
  19.         btnSave = (Button)findViewById(R.id.btnSave); 
  20.          
  21.         String filePath = "http://hi.youkuaiyun.com/attachment/201105/21/134671_13059532779c5u.jpg"
  22.         fileName = "test.jpg"
  23.          
  24.         try
  25.             //////////////// 取得的是byte数组, 从byte数组生成bitmap 
  26.             byte[] data = getImage(filePath);       
  27.             if(data!=null){       
  28.                 bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);// bitmap       
  29.                 imageView.setImageBitmap(bitmap);// display image       
  30.             }else{       
  31.                 Toast.makeText(AndroidTest2_3_3.this, "Image error!", 1).show();       
  32.             } 
  33.             //////////////////////////////////////////////////////// 
  34.  
  35.             //******** 取得的是InputStream,直接从InputStream生成bitmap ***********/ 
  36.             bitmap = BitmapFactory.decodeStream(getImageStream(filePath)); 
  37.             if (bitmap != null) { 
  38.                 imageView.setImageBitmap(bitmap);// display image 
  39.             } 
  40.             //********************************************************************/ 
  41.             Log.d(TAG, "set image ..."); 
  42.         } catch (Exception e) {    
  43.             Toast.makeText(AndroidTest2_3_3.this,"Newwork error!", 1).show();    
  44.             e.printStackTrace();    
  45.         }    
  46.  
  47.          
  48.         // 下载图片 
  49.         btnSave.setOnClickListener(new Button.OnClickListener(){ 
  50.             public void onClick(View v) { 
  51.                 myDialog = ProgressDialog.show(AndroidTest2_3_3.this, "保存图片", "图片正在保存中,请稍等...", true); 
  52.                 new Thread(saveFileRunnable).start(); 
  53.         } 
  54.         }); 
  55.     } 
  56.  
  57.     /** 
  58.      * Get image from newwork 
  59.      * @param path The path of image 
  60.      * @return byte[]
  61.      * @throws Exception 
  62.      */   
  63.     public byte[] getImage(String path) throws Exception{    
  64.         URL url = new URL(path);    
  65.         HttpURLConnection conn = (HttpURLConnection) url.openConnection();    
  66.         conn.setConnectTimeout(5 * 1000);    
  67.         conn.setRequestMethod("GET");    
  68.         InputStream inStream = conn.getInputStream();    
  69.         if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){    
  70.             return readStream(inStream);    
  71.         }    
  72.         return null;    
  73.     }    
  74.    
  75.     /** 
  76.      * Get image from newwork 
  77.      * @param path The path of image 
  78.      * @return InputStream
  79.      * @throws Exception 
  80.      */ 
  81.     public InputStream getImageStream(String path) throws Exception{    
  82.         URL url = new URL(path);    
  83.         HttpURLConnection conn = (HttpURLConnection) url.openConnection();    
  84.         conn.setConnectTimeout(5 * 1000);    
  85.         conn.setRequestMethod("GET"); 
  86.         if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){    
  87.             return conn.getInputStream();       
  88.         }    
  89.         return null;  
  90.     } 
  91.     /** 
  92.      * Get data from stream
  93.      * @param inStream 
  94.      * @return byte[]
  95.      * @throws Exception 
  96.      */   
  97.     public static byte[] readStream(InputStream inStream) throws Exception{    
  98.         ByteArrayOutputStream outStream = new ByteArrayOutputStream();    
  99.         byte[] buffer = new byte[1024];    
  100.         int len = 0;    
  101.         while( (len=inStream.read(buffer)) != -1){    
  102.             outStream.write(buffer, 0, len);    
  103.         }    
  104.         outStream.close();    
  105.         inStream.close();    
  106.         return outStream.toByteArray();    
  107.     }  
  108.  
  109.     /**
  110.      * 保存文件
  111.      * @param bm
  112.      * @param fileName
  113.      * @throws IOException
  114.      */ 
  115.     public void saveFile(Bitmap bm, String fileName) throws IOException { 
  116.         File dirFile = new File(ALBUM_PATH); 
  117.         if(!dirFile.exists()){ 
  118.             dirFile.mkdir(); 
  119.         } 
  120.         File myCaptureFile = new File(ALBUM_PATH + fileName); 
  121.         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile)); 
  122.         bm.compress(Bitmap.CompressFormat.JPEG, 80, bos); 
  123.         bos.flush(); 
  124.         bos.close(); 
  125.     } 
  126.      
  127.     private Runnable saveFileRunnable = new Runnable(){ 
  128.         @Override 
  129.         public void run() { 
  130.             try
  131.                 saveFile(bitmap, fileName); 
  132.                 message = "图片保存成功!"
  133.             } catch (IOException e) { 
  134.                 message = "图片保存失败!"
  135.                 e.printStackTrace(); 
  136.             } 
  137.             messageHandler.sendMessage(messageHandler.obtainMessage()); 
  138.         } 
  139.              
  140.     }; 
  141.      
  142.     private Handler messageHandler = new Handler() { 
  143.         @Override 
  144.         public void handleMessage(Message msg) { 
  145.             myDialog.dismiss(); 
  146.             Log.d(TAG, message); 
  147.             Toast.makeText(AndroidTest2_3_3.this, message, Toast.LENGTH_SHORT).show(); 
  148.         } 
  149.     }; 

 

下载进度条的可以参考我的另外一个帖子:Android更新下载进度条

2.main.xml文件,只有一个button和一个ImageView

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.     android:orientation="vertical" 
  4.     android:layout_width="fill_parent" 
  5.     android:layout_height="fill_parent" 
  6.     > 
  7.     <Button 
  8.         android:id="@+id/btnSave" 
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content" 
  11.         android:text="保存图片" 
  12.         /> 
  13.     <ImageView 
  14.         android:id="@+id/imgSource" 
  15.         android:layout_width="wrap_content"  
  16.         android:layout_height="wrap_content"  
  17.         android:adjustViewBounds="true" 
  18.         /> 
  19. </LinearLayout> 

3.在mainfest文件中增加互联网权限和写sd卡的权限

  1. <uses-permission android:name="android.permission.INTERNET" />  
  2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
  3.    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> 

4.预览图:

注:本实例图片是本人拍摄的位于东京西郊美军横田基地的一个大门。

 

 

 

 

 

备注:代码在4.0以上的真机上应该是发生了android.os.NetworkOnMainThreadException(但模拟器上可能没问题),
规范下代码,和network相关的工作请另开线程处理,起线程方法自己google,建议不要用网上说的StrictMode这个方法,这是偏方。异步处理建议用AsyncTask类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值