1、对文件进行读写枷锁,使用了nio技术
RandomAccessFile randomFile = null;
byte[] buf = new byte[1024];
int count = 0;
try {
randomFile = new RandomAccessFile(new File(filePath), "rws");
FileChannel channel = randomFile.getChannel();
while ((count = is.read(buf)) > 0) {
FileLock lock = channel.tryLock();
randomFile.write(buf, 0, count);
lock.release();
}
return BitmapFactory.decodeFile(filePath);
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
if (randomFile != null)
try {
randomFile.close();
} catch (IOException e) {
e.printStackTrace();
}
closeStream(is, null);
}
2、当页面中需要横向滑动和纵向滑动时的时间判断机制:重写父view
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();//获取触摸事件类型
final float x = ev.getX();//每次触摸事件的x坐标
final float y = ev.getY();//每次触摸事件的y坐标
switch (action) {
case MotionEvent.ACTION_DOWN://按下事件
mLastMotionX = x;//初始化每次触摸事件的x方向的初始坐标,即手指按下的x方向坐标
mLastMotionY = y;//初始化每次触摸事件的y方向的初始坐标,即手指按下的y方向坐标
break;
case MotionEvent.ACTION_MOVE:
final intdeltaX = (int) (mLastMotionX - x);//每次滑动事件x方向坐标与触摸事件x方向初始坐标的距离
final intdeltaY = (int) (mLastMotionY - y);//每次滑动事件y方向坐标与触摸事件y方向初始坐标的距离
boolean xMoved = Math.abs(deltaX) > mTouchSlop && Math.abs(deltaY/deltaX) < 1;
//判断触摸事件处理的传递方向,该业务中是,
//x方向的距离大于手指,并且y方向滑动的距离小于x方向的滑动距离时,Gallery消费掉此次触摸事件
//如果需要,请在您的业务中,改变判断的逻辑
if (xMoved) {//Gallery需要消费掉此次触摸事件
return true;//返回true就不会将此次触摸事件传递给子View了,我的业务中是ListView
}
break;
}
return false;//将此次触摸事件传递给子View,即ListView
}
3、手机内存信息查看注释:
VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
4、查看单个应用内存使用情况命令:
查看单个应用程序内存占用量的命令:adb shell dumpsys meminfo [包名]|[进程号]
5、外置SD卡和手机内置内存:
public static File getDiskCacheDir(Context context, String uniqueName) {
// 先检查外部存储是否挂载,如果挂载了,则使用外存,否则使用内存路径
final String cachePath = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|| isExternalStorageRemovable() ? getExternalCacheDir(context).getPath() : context.getCacheDir()
.getPath();
return new File(cachePath + File.separator + uniqueName);
}
6、查看网络连接是否可用:
final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
if(networkInfo == null || !networkInfo.isConnectedOrConnecting()){
//提示用户设置网络:
Toast.makeText(context, R.string.no_network_connection_toast , Toast.LENGTH_SHORT).show();
Log.e(TAG, "checkConnection - no connection found");
}
7、获取目前该手机能显示指定宽度图片多少列:
mImageThumbSize = getResources().getDimensionPixelSize(R.dimen.image_thumbnail_size);
mImageThumbSpacing = getResources().getDimensionPixelSize(R.dimen.image_thumbnail_spacing);
int numColumns = (int) Math.floor(mGridView.getWidth() / (mImageThumbSize + mImageThumbSpacing));
//Adapter中这样设置:
public int getCount() {
// Size + number of columns for top empty row
return Images.imageThumbUrls.length + mNumColumns;
}
public Object getItem(int position) {
return position < mNumColumns ?
null : Images.imageThumbUrls[position - mNumColumns];
}
public long getItemId(int position) {
return position < mNumColumns ? 0 : position - mNumColumns;
}
8、图片下载缓存类使用方法:
先设置imageCacheParams
new ImageCacheParams(getActivity(), IMAGE_CACHE_DIR);
cacheParams.setMemCacheSizePercent(0.25f); // Set memory cache to 25% of app memory
创建一个mImageFetcher
设置下载完成之前要显示的图片
添加到缓存 addImageCache();
对ListView的滑动状态进行监听
onScrollStateChange(){
if(scrollState == .SCROLL_STATE_FLING{
mImageFetcher.setPauseWork(true);
}else{
mImageFetcher.setPauseWork(false);
}
}
然后
onResume
mImageFetcher.setExitTasksEarly(false);
onPause
mImageFetcher.setExitTasksEarly(true);
onDestory()
mImageFetcher.colseCache();
mImageFetcher.setImageSize(height);
使用的时候:
mImageFetcher.loadImage(Images.imageThumbUrls[position - mNumColumns], imageView);
int numColumns = (int) Math.floor(
mGridView.getWidth() / (mImageThumbSize + mImageThumbSpacing));
9、获取当前手机的宽高:
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
final int height = displayMetrics.heightPixels;
final int width = displayMetrics.widthPixels;
10、为了避免图片被重复下载,需要缓存图片。我可以通过获取头信息来保证我们的图片不过期(有效的缓存动态数据):
long currentTime = System.currentTimeMillis());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
long expires = conn.getHeaderFieldDate("Expires", currentTime);
long lastModified = conn.getHeaderFieldDate("Last-Modified", currentTime);
setDataExpirationDate(expires);
if (lastModified < lastUpdateTime) {
// Skip update
} else {
// Parse update
}
11、获取Android系统app的缓存路径:
//外部缓存,用来缓存不敏感的数据,在Froyo之后
Context.getExternalCacheDir();
//内部缓存,是安全的应用程序缓存,但是当系统低可用存储的是该部分可能被刷新
Context.getCache();
//不论你将数据存储在那种缓存中,当应用程序卸载后该数据都将被清除。
/**
* Get the external app cache directory.
*
* @param context The context to use
* @return The external cache dir
*/
@TargetApi(8)
public static File getExternalCacheDir(Context context) {
if (Utils.hasFroyo()) {
return context.getExternalCacheDir();
}
// Before Froyo we need to construct the external cache dir ourselves
final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/";
return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);
}
12、关于HttpURLConnection Response Cache:在Android 4.0中添加了HttpURLConnection响应的缓存,你可以用HTTP响应,在支持设备上使用反射缓存数据:
private void enableHttpResponseCache() {
try {
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
File httpCacheDir = new File(getCacheDir(), "http");
Class.forName("android.net.http.HttpResponseCache")
.getMethod("install", File.class, long.class)
.invoke(null, httpCacheDir, httpCacheSize);
} catch (Exception httpResponseCacheNotAvailable) {
Log.d(TAG, "HTTP response cache is unavailable.");
}
}
上面的这段代码在4.0以上设备中将打开response cache,并且不影响其他低版本
| |
/**
* Check how much usable space is available at a given path.
*
* @param path The path to check
* @return The space available in bytes
*/
@TargetApi(9)
public static long getUsableSpace(File path) {
if (Utils.hasGingerbread()) {
return path.getUsableSpace();
}
final StatFs stats = new StatFs(path.getPath());
return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();
}
14、标准下载实例:
/**
* Download something from a URL and write the content to an output stream.
*
* @param urlString The URL to fetch
* @return true if successful, false otherwise
*/
public boolean downloadUrlToStream(String urlString, OutputStream outputStream) {
disableConnectionReuseIfNecessary();
HttpURLConnection urlConnection = null;
BufferedOutputStream out = null;
BufferedInputStream in = null;
try {
final URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
in = new BufferedInputStream(urlConnection.getInputStream(), IO_BUFFER_SIZE);
out = new BufferedOutputStream(outputStream, IO_BUFFER_SIZE);
int b;
while ((b = in.read()) != -1) {
out.write(b);
}
return true;
} catch (final IOException e) {
Log.e(TAG, "Error in download- " + e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (final IOException e) {}
}
return false;
}
/**
* Workaround for bug pre-Froyo, see here for more info:
* http://android-developers.blogspot.com/2011/09/androids-http-clients.html
*/
public static void disableConnectionReuseIfNecessary() {
// HTTP connection reuse which was buggy pre-froyo
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
System.setProperty("http.keepAlive", "false");
}
}
15、Android屏幕解锁和点亮:
KeyguardManager km= (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
//得到键盘锁管理器对象
KeyguardLock kl = km.newKeyguardLock("unLock");
//参数是LogCat里用的Tag
kl.disableKeyguard(); //解锁
PowerManager pm=(PowerManager) getSystemService(Context.POWER_SERVICE);//获取电源管理器对象
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, "bright");
//获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是LogCat里用的Tag
wl.acquire();//点亮屏幕
wl.release();//释放
//需要的权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
16、查看android每帧的绘制时间:
在android4.1之上,setting->developter options->Force Gpu rendering。如果开发者选项在你的4.2设备上不可见,你可以在“关于手机”或者“关于桌面选择”的界面底部,点击“版本号”七次。(真的可以?)打开这个选项之后,系统将会记录每个窗口绘画最后128帧需要的时间。在使用这个工具前,你得先杀掉这个应用(Android未来版本将会去掉这个要求)。然后重新启动这个应用并滚动时间轴主界面时。在终端运行一下命令:
$ adb shell dumpsys gfxinfo packagename
将标记为Profile的毫秒级的数据,这段数据包含了一个有三列数据的表,应用的每个window都有一个这样的表,为了使用这个数据,你可以简单的讲这个表拷贝到你喜欢的电子制表软件中,从而生成一个数据堆叠的列图。每一列给出了每一帧花在渲染上的时间估计:
“Draw”是指Java层用在创建“display lists”(显示列表)上的时间。它表明运行例如View.onDraw(Canvas)需要多少时间。
“Process”是指Android 2D渲染引擎用在执行“display lists”上的时间。你的UI层级(hierarchy)中的View数量越多,需要执行的绘画命令就越多。
“Execute”是指将一帧图像交给合成器(compositor)的时间。这部分占用的时间通常比较少以60fps的帧率进行平滑的渲染,每一帧所占用的时间需要要少于16ms
17、也可以使用Systrace来检查问题,setting->developer options->Enable traces->在dialog中选择要监视的项目,比如Graphics、View。不要忘记关闭profile GPU rendering。然后在tools/systrace目录下,运行$./sysytrace.py这个工具默认会记录5秒内发生的事情。可以看到一个用HTML文档展现结果。
18、开启GPU视图更新之后,色块代表的意思:
如果你记得每种颜色所表示的含义,你就能很容易的知道结果是什么:
没有颜色就表示没有重绘。每个像素只画了一次。在这个例子里,你可以看到背景是完全无色的。
蓝色:表示重绘了一次。每个像素只画了两次。大块的蓝色是可以接受的。(如果整个window是蓝色的,你就可以使用一个图层(layer)。)
绿色:表示重绘了两次。每个像素画了三次。中等尺寸的绿色方块是可以接受的,但你最好尝试做出优化。
红色:表示重绘了三次。这个像素被画了四次。很小尺寸的红色方块是可以接受的。
黑色:表示重绘了四次及以上。这个像素被画了五次及以上。这个是错的,需要解决。
基于这些信息,你可以看到“设置”应用表现地很好,不需要额外的改进。只有在切换时有一点点红块,但不需要我们再做什么工作了。
19、当作为第三方包时,检查当前应用是否包含某权限(访问网络的权限):
Context.checkCallingOrSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED