دانلود تعدادی عکس از آدرس های اینترنتی (آدرس های URL) و ذخیره آنها در حافظه خارجی (External Storage) و نمایش آنها در برنامه اندروید، با قابلیت Cache کردن عکس ها به گونه ای که عکس هایی که قبلا دانلود شده اند، دوباره دانلود نشوند، در برنامه نویسی اندروید
در مباحثی دیگر، چگونگی نمایش یک عکس قرار گرفته در اینترنت (یک آدرس URL) را شرح دادیم ( آموزش شماره 294 و آموزش شماره 295 ). اما در آنها، عکس مورد نظر در حافظه خارجی (External Storage) ذخیره نمی شد و نگهداری آن به صورت موقت بود. اما در برنامه های اندرویدی که زیاد با دریافت عکس از اینترنت و نمایش آن، سر و کار دارند، اصلا به صرفه نیست که با هر بار اجرای برنامه اندروید، همه عکس ها از اینترنت دریافت شده و نمایش داده شوند، بلکه عکس هایی که دریافت می شوند را در محلی در حافظه خارجی (External Storage) ذخیره می کنند و هنگامی که قرار است یک عکس جدید دانلود شود، ابتدا چک می کنند که آیا عکس قبلا دانلود شده است یا نه، اگر قبلا دانلود شده باشد، به جای دانلود دوباره آن، تنها عکس را از حافظه خارجی (External Storage) می خوانند و نمایش می دهند. این فرآیند را عملیات Cache کردن می نامند.
دقت شود که کدهای مربوط به بخش دانلود و Cache کردن عکس ها را بنده قبلا از سایتی انگلیسی زبان دریافت کرده بودم، اما به دلیل گذشت زمانی طولانی، آدرس سایت مورد نظر را فراموش کرده ام (در غیر این صورت، لینک سایت مورد نظر را ذکر می کردم).
اکنون قصد داریم که یک پروژه اندروید بسازیم که در آن، سه ImageView تعریف می کنیم و سه عکس هم در اینترنت داریم که باید دانلود شده، در پوشه ای در حافظه خارجی (External Storage) ذخیره شوند و سپس در ImageView ها نمایش داده شوند. ذخیره سازی هم به صورت Cache کردن می باشد، یعنی برنامه اندروید ابتدا چک می کند که آیا عکس ها در پوشه مورد نظر در حافظه خارجی (External Storage)، قبلا ذخیره شده اند یا خیر.
فایل پروژه اندروید و همچنین فایل apk ساخته شده از آن را می توانید از انتهای مبحث دانلود نمایید.
سه عکس مورد نظر را در آدرس های اینترنتی (آدرس های URL) زیر قرار داده ایم :
http://www.kelidestan.com/fixed-url/Kelidestan_image_2.jpg
http://www.kelidestan.com/fixed-url/Kelidestan_image_3.jpg
آدرس های فوق، مربوط به پوشه fixed-url در سایت کلیدستان می باشند و نامگذاری این پوشه هم به این علت برابر fixed-url انتخاب شده است که مدیر سایت، تحت هیچ شرایطی این پوشه و فایل های درون آن را تغییر ندهد و بنابراین، برنامه نویسان بتوانند با خیال راحت، از فایل های موجود در آن استفاده کنند.
نام پروژه اندروید را برابر DownloadImageCache انتخاب کرده ایم (نام package برابر com.kelidestan.downloadimagecache انتخاب شده است. نام Activity اصلی را برابر MainActivity.java انتخاب کرده ایم و فایل xml متناظر آن را هم برابر activity_main.xml قرار داده ایم) :
حتما با دیدن ساختار پروژه اندروید در شکل بالا، متوجه شده اید که در این پروژه اندروید، به غیر از package اصلی با نام com.kelidestan.downloadimagecache (که Activity اصلی برنامه اندروید با نام MainActivity.java در آن قرار گرفته است)، یگ package دیگر نیز با نام com.kelidestan.imageloadercache داریم که 4 فایل در زیرمجموعه آن قرار گرفته اند :
در واقع، این 4 فایل، 4 کلاس (class) می باشند که عملیات مربوط به دانلود عکس، ذخیره کردن آن در حافظه خارجی (External Storage) و عملیات های مربوط به cache و همچنین نمایش عکس در یک ImageView را انجام می دهند. شاید این سوال پیش بیاید که چرا یک package جداگانه برای آنها ساخته ایم، پاسخ این است که در پروژه های اندروید، معمولا کلاس های مرتبط با هم را در package های جداگانه قرار می دهند تا در صورتی که تعداد کلاس ها (class) ها زیاد شود، آنگاه برنامه نویس گیج نشود و پروژه اندروید، دارای ساختاری منظم و غیر گیج کننده باشد. اگر در این مورد اطلاعات کافی ندارید، می توانید آموزش شماره 2670 را در مورد ساخت یک package جدید برای برنامه اندروید بخوانید.
این نوع ساختار به شما کمک می کند که مثلا اگر در یک پروژه اندروید دیگر نیاز به عملیات دانلود عکس و cache کردن آن داشتید، خیلی راحت، تنها فایل های موجود در package مورد نظر را به درون آن پروژه اندروید جدید کپی کنید.
قبل از اینکه به سراغ این فایل ها برویم، ابتدا بهتر است که اجازه های (permissions) مورد نیاز برای برنامه اندروید را در فایل AndroidManifest.xml ذکر کنیم. چون باید به اینترنت متصل شویم و همچنین باید قابلیت خواندن و نوشتن در حافظه خارجی (External Storage) را داشته باشیم، بنابراین باید اجازه های زیر به برنامه اندروید داده شود :
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
پس باید فایل AndroidManifest.xml از پروژه اندروید را باز کرده و کدهای بالا را در آن بنویسیم :
بنابراین کدهای فایل AndroidManifest.xml به صورت زیر خواهد بود :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kelidestan.downloadimagecache"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.kelidestan.downloadimagecache.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
بهتر است که همیشه در ابتدای ساخت پروژه اندروید، اجازه های (permissions) مورد نیاز برای آن را در فایل AndroidManifest.xml بنویسید، زیرا معمولا این موارد فراموش می شود و به همین دلیل، برنامه اندروید با force close (بسته شدن اجباری برنامه اندروید) روبرو می شود و برنامه نویس نیز به سختی دلیل آن را متوجه خواهد شد.
اکنون به سراغ 4 فایل مربوط به دانلود عکس، ذخیره کردن آن در حافظه خارجی (External Storage) و عملیات های مربوط به cache و همچنین نمایش عکس در یک ImageView می رویم :
کدهای فایل FileCache.java به صورت زیر می باشد :
import java.io.File;
import android.content.Context;
public class FileCache {
private File cacheDir;
public FileCache(Context context){
//Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"myFolder/.hidden_folder"); // point to folder be hidden
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
public File getFile(String url){
//I identify images by hashcode. Not a perfect solution, good for the demo.
String filename=String.valueOf(url.hashCode());
//Another possible solution (thanks to grantland)
//String filename = URLEncoder.encode(url);
File f = new File(cacheDir, filename);
return f;
}
public void clear(){
File[] files=cacheDir.listFiles();
if(files==null)
return;
for(File f:files)
f.delete();
}
}
همان طور که می دانید، باید پوشه ای را به عنوان محل نگهداری فایل های مربوط به ذخیره کردن (cache کردن) عکس ها در حافظه خارجی (External Storage) تعیین کنیم. این مورد، با خط زیر از کدها، تعیین شده است :
در واقع، با کد بالا تعیین کرده ایم که در مسیر اصلی پوشه بندی گوشی (محل پوشه بندی گوشی - پوشه root)، یک پوشه با نام myFolder ساخته شود و سپس درون آن، یک پوشه با نام .hidden_folder ساخته شود که فایل های مربوط به ذخیره کردن (cache کردن) عکس ها، در آن قرار خواهد گرفت. اما اگر دقت کرده باشید، در ابتدای نام پوشه دوم، علامت نقطه (.) را به کار برده ایم. به این دلیل که در اندروید، قرارداد است که اگر در ابتدای نام یک فایل یا پوشه، علامت نقطه (.) وجود داشته باشد، آن پوشه به صورت مخفی (hidden) خواهد بود ( آموزش شماره 365 ) و چون ما هم دوست نداریم که کاربران، فایل های مربوط به ذخیره کردن (cache کردن) را ببینند، این پوشه را به صورت مخفی (hidden) می سازیم. به هر حال، شما آدرس مورد نظرتان را برای این مسئله تعیین کنید و یا حتی اگر دوست داشتید، می توانید پوشه را به صورت غیر مخفی بسازید.
معمولا برنامه نویسان، کدهای خود را چند بار تست می کنند، بنابراین اگر کدهای برنامه اندروید را تغییر دادید و قصد داشتید که دوباره آن را از ابتدا تست کنید، حتما پوشه myFolder (یا هر نامی که خودتان انتخاب کرده اید) را حذف کنید تا دوباره از اول، عکس ها دانلود شوند و اگر کدهای بخش دانلود مشکلی داشتند، آن مشکل را متوجه بشوید. فکر کنم با بیان این نکته، حکمت آن را هم متوجه شده باشید که اصلا چرا پوشه مخفی را در پوشه بندی اصلی گوشی اندروید نساختیم و چرا آن را در پوشه ای با نام myFolder ساختیم (چون مخفی بود، حذف کردن آن سختتر می شد و باید در تنظیمات گوشی، تعیین می کردیم که پوشه های مخفی هم نمایش داده شوند و بعد برای حذف آن اقدام می کردیم).
کدهای فایل ImageLoader.java به صورت زیر می باشد :
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.ImageView;
import com.kelidestan.downloadimagecache.R;
public class ImageLoader {
MemoryCache memoryCache=new MemoryCache();
FileCache fileCache;
private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
public ImageLoader(Context context){
fileCache=new FileCache(context);
executorService=Executors.newFixedThreadPool(5);
}
final int stub_id=R.drawable.ic_launcher;
public void DisplayImage(String url, ImageView imageView)
{
imageViews.put(imageView, url);
Bitmap bitmap=memoryCache.get(url);
if(bitmap!=null)
imageView.setImageBitmap(bitmap);
else
{
queuePhoto(url, imageView);
imageView.setImageResource(stub_id);
}
}
private void queuePhoto(String url, ImageView imageView)
{
PhotoToLoad p=new PhotoToLoad(url, imageView);
executorService.submit(new PhotosLoader(p));
}
private Bitmap getBitmap(String url)
{
File f=fileCache.getFile(url);
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
//from web
try {
Bitmap bitmap=null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is=conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex){
ex.printStackTrace();
if(ex instanceof OutOfMemoryError)
memoryCache.clear();
return null;
}
}
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
//Task for the queue
private class PhotoToLoad
{
public String url;
public ImageView imageView;
public PhotoToLoad(String u, ImageView i){
url=u;
imageView=i;
}
}
class PhotosLoader implements Runnable {
PhotoToLoad photoToLoad;
PhotosLoader(PhotoToLoad photoToLoad){
this.photoToLoad=photoToLoad;
}
@Override
public void run() {
if(imageViewReused(photoToLoad))
return;
Bitmap bmp=getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url, bmp);
if(imageViewReused(photoToLoad))
return;
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
Activity a=(Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
boolean imageViewReused(PhotoToLoad photoToLoad){
String tag=imageViews.get(photoToLoad.imageView);
if(tag==null || !tag.equals(photoToLoad.url))
return true;
return false;
}
//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable
{
Bitmap bitmap;
PhotoToLoad photoToLoad;
public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}
public void run()
{
if(imageViewReused(photoToLoad))
return;
if(bitmap!=null)
photoToLoad.imageView.setImageBitmap(bitmap);
else
photoToLoad.imageView.setImageResource(stub_id);
}
}
public void clearCache() {
memoryCache.clear();
fileCache.clear();
}
}
با بزرگتر کردن عدد موجود در خط زیر از کدها می توانیم کیفیت عکس ها را بهتر کنیم (اگر از تغییر کیفیت عکس ها راضی نبودید، یک عدد بزرگتر انتخاب کنید) :
تا قبل از دانلود کامل عکس، یک عکس موقتی به جای آن در ImageView نمایش داده می شود، آن عکس را در خط زیر از کدها تعیین کرده ایم :
کدهای فایل MemoryCache.java به صورت زیر می باشد :
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import android.graphics.Bitmap;
import android.util.Log;
public class MemoryCache {
private static final String TAG = "MemoryCache";
private Map<String, Bitmap> cache=Collections.synchronizedMap(
new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering
private long size=0;//current allocated size
private long limit=1000000;//max memory in bytes
public MemoryCache(){
//use 25% of available heap size
setLimit(Runtime.getRuntime().maxMemory()/4);
}
public void setLimit(long new_limit){
limit=new_limit;
Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB");
}
public Bitmap get(String id){
try{
if(!cache.containsKey(id))
return null;
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
return cache.get(id);
}catch(NullPointerException ex){
ex.printStackTrace();
return null;
}
}
public void put(String id, Bitmap bitmap){
try{
if(cache.containsKey(id))
size-=getSizeInBytes(cache.get(id));
cache.put(id, bitmap);
size+=getSizeInBytes(bitmap);
checkSize();
}catch(Throwable th){
th.printStackTrace();
}
}
private void checkSize() {
Log.i(TAG, "cache size="+size+" length="+cache.size());
if(size>limit){
Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated
while(iter.hasNext()){
Entry<String, Bitmap> entry=iter.next();
size-=getSizeInBytes(entry.getValue());
iter.remove();
if(size<=limit)
break;
}
Log.i(TAG, "Clean cache. New size "+cache.size());
}
}
public void clear() {
try{
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
cache.clear();
size=0;
}catch(NullPointerException ex){
ex.printStackTrace();
}
}
long getSizeInBytes(Bitmap bitmap) {
if(bitmap==null)
return 0;
return bitmap.getRowBytes() * bitmap.getHeight();
}
}
کدهای فایل Utils.java به صورت زیر می باشد :
import java.io.InputStream;
import java.io.OutputStream;
public class Utils {
public static void CopyStream(InputStream is, OutputStream os)
{
final int buffer_size=1024;
try
{
byte[] bytes=new byte[buffer_size];
for(;;)
{
int count=is.read(bytes, 0, buffer_size);
if(count==-1)
break;
os.write(bytes, 0, count);
}
}
catch(Exception ex){}
}
}
اکنون باید کدهای مربوط به فایل xml متناظر با Activity اصلی برنامه اندروید (البته برنامه اندروید، تنها یک Activity دارد) را بنویسیم، یعنی فایل activity_main.xml :
کدهای فایل activity_main.xml را به صورت زیر می نویسیم :
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:src="@drawable/ic_launcher" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="300dp"
android:src="@drawable/ic_launcher" />
<ImageView
android:id="@+id/imageView3"
android:layout_width="match_parent"
android:layout_height="300dp"
android:src="@drawable/ic_launcher" />
</LinearLayout>
</ScrollView>
همان طور که در کدهای بالا مشاهده می کنید، سه عنصر ImageView تعریف کرده ایم، زیرا باید سه عکس در این سه ImageView نمایش داده شوند.
اکنون باید کدهای Activity اصلی برنامه اندروید (با نام MainActivity.java) را بنویسیم :
کدهای فایل MainActivity.java عبارتند از :
import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageView;
import com.kelidestan.imageloadercache.ImageLoader;
public class MainActivity extends Activity {
private ImageLoader imgLoader;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imgLoader = new ImageLoader(this); // important
ImageView iv_1 = (ImageView) findViewById(R.id.imageView1);
String image_url_1 = "http://www.kelidestan.com/fixed-url/Kelidestan_image_1.jpg";
imgLoader.DisplayImage(image_url_1, iv_1);
ImageView iv_2 = (ImageView) findViewById(R.id.imageView2);
String image_url_2 = "http://www.kelidestan.com/fixed-url/Kelidestan_image_2.jpg";
imgLoader.DisplayImage(image_url_2, iv_2);
ImageView iv_3 = (ImageView) findViewById(R.id.imageView3);
String image_url_3 = "http://www.kelidestan.com/fixed-url/Kelidestan_image_3.jpg";
imgLoader.DisplayImage(image_url_3, iv_3);
}
}
اکنون بخش های مهم آن را شرح می دهیم :
با خط زیر از کدها، یک شیء (object) از کلاس (class) با نام ImageLoader ساخته ایم (نام شیء را برابر imgLoader انتخاب کرده ایم و آن را به صورت private تعریف کرده ایم) :
دقت شود که کلاس ImageLoader ، توسط یکی از همان 4 فایلی که گفتیم، تعریف شده است :
بنابراین با روش های موجود در شیء imgLoader (که آنها را از کلاس ImageLoader به ارث برده است)، می توانیم عملیات های مربوط به دانلود عکس، ذخیره کردن آن در حافظه خارجی (External Storage) و عملیات های مربوط به cache و همچنین نمایش عکس در یک ImageView را انجام بدهیم.
این عملیات ها برای هر یک از سه ImageView ، مشابه می باشند. مثلا برای ImageView با id برابر imageView1 ، کدهای زیر نوشته شده است :
String image_url_1 = "http://www.kelidestan.com/fixed-url/Kelidestan_image_1.jpg";
imgLoader.DisplayImage(image_url_1, iv_1);
مشاهده می کنید که از روش DisplayImage از شیء imgLoader استفاده کرده ایم که دو ورودی را دریافت می کند. اولین ورودی، یک رشته (String) است که در آن، آدرس اینترنتی (آدرس URL) مربوط به فایل عکس، ذخیره شده است و دومین ورودی، آن ImageView ای است که می خواهیم عکس در آن نمایش داده شود.
ساخت پروژه اندروید تمام شد و اکنون می توانیم آن را تست کنیم. من یک فایل apk از آن می سازم و بر روی یک گوشی اندروید واقعی، آن را تست می کنم :
همچنین نگاهی به پوشه بندی گوشی اندروید می اندازیم و مشاهده می کنیم که پوشه با نام myFolder به درستی ساخته شده است :
درون پوشه myFolder هیچ فایلی وجود ندارد، زیرا تعیین کردیم که یک پوشه دیگر درون آن ساخته شود که چون علامت نقطه (.) در ابتدای نام آن است، به صورت پنهان (hidden) خواهد بود و کاربر نمی تواند آن را ببیند ( آموزش شماره 365 ) :
فایل های پروژه اندروید را می توانید از لینک های زیر دریافت کنید :
سلام و تشکر از مطالب مفیدتون.
چرا عکس هایی که از سرور گرفته میشن و در image view نمایش داده میشن، نسبت به عکس اصلی که در سایت قرار دادیم از کیفیت پایین تری برخوردارن؟
تفاوت کیفیت خیلی زیاده. چطور این مشکل رو حل کنیم؟؟؟
خودم متوجه شدم باید REQUEST_SIZE رو به مقدار بیشتری افزایش داد. مثلا 200
سلام با تشکر از مطالب مفیدتون یه سوال داشتم اینه چرا وقتی این کدها رو در پروژه دیگر استفاده می کنی چرا عکس ها را لود نمکند فقط عکس پیش فرض را نمایش میدهد و خطایی هم نمدهد.
سلام.
بررسی کنید که اجازه های دسترسی (permissions) که برای این پروژه اندروید ذکر کردیم، برای پروژه اندروید شما نیز ذکر شده باشد (در فایل AndroidManifest.xml) :
همچنین 4 فایل قرار گرفته در package با نام com.kelidestan.imageloadercache را باید در پروژه اندروید خود کپی کنید (4 فایل مورد نیاز برای دانلود عکس) و اگر نام package شامل آنها در پروژه اندروید شما متفاوت است، باید نام مورد نظر را در کد آن 4 فایل نیز تغییر بدهید. همچنین برای ارجاع به آنها در سایر Activity های پروژه اندروید، باید نام package شامل آنها را به درستی ذکر نمایید.
علاوه بر این موارد، از اتصال به اینترنت مطمئن شوید.
در حال حاضر، مورد دیگری به ذهن بنده نمی رسد، این موارد را بررسی کنید و اگر مجددا مشکل تکرار شد، توصیه می کنم که به خطایابی بپردازید (با استفاده از Log نویسی و دیدن پیام ها در LogCat ، فرآیند اجرای کدها را مرحله به مرحله چک کنید) :
با سلام و سپاس
این مشکل برای من هم بوجود آمد که متوجه شدم کلاس اکتیوتی از نوع ActionBarActivity مشتق کرده ام اگر از نوع اکتیویتی مشتق شود مشکل حل می شود. ولی من لازم دارم کلاس از نوع ActionBarActivity باشد.
لطفا بفرمایید راه حل چیست؟
سلام خسته نباشد
این کدها رو وقتی توی یه برنامه دیگه تو اندروید استادیو استفاده میکنیم عکس ها رو لود نمی کند در حالی که اجازه دسترسی ها و نام پکچ ها هم درست می باشد لطفا این کد ها رو برای اندروید استادیو هم تست کنید و منتشر کنید...
با تشکر و سپاس از زحماتتون.
کد های زیر را در قسمت (dependencies) از فایل Buil.gradle(Module app) در پروژهتون بنویسید و Synse را بزنید:
اگر فایل Buil.gradle(Module app) در ابتدا این باشه:
در نهایت اینجوری میشه:
سلام.
ابتدا از پروژه اندروید خود یک back up تهیه کنید (فایل های آن را در محل دیگری از کامپیوتر کپی نمایید تا اگر مشکلی پیش آمد، بتوانید از نسخه back up استفاده کنید)، سپس در برنامه Android Studio ، از منوی Build ، گزینه Rebuild Project را انتخاب نمایید :
سپس Sync Project with Gradle Files را اجرا کنید. از مسیر زیر :
سلام و ممنون از اموزشی ک قرار دادید ولی من یه سوال دارم. این اموزش واسه تعداد محدود عکس بود اگه من بخوام تعداد بیشتری عکس رو روی نرم افزار نشون بدم باید چیکار کنم. منظورم اینه که اگه امروز 4 عکس دارم ولی روزانه لازم دارم ک تعداد عکس ها رو بیشتر کنم بدون این ک لازم باشه نرم افزار اپدیت بشه باید چکار کنم؟ یعنی به ازای هر هر عکسی ک به یه پوشه داخل سایتم اضافه میشه خود نرم افزار یه ایمیج ویو واسم بسازه و اون عکس رو به عکسای قبلی اضافه کنه. ببخشید اگه بد توضیح دادم ولی خیلی واسم مهمه ک عکس ها هر روز اپدیت بشه بدون این ک عکسای قبلی پاک بشه. ممنون میشم جواب بدید
از گرید ویو (grid view) استفاده کنید و کد زیر را حتما در فایل اداپتر (Adapter) برنامه خودتون بنویسید:
سلام
تشکر از مطالب بسیار مفیدتون
لطفا آموزش بدید که اگه بخواییم بجای عکس چند تا ویدیو دانلود و ذخیره بشه چکار کنیم
ممنون
سلام اگه کسی جواب سوال بالایی رو داره ممنون میشم جواب بده
ممنونم از لطفتون.دعای خیر میکنم تو را
عالی بود . واقعا ممنون.
مشکل دانلود عکس توی برنامم داشتم هر چی توی سایت های خارجی گشتم چیز درست و حسابی پیدا نکردم و اینجا مشکلم به راحتی اب خوردن حل شد.
مرسی
سلام . با تشکر از اموزش خوبتون . من در یه adapter اجراش کردم اما اجرا نمیشه . ارور نمیده ولی صفحه باز نمیشه .
final ImageLoader imgLoader;
imgLoader = new ImageLoader(v.getContext());
String image_url_2 = "http://www.kelidestan.com/fixed-url/Kelidestan_image_2.jpg";
imgLoader.DisplayImage(image_url_2, holder.icon);
این کد هارو نوشتم holder هم تعریف کردم کامل فقط یه تغییری که اجرا کردم اینه که ImageLoader رو final کردم . از private برداشتم چون ارور میداد . میشه کمک کنید
خیلی ممنون از مطلب مفید و عالی تون
سلام اول اینکه بابت مطالب مفید شما سپاس. متاسفانه من هم همین مشکل رو دارم و عکس های پیش فرض نمایش داده میشن
سلام یه سوال داشتم
من میخوام از 4 تا لینک ثابت تو نرم افزارم عکس لود بشه و کاربر هر بار که اینترنتش روشن بود تو نرم افزار چک بشه اگه عکس ها تو سرور عوض نشده بودن که همون عکس های قدیمی رو نمایش بده اگه عکس ها تو سرور عوض شده بودن وقتی کاربر اینترنتش فعال بود عکس های اون imageview عوض بشه
به خاطر اینه که میخوام هر چند وقت یک بار عکس های برنامه آپدیت بشه
ولی مشکلم اینه که این آموزش رو انجام دادم عکس ها برای بار اول لود میشه ولی وقتی یه عکس رو تو یکی از لینک ها تغییر میدم عکس ها تغییر نمیکنه و همچنان همون عکس قدیمی رو نمایش میده
لطفا اگه میشه کمک کنید ممنون