【Android】内存卡图片读取器,图库app

上一篇《【Android】读取sdcard卡上的全部图片而且显示,读取的过程有进度条显示》(点击打开链接)在真机上測试非常有问题。常常遇到内存溢出。卡死的情况。由于如今真机上的内存上,2G已经非常少见了,基本上都8G的样子了。

由于把读取出来的图片一次性地放到app上,而且读取的过程中,又没有正在读取到哪个文件,尽管可以在AVD安卓模拟器上完毕主要的功能,可是这个app非常不友好。

因此採用Handler、Message配合线程等安卓消息机制。完毕读取过程,而且利用GridView把读取到的图片显示出来。改进这个内存卡图片读取器,详细效果例如以下,基本是可以媲美部分安卓系统自带的图库了吧……就差个对目录的分类而已了……

一開始。在读取的过程。有读取进度的显示,详细读取到哪个目录。

这对于大内存卡非常有意义。我的8G内存卡亲測,仅30秒完毕读取。

之后,用网格视图把图片显示出来。点击图片能够查看图片的大图。与图片的路径。

在app的右上角能够退出。

当然本app也完毕对返回键的监听。

返回键也可以退出。

这个在《【Android】各式各样的弹出框与对菜单键、返回键的监听》(点击打开链接)已经说过了,这里不再赘述。

1、首先改动res\values\strings.xml,设置各个字符,例如以下。作者什么的,请忽略这些细节!

<?xml version="1.0" encoding="utf-8"?

>
<resources>

    <string name="app_name">内存卡图片查看器</string>
    <string name="menu_author">作者:yongh701</string>
    <string name="menu_exit">退出</string>
    <string name="img_description">大图</string>
    <string name="view_button1">返回</string>

</resources>

2、之后改动菜单的字符文件res\menu\main.xml例如以下,一个配置到MainActivity.java其中,这个在《【Android】日期拾取器、时间拾取器与菜单》(点击打开链接)已经说过了。这里不再赘述。

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/menu_exit"
        android:title="@string/menu_exit"/>
    <item android:title="@string/menu_author"/>

</menu>

3、随后完毕AndroidManifest.xml的改动。要求系统对本app赋予SDCard的读写权限。同一时候。由于app查看大图要用还有一个Activity,这里同一时候在这里注冊查看大图的ViewActivity。该文件改动例如以下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sdcard_read_all"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- 要求向SDCard读取数据权限 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- 要求向SDCard写入数据权限 -->

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.sdcard_read_all.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>
        <activity
            android:name="com.sdcard_read_all.ViewActivity"
            android:label="@string/img_description" > <!-- 注冊ViewActivity -->
        </activity>
    </application>

</manifest>

4、事实上之后的过程,与《【Android】图片资源的訪问与网格式图片浏览器》(点击打开链接)是一样的。先改动MainActivity的布局文件res\layout\activity_main.xml,布置一个网格布局GridView。当然,同一时候布置一个TextView,用于在读取完毕之前。显示读取信息。此文件改动之后例如以下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="36sp" />

    <GridView
        android:id="@+id/gridView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="2" >
    </GridView>

</LinearLayout>

5、同一时候在res\layout\新建一个查看大图的的ViewActivity的布局文件activity_view.xml。这里和《【Android】画廊式的图片浏览器,使用HorizontalScrollView代替Gallery,OnClickListener的參数传递》(点击打开链接)同理。仅仅只是是在一个垂直滚动布局下。新建一个线性子布局LinearLayout。这样就不用操心组件的超过一屏,能够达到滚动效果。线性布局的滚动栏就是这样做的。三个组件皆沾满屏幕宽度,同一时候分别赋予id,一会儿通过ViewActivity.java赋予对应的值。当中图片视图ImageView配置的adjustViewBounds与scaleType。让其自己主动缩放大小。

android:contentDescription="@string/img_description"是图片的描写叙述,不赋予。Eclipse会出现警告。

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="24sp" />

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:adjustViewBounds="true"
            android:scaleType="centerInside"
            android:paddingTop="10dp"
            android:paddingBottom="10dp"
            android:contentDescription="@string/img_description" />

        <Button
            android:id="@+id/button1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/view_button1"
            android:textSize="24sp" />
    </LinearLayout>

</ScrollView>

6、在src\当前project包下(这里是com.sdcard_read_all)中。如《【Android】多个Activity之间利用bundle传递数值》(点击打开链接)一样,新建一个继承android.app.Activity的ViewActivity.java。里面代码例如以下:

package com.sdcard_read_all;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class ViewActivity extends Activity {
	private TextView textView1;
	private ImageView imageView1;
	private Button button1;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_view);
		//获取组件
		textView1 = (TextView) findViewById(R.id.textView1);
		imageView1 = (ImageView) findViewById(R.id.imageView1);
		button1 = (Button) findViewById(R.id.button1);
		//得到MainActivity传递过来的图片路径,进行对应的处理。
		Intent intent = getIntent();
		Bundle bundle = intent.getExtras();
		String imgPath = bundle.getString("imgPath");
		textView1.setText("图片路径:" + imgPath);
		Bitmap bm = BitmapFactory.decodeFile(imgPath);
		imageView1.setImageBitmap(bm);
		//按钮的返回事件
		button1.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				finish();
			}
		});

	}

	// 对物理按钮的监听
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		switch (keyCode) {
		case KeyEvent.KEYCODE_BACK:
			finish();// 关闭这个Activity。
			break;
		}
		return super.onKeyDown(keyCode, event);
	}
}

7、完毕了查看大图ViewActivity之后,便是我们的压轴大戏MainActivity,MainActivity也是整个程序的核心,代码例如以下。代码在结构上分为五部分:1、遍历sdcard的方法。2、载入图片的缓存工具方法,这两个方法与《【Android】读取sdcard卡上的全部图片而且显示。读取的过程有进度条显示》(点击打开链接)是相同的。

3、程序的运行onCreate方法,4、app的菜单,这《【Android】日期拾取器、时间拾取器与菜单》(点击打开链接)已经说过了。

5、对物理按键的监听。这能够參考《【Android】各式各样的弹出框与对菜单键、返回键的监听》(点击打开链接)。

程序的入口与其他安卓程序相同为onCreate方法。

程序的运行将会分成两部分:

1、读取时候。开一条读取进行,利用安卓的线程消息传递机制。不停在更新textView1。这与《【Android】进度条与线程之间的消息处理》(点击打开链接)事实上是同理。仅仅能这样完毕更新,通过安卓的线程消息传递机制,不至于app会出现死机的线程。安卓系统会自己主动对程序上的线程进行资源良好调度与分配。

之前的程序就由于对线程的处理不好,导致读大内存卡会卡死。如今通过安卓的线程消息传递机制读多大的内存卡也是没事的!

2、读取完成,与《【Android】图片资源的訪问与网格式图片浏览器》(点击打开链接)相同。利用适配器与网格视图,把全部图片显示。这里因为网格视图自带的适配器是自己主动会分配好资源的,因此占用系统资源也不大的。同一时候对网格视图赋予监听,点击图片传递图片路径,并打开查看大图ViewActivity。

package com.sdcard_read_all;

import java.io.File;
import java.util.ArrayList;

import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.TextView;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class MainActivity extends Activity {
	private TextView textView1;
	private GridView gridView1;
	private static Handler handler;// 线程消息处理器
	// 用于存放sdcard卡上的全部图片路径
	public static ArrayList<String> dirAllStrArr = new ArrayList<String>();

	// 用于遍历sdcard卡上全部文件的类
	public static void DirAll(File dirFile) throws Exception {
		if (dirFile.exists()) {
			File files[] = dirFile.listFiles();
			for (File file : files) {
				String fileName = file.getName();
				String filePath = file.getPath();
				// 读取文件路径,作为信息发送给handler进行处理
				Message msg = new Message();
				msg.obj = "正在读取:" + filePath;
				handler.sendMessage(msg);
				if (file.isDirectory()) {
					// 除sdcard上Android这个目录以外。
					if (!fileName.endsWith("Android")) {
						// 假设遇到目录则递归调用。

DirAll(file);
					}
				} else {
					// 假设是图片文件压入数组
					if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")
							|| fileName.endsWith(".bmp")
							|| fileName.endsWith(".gif")
							|| fileName.endsWith(".png")) {
						if (dirFile.getPath().endsWith(File.separator)) {
							dirAllStrArr
									.add(dirFile.getPath() + file.getName());
						} else {
							dirAllStrArr.add(dirFile.getPath() + File.separator
									+ file.getName());
						}
					}
				}
			}
		}
	}

	// 图片载入的缓存工具类,利用安卓自带的方法,依据大小压缩图片
	public static BitmapFactory.Options getHeapOpts(File file) {
		BitmapFactory.Options opts = new BitmapFactory.Options();
		// 数字越大读出的图片占用的内存必须越小,不然总是溢出
		if (file.length() < 20480) { // 0-20k
			opts.inSampleSize = 1;// 这里意为缩放的大小 ,数字越多缩放得越厉害
		} else if (file.length() < 51200) { // 20-50k
			opts.inSampleSize = 2;
		} else if (file.length() < 307200) { // 50-300k
			opts.inSampleSize = 4;
		} else if (file.length() < 819200) { // 300-800k
			opts.inSampleSize = 6;
		} else if (file.length() < 1048576) { // 800-1024k
			opts.inSampleSize = 8;
		} else {
			opts.inSampleSize = 10;
		}
		return opts;
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 获取组件
		textView1 = (TextView) findViewById(R.id.textView1);
		gridView1 = (GridView) findViewById(R.id.gridView1);
		// 线程開始之前。先把网格视图因此
		gridView1.setVisibility(View.INVISIBLE);
		/* 遍历sdcard旗下的全部目录的线程開始 */

		Thread readSdcard = new Thread() {
			private String sdpath = Environment.getExternalStorageDirectory()
					.getAbsolutePath();// 获取sdcard的根路径
			private File dirFile = new File(sdpath);

			public void run() {
				try {
					DirAll(dirFile);// 遍历sdcard旗下的全部目录
					// 完毕之后,在线程自身的消亡之前,发送一条“0”的标志信息。给handler
					Message msg = new Message();
					msg.obj = "0";
					handler.sendMessage(msg);
				} catch (Exception e) {
					e.printStackTrace();
				}
			};
		};
		textView1.setVisibility(View.VISIBLE);
		readSdcard.start();// 线程開始,默认不開始。

/* 遍历sdcard旗下的全部目录结束 */
		// 不停在接受线性的消息,依据消息。进行处理
		// 随着线程readSdcard的開始而出现。随其死亡而消亡。与线程是一对的。

		handler = new Handler(new Handler.Callback() {// 这样写。就不弹出什么泄漏的警告了
					@Override
					public boolean handleMessage(Message msg) {
						textView1.setText(msg.obj + "");
						if (msg.obj.equals("0")) {// 完毕读取之后
							textView1.setVisibility(View.GONE);// 隐藏读取信息
							gridView1.setVisibility(View.VISIBLE);// 显示网格视图
						}
						return false;
					}
				});

		// 网格视图适配器
		BaseAdapter baseAdapter = new BaseAdapter() {

			@Override
			public View getView(int position, View convertView, ViewGroup arg2) {
				ImageView imageView1;
				if (convertView == null) {
					imageView1 = new ImageView(MainActivity.this);
					imageView1.setAdjustViewBounds(true);// 自己主动缩放为宽高比
					imageView1.setScaleType(ScaleType.CENTER_INSIDE);// 设置图片保持宽高比显示
					imageView1.setPadding(5, 5, 5, 5);
				} else {
					imageView1 = (ImageView) convertView;
				}
				// 把图片载入到网格视图
				String filePath = dirAllStrArr.get(position);
				File file = new File(filePath);
				Bitmap bm = BitmapFactory.decodeFile(filePath,
						getHeapOpts(file));
				imageView1.setImageBitmap(bm);

				return imageView1;
			}

			// 获取当前选项
			@Override
			public long getItemId(int position) {
				return position;
			}

			@Override
			public Object getItem(int position) {
				return position;
			}

			// 获取数量
			@Override
			public int getCount() {
				return dirAllStrArr.size();
			}
		};
		gridView1.setAdapter(baseAdapter);// 把适配器与网格视图链接起来
		gridView1.setOnItemClickListener(new OnItemClickListener() {// 点击网格组件的随意一张图片时候的事件
					@Override
					public void onItemClick(AdapterView<?> arg0, View arg1,
							int position,// position为点击的id
							long arg3) {
						Intent intent = new Intent(MainActivity.this,
								ViewActivity.class);// 激活ViewActivity
						Bundle bundle = new Bundle();
						bundle.putString("imgPath", dirAllStrArr.get(position));// 传递点击的图片的id到ViewActivity
						intent.putExtras(bundle);
						startActivity(intent);
					}
				});
	}

	// 创建menu的方法,没有该方法。不会在右上角设置菜单。
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// 设置menu界面为res\menu\menu.xml
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	// 处理菜单事件
	public boolean onOptionsItemSelected(MenuItem item) {
		// 得到当前选中的MenuItem的ID,
		int item_id = item.getItemId();
		switch (item_id) {
		// 设置id为menu_exit的菜单子项所要运行的方法。
		case R.id.menu_exit:
			System.exit(0);// 结束程序
			break;
		}
		return true;
	}

	// 对物理button的监听
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		switch (keyCode) {
		case KeyEvent.KEYCODE_BACK:
			finish();// 关闭这个Activity。
			break;
		}
		return super.onKeyDown(keyCode, event);
	}

}

整个制作过程如上所看到的了,我还上传了一份Ecllipse,在ADT的编写源代码,大家有兴趣能够下载来看一下:

安卓读取SD卡上的全部图片(点击打开链接

时间: 2024-11-06 12:37:20

【Android】内存卡图片读取器,图库app的相关文章

OpenCV:基于MFC的视频播放器和图片读取器

实例工程包下载[OpenCV:基于MFC的视频播放器和图片读取器] 一.实现的功能 1.打开本地视频进行读取.播放.暂停.停止控制 2.图片打开功能分为两种:可使用"打开图片"按钮打开本地图片,或者点击comobox里面设定的图片列表选择并显示图片 二.编译环境 OS:Win8.1 x64 IDE:  Visual Studio 2013 OpenCV: 2.4.8 三.主要思路 1.视频的滑动条控制: ①主窗体的OnHScroll()响应函数负责响应slider滑动条的变化,这样就轻

Android资源图片读取机制

在新建一个Android项目时.在res目录下会自己主动生成几个drawable目录,drawable-ldpi,drawable-mdpi,drawable-hdpi,一直以来都对此不太清楚.图片应该放到哪个目录以下.有什么不同的影响?曾经一直都是干脆再新建一个不带后缀的drawable目录,图片都丢进去,如今决定彻底搞清楚这个事儿. 1.基础知识 density(密度):简单的说就是一个比例系数,用来将Dip(设备独立像素)转换成实际像素px.详细公式是: px = dip*density+

【Android】利用安卓的数据接口、多媒体处理编写内存卡Mp3播放器app

通过调用安卓的MediaPlayer可以直接完成Mp3等主流音频的播放,同时利用ContentResolver与Cursor可以直接读取安卓内在数据库的信息,直接获取当前sdcard中所有音频的列表,无须像<[Android]内存卡图片读取器,图库app>(点击打开链接)一样利用原始的Java代码去遍历整个sdcard卡,直接调用安卓固有的类既便捷又快速.最后,读取出来的Mp3可以通过适配器直接加载到ListView列表,做出如下所示的内存卡Mp3播放器app效果.本app在自己的真实的16G

Android笔记二十七.Bitmap之简易图片查看器

转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 为了增强用户之间的交互,Android系统中提供了一些API和部件给我们开发美观有趣的应用.比如Android系统提供了ImageView来显示静态图片.AnimationDrawble来开发逐帧动画以及通过Animation对普通图片使用不减动画等.另外,Android应用中的图片不仅包括*.png.*.jpg.*.gif等格式的位图,也包括使用XML资源文件定义的各种Drawable对象.关

Android中的图片查看器

本案例,使用Eclipse来开发Android2.1版本的图片查看器. 1)首先,打开Eclipse,新建一个Android2.1版本的项目ShowTu,打开res/values中目录下的strings.xml,将其中代码替换成一下代码: 路径:ShowTu/res/valus/string.xml <?xml version="1.0" encoding="utf-8"?> <resources> <string name="

Android 自学之网格试图(GridView)和图片切换器(ImageSwitcher)功能和用法

网格试图(GridView)用于在界面上按行,列分布的方式来显示多个组件. GridView和ListView有共同的父类:AbsListView,因此GridView和ListView具有一定的相似性.GridView和ListView的主要区别在于:ListView只是一个方向上的分布:而GridView则会在两个方向上分布. 与ListView相似的是,GridView也需要通过Adapter来提供显示数据:可以通过SimpleAdapter来为GridView提供数据,也可以通过开发Ba

Android图片查看器(图片可移动、缩放)

要实现图片在手指点击后移动和缩放有好几种方法,在这里是通过onTouch来实现的. 实例代码如下: 首先是在View中有一个ImageView <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_paren

Android 避免图片等资源泄露在系统图库当中

总结 Android避免文件泄露在系统图库和系统铃声中 在应用开发中 项目的图片总是被系统的图库收录了 避免图片被系统图库收录的发现有2个方法 第一种针对图片 将 .png为后缀的图片全部改名为 .ing 后缀 例如  ic_launcher.png   改为  ic_launcher.ing 第二种 在项目存放图片的文件夹写入 /.nomedia File nomedia = new File(filePath + "/.nomedia" ); if (! nomedia.exist

Android从相册读取图片

Uri originalUri = data.getData();        //获得图片的uri  bm = MediaStore.Images.Media.getBitmap(resolver, originalUri);         //显得到bitmap图片 imgShow.setImageBitmap(bm); http://blog.csdn.net/qq435757399/article/details/8118528 http://blog.csdn.net/dxj007