Android开发实用代码片段(一)

由于在开发中,常常会用到小功能或者属性或设置等,这些呢,我们也不会去记,经常去百度,但是过了段时间后呢,还是很容易忘记,又得去查。所以我决定了,以后对一些小代码段,收集记录下来,以备后用,所以此文会不断更新。

1.获取设备屏幕宽高

网络上代码段通常是这样的:

WindowManager wm = (WindowManager) getContext()
                    .getSystemService(Context.WINDOW_SERVICE);
 
     int width = wm.getDefaultDisplay().getWidth();
     int height = wm.getDefaultDisplay().getHeight();
或者

WindowManager wm = this.getWindowManager();
 
     int width = wm.getDefaultDisplay().getWidth();
     int height = wm.getDefaultDisplay().getHeight();

但是现在系统会提示我们,不建议使用类型Display的方法getHeight/getWidth。

所以我们可以使用下面的方法

public class MeasureUtil {
	public static int getScreenWidth(Context mContext) {
		int width = mContext.getResources().getDisplayMetrics().widthPixels;
		return width;
	}
	public static int getScreenHeight(Context mContext) {
		int height = mContext.getResources().getDisplayMetrics().heightPixels;
		return height;
	}
}

ps,通过getDisplayMetrics类,我们还可以获取一些其他的屏幕信息

DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        float density = displayMetrics.density; //屏幕密度
        int densityDpi = displayMetrics.densityDpi;//屏幕密度dpi
        int heightPixels = displayMetrics.heightPixels;//屏幕高度的像素
        int widthPixels = displayMetrics.widthPixels;//屏幕宽度的像素
        float scaledDensity = displayMetrics.scaledDensity;//字体的放大系数
        float xdpi = displayMetrics.xdpi;//宽度方向上的dpi
        float ydpi = displayMetrics.ydpi;//高度方向上的dpi

2.Dip和Px的相互转换

先讲下dip和px的区别吧

        dip: device independent pixels(设备独立像素). 不同设备有不同的显示效果,这个和设备硬件有关,一般我们为了支持WVGA、HVGA和QVGA 推荐使用这个,不依赖像素。 
    这里要特别注意dip与屏幕密度有关,而屏幕密度又与具体的硬件有关,硬件设置不正确,有可能导致dip不能正常显示。在屏幕密度为160的显示屏上,1dip=1px,有时候可能你的屏幕分辨率很大如480*800,但是屏幕密度没有正确设置比如说还是160,那么这个时候凡是使用dip的都会显示异常,基本都是显示过小。 
     dip的换算: 
           dip(value)=(int) (px(value)/1.5 + 0.5) 

px: pixels(像素),不同的设备不同的显示屏显示效果是相同的,这是绝对像素,是多少就永远是多少不会改变。

下面举个例子区别px和dip:
px就是像素,如果用px,就会用实际像素画,举个栗子,用画一条长度为240px的横线,在480分辨率宽的模拟器上看就是一半的屏宽,而在320分辨率宽的模拟器上看就是2/3的屏宽了。
而dip,就是把屏幕的高分成480分,宽分成320分。比如你做一条160dip的横线,无论你在320还480的模拟器上,都是一半屏的长度。

其实在安卓中,将屏幕密度为160dpi的中密度设备屏幕作为基准屏幕,在这个屏幕中,1dp=1px。其他屏幕密度的设备按照比例换算,具体如下表:

Android开发实用代码片段(一)_第1张图片

由上表不难计算1dp在hdpi设备下等于1.5px,同样的在xxhdpi设备下1dp=3px。这里我们从dp到px解释了Android中不同屏幕密度之间的像素比例关系。

/**
 * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
 */
public static int dip2px(Context context, float dpValue) {
 final float scale = context.getResources().getDisplayMetrics().density;
 return (int) (dpValue * scale + 0.5f);
}

/**
 * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
 */
public static int px2dip(Context context, float pxValue) {
 final float scale = context.getResources().getDisplayMetrics().density;
 return (int) (pxValue / scale + 0.5f);
}

说个题外话,在我们设计UI图片时,图片资源应该尽量放在高密度文件夹下,这样可以节省图片的内存开支,而UI在设计图片的时候也应该尽量面向高密度屏幕的设备来进行设计。就目前来讲,最佳放置图片资源的文件夹就是drawable-xxhdpi。参考链接Android drawable微技巧,你所不知道的drawable的那些细节。

3.更改Toast显示位置的技巧

在Android中,如果开发者需要通知用户发生了什么事,一般我们会选择Toast这个类,但是Toast的显示位置总是在同一个地方,不是很灵活,其实我们可以根据应用程序的布局不同,可以自由的显示Toast的位置。

Android开发实用代码片段(一)_第2张图片

要显示下图中Toast的显示位置,我们可以通过下面的代码来实现

setGravity(int gravity, int xOffset, int yOffset)

Toast toast = Toast.makeText(this, "我是一个Toast", Toast.LENGTH_LONG);
		toast.setGravity(Gravity.TOP | Gravity.CENTER, 0, 100);
		toast.show();
4.ScrollView嵌套ListView,滑动事件冲突解决方案
public class ListViewNoScroll extends ListView {  
    public ListViewNoScroll(Context context) {  
        super(context);  
    }  
  
    public ListViewNoScroll(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  
  
    @Override  
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,  
                MeasureSpec.AT_MOST);  
        super.onMeasure(widthMeasureSpec, expandSpec);  
    }  
  
}  
5.获取指定目录的文件夹下的所有文件名

主要是利用了递归算法

/**
     * @param path
     *            文件路径
     * @param suffix
     *            后缀名, 为空则表示所有文件
     * @param isdepth
     *            是否遍历子目录
     * @return list
     */
    public static List getListFiles(String path, String suffix, boolean isdepth) {
        List lstFileNames = new ArrayList();
        File file = new File(path);
        return MyTest.listFile(lstFileNames, file, suffix, isdepth);
    }

    private static List listFile(List lstFileNames, File f, String suffix, boolean isdepth) {
        // 若是目录, 采用递归的方法遍历子目录
        if (f.isDirectory()) {
            File[] t = f.listFiles();

            for (int i = 0; i < t.length; i++) {
                if (isdepth || t[i].isFile()) {
                    listFile(lstFileNames, t[i], suffix, isdepth);
                }
            }
        } else {
            String filePath = f.getAbsolutePath();
            if (!suffix.equals("")) {
                int begIndex = filePath.lastIndexOf("."); // 最后一个.(即后缀名前面的.)的索引
                String tempsuffix = "";

                if (begIndex != -1) {
                    tempsuffix = filePath.substring(begIndex + 1, filePath.length());
                    if (tempsuffix.equals(suffix)) {
                        lstFileNames.add(filePath);
                    }
                }
            } else {
                lstFileNames.add(filePath);
            }
        }
        return lstFileNames;
    }

6.context.getExternalFilesDir()和context.getExternalCacheDir()方法

应用程序在运行的过程中如果需要向手机上保存数据,一般是把数据保存在SDcard中的。

大部分应用是直接在SDCard的根目录下创建一个文件夹,然后把数据保存在该文件夹中。
这样当该应用被卸载后,这些数据还保留在SDCard中,留下了垃圾数据。
如果你想让你的应用被卸载后,与该应用相关的数据也清除掉,该怎么办呢?

通过Context.getExternalFilesDir()方法可以获取到 SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据
通过Context.getExternalCacheDir()方法可以获取到 SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据

如果使用上面的方法,当你的应用在被用户卸载后,SDCard/Android/data/你的应用的包名/ 这个目录下的所有文件都会被删除,不会留下垃圾信息。

而且上面二个目录分别对应 设置->应用->应用详情里面的”清除数据“与”清除缓存“选项。所以重要的,需要长期保存的文件不要放在此处。

/**
     * 获取Temp目录
     * @param context
     * @return
     */
    public static String GetTempFileSavePath(Context context)
    {
        if(context==null)
        {
            return "";
        }
        String strTempPath = "";
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
                || !Environment.isExternalStorageRemovable())
        {
            strTempPath = String.valueOf(context.getExternalCacheDir());
        }
        else
        {
            strTempPath = String.valueOf(context.getCacheDir());
        }

        if(strTempPath.equalsIgnoreCase("null"))
        {
            strTempPath = String.valueOf(context.getCacheDir());
        }
        if (!strTempPath.endsWith("/"))
        {
            strTempPath += "/";
        }

        File file = new File(strTempPath);
        if (!file.exists())
        {
            file.mkdirs();
        }
        return strTempPath;
    }

获取sd卡路径

 /**
     *  Android SD卡路径
     */
    public String getSDPath(){
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState()
                .equals(Environment.MEDIA_MOUNTED);   //判断sd卡是否存在
        if   (sdCardExist)
        {
            sdDir = Environment.getExternalStorageDirectory();//获取根目录
        }
        return sdDir.toString();
    }
使用时:在后面加上斜杠,在加上文件名 
String fileName = getSDPath() +"/" + name;//以name存在目录中

注意添加权限








假如出现以下错误

Android中的文件存储位置:java.io.FileNotFoundException: xxx: open failed: EROFS (Read-only file system)

保存文件时路径不对,貌似是少了个“/”。

最好用File fullFilename = new File(extDir, filename);  代替 File f2=new File(path);

7.对整个屏幕视图进行截屏并生成图片

Android中经常会遇到把View转换为Bitmap的情形,比如,对整个屏幕视图进行截屏并生成图片.

网上收集到有2种方法

 public static Bitmap convertViewToBitmap(View view, int bitmapWidth, int bitmapHeight){
        Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
        view.draw(new Canvas(bitmap));
        
        return bitmap;
    }
或者

public static Bitmap convertViewToBitmap(View view){
       view.buildDrawingCache();
    Bitmap bitmap = view.getDrawingCache();
    return bitmap; 
}
一般情况下,这2个方法能够正常的工作。但有时候,生成Bitmap会出现问题(Bitmap全黑色)。主要原因是 drawingCache的值大于系统给定的值。

较好的解决方案是

public static Bitmap convertViewToBitmap(View view){
      view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
        view.buildDrawingCache();
        Bitmap bitmap = view.getDrawingCache();

     return bitmap;
}
8.Android三种实现定时器的方法

方法一:Handler+Thread

import android.app.Activity;  
import android.os.Bundle;  
import android.os.Handler;  
import android.os.Message;  
import android.widget.TextView;  
  
/** 
 * handler定时器 
 *  
 */  
public class HanderDemoActivity extends Activity {  
    TextView tvShow;  
    private int i = 0;  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        tvShow = (TextView) findViewById(R.id.tv_show);  
        new Thread(new ThreadShow()).start();  
    }  
  
    // handler类接收数据  
    Handler handler = new Handler() {  
        public void handleMessage(Message msg) {  
            if (msg.what == 1) {  
                tvShow.setText(Integer.toString(i++));  
                System.out.println("receive....");  
            }  
        };  
    };  
  
    // 线程类  
    class ThreadShow implements Runnable {  
  
        @Override  
        public void run() {  
            // TODO Auto-generated method stub  
            while (true) {  
                try {  
                    Thread.sleep(1000);  
                    Message msg = new Message();  
                    msg.what = 1;  
                    handler.sendMessage(msg);  
                    System.out.println("send...");  
                } catch (Exception e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                    System.out.println("thread error...");  
                }  
            }  
        }  
    }  
}  
方法二:Handler类自带的postDelyed

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;

/**
 * handler定时器使用postDelyed实现
 * 
 */
public class HanderDemoActivity extends Activity {
	TextView tvShow;
	private int i = 0;
	private int TIME = 1000;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		tvShow = (TextView) findViewById(R.id.tv_show);
		handler.postDelayed(runnable, TIME); //每隔1s执行
	}

	Handler handler = new Handler();
	Runnable runnable = new Runnable() {

		@Override
		public void run() {
			// handler自带方法实现定时器
			try {
				handler.postDelayed(this, TIME);
				tvShow.setText(Integer.toString(i++));
				System.out.println("do...");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println("exception...");
			}
		}
	};

}
方法三:Handler+Timer+TimerTask
import java.util.Timer;  
import java.util.TimerTask;  
  
import android.app.Activity;  
import android.os.Bundle;  
import android.os.Handler;  
import android.os.Message;  
import android.widget.TextView;  
  
/** 
 * 定时器实现:Handler+Timer+TimerTask 
 *  
 */  
public class HanderDemoActivity extends Activity {  
    TextView tvShow;  
    private int i = 0;  
    private int TIME = 1000;  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        tvShow = (TextView) findViewById(R.id.tv_show);  
        timer.schedule(task, 1000, 1000); // 1s后执行task,经过1s再次执行  
    }  
  
    Handler handler = new Handler() {  
        public void handleMessage(Message msg) {  
            if (msg.what == 1) {  
                tvShow.setText(Integer.toString(i++));  
            }  
            super.handleMessage(msg);  
        };  
    };  
    Timer timer = new Timer();  
    TimerTask task = new TimerTask() {  
  
        @Override  
        public void run() {  
            // 需要做的事:发送消息  
            Message message = new Message();  
            message.what = 1;  
            handler.sendMessage(message);  
        }  
    };  
}  
综合比较三种方法,推荐第二个。因为第一个Thread.sleep会占用线程资源,当Sleep的时候,就等于说:现在我不用,但是你也别想用。虽然没占用CPU资源,但是阻碍了线程的调度。第三个话,在run方法中会不断的new 对象,为了实现定时,而不断创建对象而浪费资源,不合算。

9.Android 倒计时功能

主要是利用了CountDownTimer类

class TimeCount extends CountDownTimer {
		public TimeCount(long millisInFuture, long countDownInterval) {
			super(millisInFuture, countDownInterval);// 参数依次为总时长,和计时的时间间隔
		}

		@Override
		public void onFinish() {// 计时完毕时触发
			bt.setText("重新验证");
			bt.setClickable(true);
			bt.setBackgroundColor(0x77ffffff);
		}

		@Override
		public void onTick(long millisUntilFinished) {// 计时过程显示
			bt.setClickable(false);
			bt.setBackgroundColor(0x77cccccc);
			bt.setText("还剩下"+millisUntilFinished / 1000 + "秒");
		}
	}
要用的时候
mTimeCount=new TimeCount(10000, 1000);
		mTimeCount.start();

10,Android常用Http请求的封装

先定义请求结果返回的接口

/**
 * 回调服务返回的接口
 *
 */
public interface HttpCallbackListener {

	void onFinish(String response);

	void onError(Exception e);

}

请求代码

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import android.util.Log;

public class HttpUtil {
	public static void sendHttpRequest(final String address,
			final HttpCallbackListener httpCallbackListener) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				//HttpURLConnection
				HttpURLConnection connection = null;
				try {
					URL url = new URL(address);
					connection = (HttpURLConnection) url.openConnection();
					connection.setRequestMethod("GET");
					connection.setReadTimeout(8000);
					connection.setConnectTimeout(7000);
					InputStream is = connection.getInputStream();
					BufferedReader bReader = new BufferedReader(
							new InputStreamReader(is));
					StringBuilder response = new StringBuilder();
					String line;
					while ((line = bReader.readLine()) != null) {
						response.append(line);
					}
					if (httpCallbackListener != null) {
						// 回调onFinish()方法
						httpCallbackListener.onFinish(response.toString());
						Log.d("返回的数据是:-->", response.toString());
					}
				} catch (Exception e) {
					
					if (httpCallbackListener != null) {
						// 回调onError()方法
						httpCallbackListener.onError(e);
					}
				} finally {
					if (connection != null) {
						connection.disconnect();
					}
				}
			}
		}).start();
	}

}




如果对以上文章内容有疑惑,或存在不当之处,还请指出,共同进步!






你可能感兴趣的:(工具,Android)