首页 > 代码库 > 图片轮播_支持显示网络图片及下载图片至SD后再显示

图片轮播_支持显示网络图片及下载图片至SD后再显示

现在的移动应用, 很常见的一个交互效果就是在首页顶部添加图片轮播的控件, 焦点图可以放入广告, 也可以放入文章的内容图片, 它们不断自动切换, 点击焦点图即跳至对应的界面. 交互效果很棒. 做图片轮播的效果, 方法并不少. 本文使用了常见的viewpager 去实现. 支持显示网络图片下载在缓存显示, 如果有SD卡则默认将图片下载至SD卡中再显示本地的图片.

其实网上这类代码已经很多,  应该也有很多写得比我好. 今天有点时间, 就做了个来练手, 顺便写下自己第一篇原创文章. 敲代码之前也参考了一些网上的例子, 感谢那些大神!

好了,不多说别的, 直接上代码.(为了减少类的数量,  将一些方法直接写在主类中, 多多见谅哈~)


MainActivity:

/**
 * 图片轮播器<br>支持显示网络图片以及将网络图片下载至本地显示
 * @author Mr.ET
 *
 */
public class MainActivity extends Activity{
	
	private List<ImageView> mImageViewList = null;
	private List<View> mViewList = null;
	private TextView mArticleTitle = null;
	private ViewPager mViewPager = null;
	private Handler mHandler = null;
	private LinearLayout mCustomSpace = null;
	private MyPagerAdapter adapter = null;
	private boolean loopPlayState = false;
	private View view;
	
	//private final String mySign = "url";
	private List<String> tList,pList,nList;
	private List<Bitmap> bList;
	//private int p1 = -1,p2 = -1,p3 = -1,p4 = -1;
	private String name;
	//图片总数
	private final int pAccount = 4;
	//控制图片变量
	private int pNum = 0;
	private int readStyle = -1;
	private final static int readInNet = 0;
	private final static int readInSD = 1;
	private final static int readInCache = 2;
	
	
	private Handler handler = new Handler(){
		@Override
		public void handleMessage(Message msg) {
			if(msg.what == 0x111){
				if(bList != null && bList.size() > 0 && readStyle != readInNet) bList.clear();
				if(mImageViewList != null && mImageViewList.size() > 0) mImageViewList.clear();
				//图片已备齐,可以设置pager图片
				for(int i=0;i<pList.size();i++){
					ImageView imageView = new ImageView(MainActivity.this);
					imageView.setLayoutParams(new LayoutParams(
							LayoutParams.MATCH_PARENT,
							LayoutParams.MATCH_PARENT));
					imageView.setScaleType(ScaleType.FIT_XY);
					imageView.setOnClickListener(new ClickListener(i));
					mImageViewList.add(imageView);
					view = new View(MainActivity.this);
					LayoutParams layoutParams = new LayoutParams(14, 14);
					layoutParams.setMargins(3, 0, 3, 0);
					view.setLayoutParams(layoutParams);
					view.setBackgroundResource(R.drawable.dot_normal);
					mViewList.add(view);
					mCustomSpace.addView(view);
					if(readStyle != readInNet){
						BitmapFactory.Options options = new BitmapFactory.Options();
						options.inSampleSize = 2;
						Bitmap bm = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/demo/"+nList.get(i)+".jpg", options);
						bList.add(bm);
					}
				}
				adapter = new MyPagerAdapter();
				mViewPager.setAdapter(adapter);
				mViewPager.setOnPageChangeListener(new MyPageChangeListener());
				
				if (!loopPlayState) {
					mArticleTitle.setText(tList.get(0));
					mViewPager.setCurrentItem(0);
					mHandler.postDelayed(loopPlay, 3000);
					loopPlayState = true;
				}
			}
			super.handleMessage(msg);
		}
	};
	
	
	public void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		mViewPager = (ViewPager)findViewById(R.id.viewpager);
		mArticleTitle = (TextView)findViewById(R.id.article_title);
		mCustomSpace = (LinearLayout)findViewById(R.id.custom_space);
		mHandler = new Handler();
		mImageViewList = new ArrayList<ImageView>();
		mViewList = new ArrayList<View>();
		
		
		tList = new ArrayList<String>();
		pList = new ArrayList<String>();
		nList = new ArrayList<String>();
		bList = new ArrayList<Bitmap>();
		for(int i=0;i<4;i++){ tList.add("这是标题"+i); }
		pList.add("http://b.hiphotos.baidu.com/image/pic/item/203fb80e7bec54e767710215bb389b504fc26a1f.jpg");
		pList.add("http://d.hiphotos.baidu.com/image/pic/item/32fa828ba61ea8d37e6f6c0f950a304e251f586f.jpg");
		pList.add("http://g.hiphotos.baidu.com/image/pic/item/e1fe9925bc315c605aeb75e48fb1cb13495477ba.jpg");
		pList.add("http://h.hiphotos.baidu.com/image/pic/item/d000baa1cd11728bd0359429cafcc3cec3fd2ca4.jpg");
		
		
		readyToImage();
		
	}
	
	/**
	 * 下载图片前的准备 <br>主要根据有无SD卡来准备图片是下载在本地还是放在内存中
	 */
	public void readyToImage(){
		if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){	//有SD卡
			String folderPath = Environment.getExternalStorageDirectory().getAbsolutePath()+"/demo";
			File demoFile = new File(folderPath);
			if(!demoFile.exists()){ //不存在这个文件夹,即不存在所需的图片. 就启动线程去下载图片
				readStyle = readInSD;
				for(int p=0;p<pList.size();p++){
					DLPThread mythread = new DLPThread(pList.get(p));
					mythread.start();
				}
			}else{
				File[] files = demoFile.listFiles();
				if(files.length >= 4 && isImage(getFileType(files[0].getName())) && isImage(getFileType(files[1].getName()))
						&& isImage(getFileType(files[2].getName())) && isImage(getFileType(files[3].getName()))){
					readStyle = readInCache;
					for(int i=0;i<4;i++){ nList.add(files[i].getName()); }
					mainSetImage();
				}else{	//下载图片
					readStyle = readInSD;
					for(int p=0;p<pList.size();p++){
						DLPThread mythread = new DLPThread(pList.get(p));
						mythread.start();
					}
				}
			}
		}else{	//无SD卡
			readStyle = readInNet;
			for(int p=0;p<pList.size();p++){
				DLPThread mythread = new DLPThread(pList.get(p));
				mythread.start();
			}
		}
	}
	
	
	/**
	 * 线程下载图片至本地
	 * @author Mr.ET
	 *
	 */
	class DLPThread extends Thread{
		private String url;
		
		public DLPThread(String url){
			this.url = url;
		}
		
		public void run(){
			try {
				Looper.prepare();
				Bitmap bitmap = (Bitmap)utils.requestGet(this.url, Bitmap.class);
				name = String.valueOf(System.currentTimeMillis());
				nList.add(name);	//存放文件名
				if(readStyle != readInNet){
					File folder = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/demo");
					if(!folder.exists()){
						folder.mkdir();
					}
					String path = folder + "/"+name+".jpg";
					File file = new File(path);
					FileOutputStream fileOutputStream = new FileOutputStream(file);
					bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream);
					fileOutputStream.flush();
					fileOutputStream.close();
				}else{	//无SD卡
					bList.add(bitmap);
				}
				
				pNum ++;
				setImage();
				Looper.loop();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
	} 
	
	
	public void setImage(){
		if(pNum == pAccount){
			handler.sendEmptyMessage(0x111);
		}
	}
	
	
	private final class MyPagerAdapter extends PagerAdapter {

		@Override
		public int getCount() {
			return mImageViewList.size();
		}

		@Override
		public void destroyItem(ViewGroup container, int position, Object object) {
			((ViewPager) container).removeView(mImageViewList.get(position));
		}

		@Override
		public Object instantiateItem(ViewGroup container, int position) {
			ImageView temp = mImageViewList.get(position);
			temp.setImageBitmap(bList.get(position));
			
			((ViewPager) container).addView(temp);
			return temp;
		}

		@Override
		public boolean isViewFromObject(View arg0, Object arg1) {
			return arg0 == arg1;
		}

	}
	
	
	
	/**
	 * 当ViewPager中页面的状态发生改变时调用
	 * 
	 * @author Mr.ET
	 * 
	 */
	private class MyPageChangeListener implements OnPageChangeListener {

		private int historyPosition = 0;

		/**
		 * 当ViewPager中页面的状态发生改变时调用
		 */
		public void onPageSelected(int position) {
			mArticleTitle.setText(tList.get(position));
			mViewList.get(historyPosition).setBackgroundResource(
					R.drawable.dot_normal);
			mViewList.get(position).setBackgroundResource(
					R.drawable.dot_focused);
			historyPosition = position;
		}

		public void onPageScrollStateChanged(int arg0) {
		}

		public void onPageScrolled(int arg0, float arg1, int arg2) {
		}
	}
	
	/**
	 * 设置自动间隔3秒自动切换图片
	 */
	Runnable loopPlay = new Runnable() {
		@Override
		public void run() {
			int position = mViewPager.getCurrentItem();
			if(position == (pList.size()-1)){
				position = 0;
				mViewPager.setCurrentItem(position);
			}
			else{
				Log.i("position++", "position++="+position++);
				mViewPager.setCurrentItem(position++);
			}
			mHandler.postDelayed(loopPlay, 3000);
			
		}
	};
	
	
	private class ClickListener implements OnClickListener{
		private int location;
		public ClickListener(int location){
			this.location = location;
		}
		
		@Override
		public void onClick(View v){
			Toast.makeText(MainActivity.this, "你点击了第"+this.location+"张的图片", 1000).show();
		}
	}
	
	
	/**
	 * 获取文件类型
	 * @param fileName
	 * @return
	 */
	public static String getFileType(String fileName) {
        if (fileName != null) {
                int typeIndex = fileName.lastIndexOf(".");
                if (typeIndex != -1) {
                        String fileType = fileName.substring(typeIndex + 1)
                                        .toLowerCase();
                        return fileType;
                }
        }
        return "";
	}
	
	/**
	 * 判断是否图片
	 * @param type
	 * @return
	 */
	public static boolean isImage(String type) {
        if (type != null
                        && (type.equals("jpg") || type.equals("gif")
                                        || type.equals("png") || type.equals("jpeg")
                                        || type.equals("bmp") || type.equals("wbmp")
                                        || type.equals("ico") || type.equals("jpe"))) {
                return true;
        }
        return false;
	}
	
	
	/**
	 * 直接从SD获取图片显示
	 */
	public void mainSetImage(){
		if(bList != null && bList.size() > 0) bList.clear();
		if(mImageViewList != null && mImageViewList.size() > 0) mImageViewList.clear();
		//图片已备齐,可以设置pager图片
		for(int i=0;i<4;i++){
			ImageView imageView = new ImageView(MainActivity.this);
			imageView.setLayoutParams(new LayoutParams(
					LayoutParams.MATCH_PARENT,
					LayoutParams.MATCH_PARENT));
			imageView.setScaleType(ScaleType.FIT_XY);
			imageView.setOnClickListener(new ClickListener(i));
			mImageViewList.add(imageView);
			view = new View(MainActivity.this);
			LayoutParams layoutParams = new LayoutParams(14, 14);
			layoutParams.setMargins(3, 0, 3, 0);
			view.setLayoutParams(layoutParams);
			view.setBackgroundResource(R.drawable.dot_normal);
			mViewList.add(view);
			mCustomSpace.addView(view);
			BitmapFactory.Options options = new BitmapFactory.Options();
			options.inSampleSize = 2;
			Bitmap bm = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getAbsolutePath()+ "/demo/"+nList.get(i), options);
			bList.add(bm);
		}
		adapter = new MyPagerAdapter();
		mViewPager.setAdapter(adapter);
		mViewPager.setOnPageChangeListener(new MyPageChangeListener());
		
		if (!loopPlayState) {
			mArticleTitle.setText(tList.get(0));
			mViewPager.setCurrentItem(0);
			mHandler.postDelayed(loopPlay, 3000);
			loopPlayState = true;
		}
	}
	
	
	
}

utils, 里面也简单的封装一下httpclient. 

public class utils {
	private static DefaultHttpClient httpClient;
	
	
	
	static{
		if(null == httpClient){
			HttpParams httpParams = new BasicHttpParams();
			
			HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
			HttpProtocolParams.setContentCharset(httpParams, HTTP.UTF_8);
			HttpProtocolParams.setUseExpectContinue(httpParams, true);
			
			
	        ConnManagerParams.setMaxTotalConnections(httpParams, 10);  
	        ConnManagerParams.setTimeout(httpParams, 60000);  
	        ConnPerRouteBean connPerRoute = new ConnPerRouteBean(8);
	        ConnManagerParams.setMaxConnectionsPerRoute(httpParams,connPerRoute);  
	        HttpConnectionParams.setConnectionTimeout(httpParams, 20000);
	        HttpConnectionParams.setSoTimeout(httpParams, 30000);
			
			SchemeRegistry schreg = new SchemeRegistry();
			schreg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
			schreg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
			
			ClientConnectionManager connManager = new ThreadSafeClientConnManager(httpParams, schreg);
			
			httpClient = new DefaultHttpClient(connManager, httpParams);
			
		}
	}
	
	
	public static HttpClient getHttpClient(){
		return httpClient;
	}
	
	
	public static Object requestGet(String url,Class<?>c){
		try {
			HttpGet httpGet = new HttpGet(url);
			HttpResponse response = httpClient.execute(httpGet);
			if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
				byte[] b = readInputStream(response.getEntity().getContent());
				if(c == String.class){
					String resultStr = new String(b);
					return resultStr;
				}
				if(c == Bitmap.class){
					Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
//					BitmapFactory.Options options = new BitmapFactory.Options();
//					options.inSampleSize = 10;
//					Bitmap bitmap = BitmapFactory.decodeStream(response.getEntity().getContent(), null, options);
					return bitmap;
				}
				
			}else{
				//sorry, can not ask for the http server......
			}
			
			
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return null;
	}
	
	
	
	private static byte[] readInputStream(InputStream in) throws Exception {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] b = new byte[1024];
		int len = 0;
		while ((len = in.read(b)) != -1) {
			baos.write(b, 0, len);
		}
		in.close();
		return baos.toByteArray();
	}
	
	
	
	
}

下面是用到的资源文件

dot_focused.xml :

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" >

    <solid android:color="#aaFFFFFF" />

    <corners android:radius="50dip" />

</shape>

dot_normal.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" >

    <solid android:color="#33000000" />

    <corners android:radius="5dip" />

</shape>



主要思路:

先判断手机是否有SD卡: 1, 有SD卡. 将图片下载至SD卡中, 图片轮播将图片转为bitmap, 显示在imageview中.  2, 无SD卡. 将图片下载至缓存中, 直接转为bitmap并显示在imageview中.  

第二种方法很不好, 因为每次打开应用都要发HTTP请求去下载图片,再来显示, 而HTTP请求是相当耗资源的操作,  严重影响交互. 所以请尽量减少无谓的HTTP请求. 当你的应用第一次安装, 这个时候就去下载这四个图片放在本地,  这是必须的,  因为这时候本地一张图片都没有嘛. 然后当用户继续操作应用, 比如继续看新闻看别的文章的时候,  可以在后台启动个线程 去 检查这四张图片的接口有无更新,  如果有更新, 再启动线程将图片悄悄的下载在本地中 , 并更新图片轮播的内容. 这样, 当用户下次再启动应用的时候, 图片轮播加载图片的速度就快了哦. 这是其中之一的思路. 具体还要看应用的需求,  在实现上有所变化.

代码中有注释, 也很简单. 应该很容易看懂吧.

例子写的不够简洁, 也还有不少可以优化的地方, 奈何时间有限, 请多包涵. 咱们互相学习, 一起进步吧. ^^


代码下载



图片轮播_支持显示网络图片及下载图片至SD后再显示