2012-09-08 8 views
5

サーバから画像をダウンロードしてリストビューに表示するアプリケーションを作成しようとしています。私が作った問題は、メモリのリークで、アプリケーションがクラッシュすることでした。私はこのlinkのようなAndroidのブログで検索していましたが、それは素晴らしいアイデアを示していますが、まだ複数のスレッドでそれを行うには不十分です。アンドロイドのいくつかのデバイスは、それを使用することができますが、いくつかのデバイスは、単一のスレッドでのみ処理することができ、まったく動作しないことがあります。Androidから画像をダウンロードし、BitmapFactoryを使わずにsdcardに保存する

私のアプリケーションには多くのアクティビティがあり、それぞれにはできるだけ早くイメージを表示する必要があるListviewがあります。 Google IO 2012を使用すると、バッファを使用して元の画像をSDカードに保存し、問題を解決します。メモリをリークしますが、ダウンロードが必要な画像が大きすぎるため読み込みが遅くなります。

私の質問は:SDカードに画像を書き込んで画像を拡大縮小する方法はありますか? 私はいくつかの可能な解決策は、入力ストリームオブジェクトのスキップバイトを使用することであると私は、ダウンロードする必要がある画像のピクセルあたりビット幅と高さを見つけることができました。

次のコードはGoogle IO 2012で使用されていましたが、複数のスレッドでうまく動作します。私の場合、4スレッドがバックグラウンドで実行されています。

private void downloadAndWriteFile(final String url, final File file) throws OutOfMemoryError { 
    BufferedOutputStream out = null; 

    try { 
     HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection(); 
     conn.setDoInput(true); 
     conn.connect(); 

     final InputStream in = new BufferedInputStream(conn.getInputStream(), IO_BUFFER_SIZE_BYTES); // buffer size 1KB 
     out = new BufferedOutputStream(new FileOutputStream(file), IO_BUFFER_SIZE_BYTES); 

     int b; 
     while ((b = in.read()) != -1) { 
      out.write(b); 
     } 
     out.close(); 
     conn.disconnect(); 
    } 
    catch (Exception e) { 
     Log.e(TAG, "!!downloadAndWriteFile " + e.getMessage()); 
     file.delete(); 
    } 
} 

答えて

1

1)このビットマップに関連付けられているネイティブ・オブジェクトを解放し、画素データへの参照をクリアするためにあなたのイメージを設定する前に、次のコードを使用します。他の参照がない場合、ガベージコレクションを行うことができます。

BitmapDrawable drawable = (BitmapDrawable) myImage.getDrawable(); 
Bitmap bitmap = drawable.getBitmap(); 
if (bitmap != null) 
{ 
    bitmap.recycle(); 
} 

2)は、メモリ内のビットマップのサイズを小さくするために、このメソッドを使用します。

/** 
* decodes image and scales it to reduce memory consumption 
* 
* @param file 
* @param requiredSize 
* @return 
*/ 
public static Bitmap decodeFile(File file, int requiredSize) { 
    try { 

     // Decode image size 
     BitmapFactory.Options o = new BitmapFactory.Options(); 
     o.inJustDecodeBounds = true; 
     BitmapFactory.decodeStream(new FileInputStream(file), null, o); 

     // The new size we want to scale to 

     // Find the correct scale value. It should be the power of 2. 
     int width_tmp = o.outWidth, height_tmp = o.outHeight; 
     int scale = 1; 
     while (true) { 
      if (width_tmp/2 < requiredSize 
        || height_tmp/2 < requiredSize) 
       break; 
      width_tmp /= 2; 
      height_tmp /= 2; 
      scale *= 2; 
     } 

     // Decode with inSampleSize 
     BitmapFactory.Options o2 = new BitmapFactory.Options(); 
     o2.inSampleSize = scale; 

     Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(file), 
       null, o2); 

     return bmp; 

    } catch (FileNotFoundException e) { 
    } finally { 
     System.gc(); 
    } 
    return null; 
} 
+0

あなたの答えをありがとう、私はすでにこのケースを通過していましたが、JNIがより多くのメモリを割り当てることを許可しないデバイスでは、複数のスレッドでリークメモリを取得します。 Google IO 2012のコードは、すべてのデバイスをサポートする複数のスレッドで動作させることができますが、イメージが大きすぎると遅くなります。どういうわけか、ユーザーは最初に読み込んだアクティビティをすばやくナビゲートしているので、まったくうまくいきません。 – vsatkh

0

あなたがこれを使用することができます。

private void downloadImagesToSdCard(String downloadUrl,String imageName) { 
try { 
    URL url = new URL(downloadUrl); //you can write here any link 

    File myDir = new File("/sdcard"+"/"+Constants.imageFolder); 
    //Something like ("/sdcard/file.mp3") 


    if (!myDir.exists()) { 
     myDir.mkdir(); 
     Log.v("", "inside mkdir"); 

    } 

    Random generator = new Random(); 
    int n = 10000; 
    n = generator.nextInt(n); 
    String fname = imageName; 
    File file = new File (myDir, fname); 
    if (file.exists()) file.delete(); 

     /* Open a connection to that URL. */ 
     URLConnection ucon = url.openConnection(); 
     InputStream inputStream = null; 
     HttpURLConnection httpConn = (HttpURLConnection)ucon; 
     httpConn.setRequestMethod("GET"); 
     httpConn.connect(); 

     if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) { 
     inputStream = httpConn.getInputStream(); 
     } 

     /* 
     * Define InputStreams to read from the URLConnection. 
     */ 
     // InputStream is = ucon.getInputStream(); 
     /* 
     * Read bytes to the Buffer until there is nothing more to read(-1). 
     */ 

     FileOutputStream fos = new FileOutputStream(file); 
     int size = 1024*1024; 
     byte[] buf = new byte[size]; 
     int byteRead; 
     while (((byteRead = inputStream.read(buf)) != -1)) { 
      fos.write(buf, 0, byteRead); 
      bytesDownloaded += byteRead; 
     } 
     /* Convert the Bytes read to a String. */ 

     fos.close(); 

} catch(IOException io) { 
    networkException = true; 
    continueRestore = false; 
} catch(Exception e) { 
    continueRestore = false; 
    e.printStackTrace(); 
} 

}

0

ビットマップファクトリを使用せず、画像、そのエミュレータで動作していないが、任意のAndroid携帯電話が

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context=".MainActivity" > 

    <TableLayout 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentBottom="true" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentRight="true" 
     android:layout_alignParentTop="true" > 

     <TableRow 
      android:id="@+id/tableRow1" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" > 
     </TableRow> 

     <TableRow 
      android:id="@+id/tableRow2" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" > 

      <CheckedTextView 
       android:id="@+id/checkedTextView1" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Accel" /> 

     </TableRow> 

     <TableRow 
      android:id="@+id/tableRow3" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" > 

      <Button 
       android:id="@+id/button1" 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:text="Button" /> 

     </TableRow> 

     <TableRow 
      android:id="@+id/tableRow4" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" > 
     </TableRow> 
    </TableLayout> 

</RelativeLayout> 

finalscreen activity_main.xml

package com.example.filedownload; 


import org.apache.http.util.ByteArrayBuffer; 

import android.os.Bundle; 
import android.app.Activity; 
import android.util.Log; 
import android.view.Menu; 
import android.view.View; 
import android.widget.Button; 
import android.content.*; 
import android.app.*; 
import android.net.*; 
import android.app.DownloadManager.Request; 
import android.os.Environment; 
public class MainActivity extends Activity { 
    public long reference; 
    BroadcastReceiver receiver; 
    @Override 
     protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 


     Button button=(Button)findViewById(R.id.button1); 
       button.setOnClickListener(new View.OnClickListener() { 
       public void onClick(View v) { 


           String file = "http://tmacfitness.com/wp-content/uploads/2013/04/Beauty-of-nature-random-4884759-1280-800.jpg"; 
           String serviceString = Context.DOWNLOAD_SERVICE; 
           DownloadManager downloadManager; 
           downloadManager = (DownloadManager)getSystemService(serviceString); 
           Uri uri = Uri.parse(file); 
           DownloadManager.Request request ; 
           request = new Request(uri); 
           request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "accel.jpg"); 
           reference = downloadManager.enqueue(request); 



       } 

     }); 

     IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE); 
     receiver = new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
     long ref = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); 
     if (reference == ref) { 
     setContentView(R.layout.finalscreen); 
     unregister(); 
     } 
     } 
     }; 
     registerReceiver(receiver, filter); 
    } 
     public void unregister(){ 
      unregisterReceiver(receiver); 

    } 
} 

使用このコードのダウンロード.xml

関連する問題