Android开发常用工具总结


什么是AIDL以及如何使用

获取总内存及可用内存

private String getAvailMemory() {// 获取android当前可用内存大小 ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo mi = new MemoryInfo();
am.getMemoryInfo(mi);//mi.availMem; 当前系统的可用内存 return Formatter.formatFileSize(getBaseContext(), mi.availMem);// 将获取的内存大小规格化 
}
private String getTotalMemory() {
String str1 = "/proc/meminfo";// 系统内存信息文件 
String str2;
String[] arrayOfString;
long initial_memory = 0;try {
FileReader localFileReader = new FileReader(str1);
BufferedReader localBufferedReader = new BufferedReader(
localFileReader, 8192);
str2 = localBufferedReader.readLine();// 读取meminfo第一行,系统总内存大小 arrayOfString = str2.split("\\s+");
for (String num : arrayOfString) {
Log.i(str2, num + "\t");
}
initial_memory = Integer.valueOf(arrayOfString[1]).intValue() * 1024;// 获得系统总内存,单位是KB,乘以1024转换为Byte 
localBufferedReader.close();} catch (IOException e) {
}
return Formatter.formatFileSize(getBaseContext(), initial_memory);// Byte转换为KB或者MB,内存大小规格化 
}

dp、px转换

 /** * 根据手机的分辨率从 dip 的单位 转成为 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);  } 

程序的安装与卸载

安装:Intent intent = new Intent(Intent.ACTION_VIEW);  intent.setDataAndType(Uri.fromFile(new File("/sdcard/xxx.apk")),   "application/vnd.android.package-archive");  MainActivity.this.startActivity(intent);  卸载:Uri uri = Uri.parse("package:com.xxx.xxx(包名)");  Intent intent2 = new Intent(Intent.ACTION_DELETE, uri);     MainActivity.this.startActivity(intent2); 

根据URI获取真实路径

    public static String getRealFilePath( final Context context, final Uri uri ) {if ( null == uri ) return null;final String scheme = uri.getScheme();String data = null;if ( scheme == null )data = uri.getPath();else if ( ContentResolver.SCHEME_FILE.equals( scheme ) ) {data = uri.getPath();} else if ( ContentResolver.SCHEME_CONTENT.equals( scheme ) ) {Cursor cursor = context.getContentResolver().query( uri, new String[] { ImageColumns.DATA }, null, null, null );if ( null != cursor ) {if ( cursor.moveToFirst() ) {int index = cursor.getColumnIndex( ImageColumns.DATA );if ( index > -1 ) {data = cursor.getString( index );}}cursor.close();}}return data;}

关闭开启网络

  public static void setDataConnectionState(Context cxt, boolean state) {     ConnectivityManager connectivityManager = null;Class connectivityManagerClz = null;try {connectivityManager = (ConnectivityManager) cxt.getSystemService("connectivity");connectivityManagerClz = connectivityManager.getClass();Method method = connectivityManagerClz.getMethod("setMobileDataEnabled", new Class[] { boolean.class });method.invoke(connectivityManager, state);} catch (Exception e) {e.printStackTrace();}}

还原短信

    ContentValues values = new ContentValues();values.put("address", "123456789");values.put("body", "haha");values.put("date", "135123000000");getContentResolver().insert(Uri.parse("content://sms/sent"), values);

横竖屏切换

< activity android:name="MyActivity"  
android:configChanges="orientation|keyboardHidden"> public void onConfigurationChanged(Configuration newConfig) {  super.onConfigurationChanged(newConfig);  if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {  //加入横屏要处理的代码  }else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {  //加入竖屏要处理的代码  }    
}  

获取mac地址

1、<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>    
2private String getLocalMacAddress() {  WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);  WifiInfo info = wifi.getConnectionInfo();  return info.getMacAddress();  }  

获取SD卡状态

/** 获取存储卡路径 */ 
File sdcardDir=Environment.getExternalStorageDirectory(); 
/** StatFs 看文件系统空间使用情况 */ 
StatFs statFs=new StatFs(sdcardDir.getPath()); 
/** Block 的 size*/ 
Long blockSize=statFs.getBlockSize(); 
/** 总 Block 数量 */ 
Long totalBlocks=statFs.getBlockCount(); 
/** 已使用的 Block 数量 */ 
Long availableBlocks=statFs.getAvailableBlocks(); 

获取状态栏和标题栏的高度


1.Android获取状态栏高度:decorView是window中的最顶层view,可以从window中获取到decorView,然后decorView有个getWindowVisibleDisplayFrame方法可以获取到程序显示的区域,包括标题栏,但不包括状态栏。于是,我们就可以算出状态栏的高度了。Rect frame = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;2.获取标题栏高度:getWindow().findViewById(Window.ID_ANDROID_CONTENT)这个方法获取到的view就是程序不包括标题栏的部分,然后就可以知道标题栏的高度了。int contentTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
//statusBarHeight是上面所求的状态栏的高度
int titleBarHeight = contentTop - statusBarHeight例子代码:package com.cn.lhq;
import android.app.Activity;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.widget.ImageView;
public class Main extends Activity {ImageView iv;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);iv = (ImageView) this.findViewById(R.id.ImageView01);iv.post(new Runnable() {public void run() {viewInited();}});Log.v("test", "== ok ==");}private void viewInited() {Rect rect = new Rect();Window window = getWindow();iv.getWindowVisibleDisplayFrame(rect);int statusBarHeight = rect.top;int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();int titleBarHeight = contentViewTop - statusBarHeight;// 测试结果:ok之后 100多 ms 才运行了Log.v("test", "=-init-= statusBarHeight=" + statusBarHeight+ " contentViewTop=" + contentViewTop + " titleBarHeight="+ titleBarHeight);}
}<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><ImageView android:id="@+id/ImageView01" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
</LinearLayout>

获取各种窗体高度

  //取得窗口属性getWindowManager().getDefaultDisplay().getMetrics(dm);//窗口的宽度int screenWidth = dm.widthPixels;//窗口高度int screenHeight = dm.heightPixels;textView = (TextView)findViewById(R.id.textView01);textView.setText("屏幕宽度: " + screenWidth + "\n屏幕高度: " + screenHeight);二、获取状态栏高度
decorView是window中的最顶层view,可以从window中获取到decorView,然后decorView有个getWindowVisibleDisplayFrame方法可以获取到程序显示的区域,包括标题栏,但不包括状态栏。 
于是,我们就可以算出状态栏的高度了。
view plainRect frame = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;三、获取标题栏高度
getWindow().findViewById(Window.ID_ANDROID_CONTENT)这个方法获取到的view就是程序不包括标题栏的部分,然后就可以知道标题栏的高度了。
view plainint contentTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
//statusBarHeight是上面所求的状态栏的高度
int titleBarHeight = contentTop - statusBarHeight

获取内外置存储卡路径

/** 获取存储卡路径 */
File sdcardDir=Environment.getExternalStorageDirectory(); 
/** StatFs 看文件系统空间使用情况 */
StatFs statFs=new StatFs(sdcardDir.getPath()); 
/** Block 的 size*/
Long blockSize=statFs.getBlockSize(); 
/** 总 Block 数量 */
Long totalBlocks=statFs.getBlockCount(); 
/** 已使用的 Block 数量 */
Long availableBlocks=statFs.getAvailableBlocks(); private static String getStoragePath(Context mContext, boolean is_removale) {  StorageManager mStorageManager = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);Class<?> storageVolumeClazz = null;try {storageVolumeClazz = Class.forName("android.os.storage.StorageVolume");Method getVolumeList = mStorageManager.getClass().getMethod("getVolumeList");Method getPath = storageVolumeClazz.getMethod("getPath");Method isRemovable = storageVolumeClazz.getMethod("isRemovable");Object result = getVolumeList.invoke(mStorageManager);final int length = Array.getLength(result);for (int i = 0; i < length; i++) {Object storageVolumeElement = Array.get(result, i);String path = (String) getPath.invoke(storageVolumeElement);boolean removable = (Boolean) isRemovable.invoke(storageVolumeElement);if (is_removale == removable) {return path;}}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}return null;
}通过反射的方式使用在sdk中被 隐藏 的类 StroageVolume 中的方法getVolumeList(),获取所有的存储空间(Stroage Volume),然后通过参数is_removable控制,来获取内部存储和外部存储(内外sd卡)的路径,参数 is_removable为false时得到的是内置sd卡路径,为true则为外置sd卡路径。在API 23 Enviroment 类中的内部类 UserEnvironment 中有一方法getExternalDirs与此一样,代码如下:public File[] getExternalDirs() {final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId,StorageManager.FLAG_FOR_WRITE);final File[] files = new File[volumes.length];for (int i = 0; i < volumes.length; i++) {files[i] = volumes[i].getPathFile();}return files;
}再看Enviroment的getExternalStorageDirectory方法实现:public static File getExternalStorageDirectory() {throwIfUserRequired();return sCurrentUser.getExternalDirs()[0];
}可以看出,在API 23时,先是通过getExternalDirs()获取到所有存储空间的File[]数组,这个数组的第一个值:getExternalDirs()[0],即为内置sd卡所在路径。而在API 23 之前的版本中,并没有类似getExternalDirs()的方法通过StorageVolume直接获得存储空间(Storage Volume),而时通过别的方式来实现的,看关键方法的源码:
public static File getExternalStorageDirectory() {throwIfUserRequired();return sCurrentUser.getExternalDirsForApp()[0];
}这里的 getExternalDirsForApp() 和上面的 getExternalDirs() 的作用是一样的,都是得到所有存储空间的File[]数组。public File[] getExternalDirsForApp() {return mExternalDirsForApp;
}

捕获Application全局异常

/** * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告. *  * *  */  
public class CrashHandler implements UncaughtExceptionHandler {  public static final String TAG = "CrashHandler";  //系统默认的UncaughtException处理类   private Thread.UncaughtExceptionHandler mDefaultHandler;  //CrashHandler实例  private static CrashHandler INSTANCE = new CrashHandler();  //程序的Context对象  private Context mContext;  //用来存储设备信息和异常信息  private Map<String, String> infos = new HashMap<String, String>();  //用于格式化日期,作为日志文件名的一部分  private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");  /** 保证只有一个CrashHandler实例 */  private CrashHandler() {  }  /** 获取CrashHandler实例 ,单例模式 */  public static CrashHandler getInstance() {  return INSTANCE;  }  /** * 初始化 *  * @param context */  public void init(Context context) {  mContext = context;  //获取系统默认的UncaughtException处理器  mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();  //设置该CrashHandler为程序的默认处理器  Thread.setDefaultUncaughtExceptionHandler(this);  }  /** * 当UncaughtException发生时会转入该函数来处理 */  @Override  public void uncaughtException(Thread thread, Throwable ex) {  if (!handleException(ex) && mDefaultHandler != null) {  //如果用户没有处理则让系统默认的异常处理器来处理  mDefaultHandler.uncaughtException(thread, ex);  } else {  try {  Thread.sleep(3000);  } catch (InterruptedException e) {  Log.e(TAG, "error : ", e);  }  //退出程序  android.os.Process.killProcess(android.os.Process.myPid());  System.exit(1);  }  }  /** * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. *  * @param ex * @return true:如果处理了该异常信息;否则返回false. */  private boolean handleException(Throwable ex) {  if (ex == null) {  return false;  }  //使用Toast来显示异常信息  new Thread() {  @Override  public void run() {  Looper.prepare();  Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG).show();  Looper.loop();  }  }.start();  //收集设备参数信息   collectDeviceInfo(mContext);  //保存日志文件   saveCrashInfo2File(ex);  return true;  }  /** * 收集设备参数信息 * @param ctx */  public void collectDeviceInfo(Context ctx) {  try {  PackageManager pm = ctx.getPackageManager();  PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);  if (pi != null) {  String versionName = pi.versionName == null ? "null" : pi.versionName;  String versionCode = pi.versionCode + "";  infos.put("versionName", versionName);  infos.put("versionCode", versionCode);  }  } catch (NameNotFoundException e) {  Log.e(TAG, "an error occured when collect package info", e);  }  Field[] fields = Build.class.getDeclaredFields();  for (Field field : fields) {  try {  field.setAccessible(true);  infos.put(field.getName(), field.get(null).toString());  Log.d(TAG, field.getName() + " : " + field.get(null));  } catch (Exception e) {  Log.e(TAG, "an error occured when collect crash info", e);  }  }  }  /** * 保存错误信息到文件中 *  * @param ex * @return  返回文件名称,便于将文件传送到服务器 */  private String saveCrashInfo2File(Throwable ex) {  StringBuffer sb = new StringBuffer();  for (Map.Entry<String, String> entry : infos.entrySet()) {  String key = entry.getKey();  String value = entry.getValue();  sb.append(key + "=" + value + "\n");  }  Writer writer = new StringWriter();  PrintWriter printWriter = new PrintWriter(writer);  ex.printStackTrace(printWriter);  Throwable cause = ex.getCause();  while (cause != null) {  cause.printStackTrace(printWriter);  cause = cause.getCause();  }  printWriter.close();  String result = writer.toString();  sb.append(result);  try {  long timestamp = System.currentTimeMillis();  String time = formatter.format(new Date());  String fileName = "crash-" + time + "-" + timestamp + ".log";  if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {  String path = "/sdcard/crash/";  File dir = new File(path);  if (!dir.exists()) {  dir.mkdirs();  }  FileOutputStream fos = new FileOutputStream(path + fileName);  fos.write(sb.toString().getBytes());  fos.close();  }  return fileName;  } catch (Exception e) {  Log.e(TAG, "an error occured while writing file...", e);  }  return null;  }  
}  在收集异常信息时,朋友们也可以使用Properties,因为Properties有一个很便捷的方法properties.store(OutputStream out, String comments),用来将Properties实例中的键值对外输到输出流中,但是在使用的过程中发现生成的文件中异常信息打印在同一行,看起来极为费劲,所以换成Map来存放这些信息,然后生成文件时稍加了些操作。
完成这个CrashHandler后,我们需要在一个Application环境中让其运行,为此,我们继承android.app.Application,添加自己的代码,CrashApplication.java代码如下:public class CrashApplication extends Application {  @Override  public void onCreate() {  super.onCreate();  CrashHandler crashHandler = CrashHandler.getInstance();  crashHandler.init(getApplicationContext());  }  
} /** * 网络是否可用 *  * @param context * @return */  public static boolean isNetworkAvailable(Context context) {  ConnectivityManager mgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);  NetworkInfo[] info = mgr.getAllNetworkInfo();  if (info != null) {  for (int i = 0; i < info.length; i++) {  if (info[i].getState() == NetworkInfo.State.CONNECTED) {  return true;  }  }  }  return false;  }  

禁止Home键

 问题的提出Android Home键系统负责监听,捕获后系统自动处理。有时候,系统的处理往往不随我们意,想自己处理点击Home后的事件,那怎么办?问题的解决先禁止Home键,再在onKeyDown里处理按键值,点击Home键的时候就把程序关闭,或者随你XXOO。@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event){ // TODO Auto-generated method stubif(KeyEvent.KEYCODE_HOME==keyCode)android.os.Process.killProcess(android.os.Process.myPid());return super.onKeyDown(keyCode, event);}
@Overridepublic void onAttachedToWindow(){ // TODO Auto-generated method stubthis.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);super.onAttachedToWindow();}
加权限禁止Home键
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"></uses-permission>

开机启动

public class StartupReceiver extends BroadcastReceiver {  @Override  public void onReceive(Context context, Intent intent) {  Intent startupintent = new Intent(context,StrongTracks.class);  startupintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  context.startActivity(startupintent);  }  }  
2)<receiver  
android:name=".StartupReceiver">  
<intent-filter>  <!-- 系统启动完成后会调用 -->  <action  android:name="android.intent.action.BOOT_COMPLETED">  </action>  
</intent-filter>  
</receiver> 

控制对话框位置

 window =dialog.getWindow();//    得到对话框的窗口.  WindowManager.LayoutParams wl = window.getAttributes();  wl.x = x;//这两句设置了对话框的位置.0为中间  wl.y =y;  wl.width =w;  wl.height =h;  wl.alpha =0.6f;// 这句设置了对话框的透明度   

模拟器错误

1、找到android模拟器安装目录:C:\Documents and Settings\Administrator\.android\avd\AVD23.avd
2、编辑config.ini文件,就是这块配置错误导致错误产生。
3、如果硬盘空间比较紧张,可以把模拟器文件放到其它盘符上:你可以在命令行下用mkcard创建一个SDCARD文件,如: mksdcard 50M D:\sdcard.img
4、下面代码可以整个覆盖原来的config文件 hw.sdCard=yes hw.lcd.density=240 skin.path=800×480 skin.name=800×480 vm.heapSize=24 sdcard.path=D:\sdcard.img hw.ramSize=512 image.sysdir.1=platforms\android-8\images\
5、OK,模拟器正常运行

挪动dialog的位置

Window mWindow = dialog.getWindow();  
WindowManager.LayoutParams lp = mWindow.getAttributes();  
lp.x = 10;   //新位置X坐标  
lp.y = -100; //新位置Y坐标  
dialog.onWindowAttributesChanged(lp);

屏幕适配

常见手机屏幕像素及对应分别率级别:ldpi 320*240     mdpi 480*320     hdpi 800*480xhdpi 1280*720xxhdpi 1920*1080dp和px之间的简单换算关系:ldpi的手机 1dp=0.75pxmdpi的手机 1dp=1.0pxhdpi的手机 1dp=1.5pxxhdpi的手机 1dp=2.0pxxxhdpi的手机 1dp=3.0px
名词解释:分辨率:eg:480*800,1280*720。表示物理屏幕区域内像素点的总和。(切记:跟屏幕适配没有任何关系)因为我们既可以把1280*720的分辨率做到4.0的手机上面。我也可以把1280*720的分辨率做到5.0英寸的手机上面,如果分辨率相同,手机屏幕越小清晰。px(pix):像素,就是屏幕中最小的一个显示单元dpi(像素密度):即每英寸屏幕所拥有的像素数,像素密度越大,显示画面细节就越丰富。计算公式:像素密度=√{(长度像素数^2+宽度像素数^2)}/ 屏幕尺寸注:屏幕尺寸单位为英寸 例:分辨率为1280*720 屏幕宽度为6英寸 计算所得像素密度约等于245,屏幕尺寸指屏幕对角线的长度。1、屏幕适配方式都有哪些1.1 适配方式之dp1.2 适配方式之dimens在values-1280x720中,中间的是大写字母X的小写形式x,而不是加减乘除的乘号。如果我们在values-1280x720中放置了dimens常量,一定记得也将该常量的对应值在values目录下的dimens.xml中放一份,因为该文件是默认配置,当用户的手机不是1280*720的情况下系统应用使用的是默认values目录中的dimens.xml。1.3 适配方式之layout跟values一样,在Android工程目录中layout目录也支持类似values目录一样的适配,在layout中我们可以针对不同手机的分辨率制定不同的布局1.4 适配方式之java代码适配为了演示用java代码控制适配的效果,因此假设有这样的需求,让一个TextView控件的宽和高分别为屏幕的宽和高的一半。//获取TextView控件TextView tv  = (TextView) findViewById(R.id.tv);//找到当前控件的夫控件(父控件上给当前的子控件去设定一个规则)DisplayMetrics metrics  = new DisplayMetrics();//给当前metrics去设置当前屏幕信息(宽(像素)高(像素))getWindowManager().getDefaultDisplay().getMetrics(metrics);//获取屏幕的高度和宽度Constant.srceenHeight = metrics.heightPixels;Constant.srceenWidth = metrics.widthPixels;//日志输出屏幕的高度和宽度Log.i(tag, "Constant.srceenHeight = "+Constant.srceenHeight);Log.i(tag, "Constant.srceenWidth = "+Constant.srceenWidth);//宽高各 50%RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(//数学角度上 四舍五入(int)(Constant.srceenWidth*0.5+0.5), (int)(Constant.srceenHeight*0.5+0.5));//给tv控件设置布局参数tv.setLayoutParams(layoutParams);1.5适配方式之weight权重适配在控件中使用属性android:layout_weight="1"可以起到适配效果,但是该属性的使用有如下规则:1、只能用在线性控件中,比如LinearLayout。2、竖直方向上使用权重的控件高度必须为0dp(Google官方的推荐用法)3、水平方向上使用权重的控件宽度必须为0dp(Google官方的推荐用法)2、屏幕适配的处理技巧都有哪些手机自适应主要分为两种情况:横屏和竖屏的切换,以及分辨率大小的不同。2.1横屏和竖屏的切换1、Android应用程序支持横竖屏幕的切换,Android中每次屏幕的切换动会重启Activity,所以应该在Activity销毁(执行onPause()方法和onDestroy()方法)前保存当前活动的状态;在Activity再次创建的时候载入配置,那样,进行中的游戏就不会自动重启了!有的程序适合从竖屏切换到横屏,或者反过来,这个时候怎么办呢?可以在配置Activity的地方进行如下的配置android:screenOrientation="portrait"(landscape是横向,portrait是纵向)。这样就可以保证是竖屏总是竖屏了。2、而有的程序是适合横竖屏切换的。如何处理呢?首先要在配置Activity的时候进行如下的配置:
android:configChanges="keyboardHidden|orientation",另外需要重写Activity的onConfigurationChanged方法。实现方式如下:@Override
public void onConfigurationChanged(Configuration newConfig){super.onConfigurationChanged(newConfig);if(this.getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE){//TODO}else if(this.getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT){//TODO}
}2.2 分辨率大小不同对于分辨率问题,官方给的解决办法是创建不同的layout文件夹,这就需要对每种分辨率的手机都要写一个布局文件,虽然看似解决了分辨率的问题,但是如果其中一处或多处有修改了,就要每个布局文件都要做出修改,这样就造成很大的麻烦。那么可以通过以下几种方式解决:一)使用layout_weight目前最为推荐的Android多屏幕自适应解决方案。该属性的作用是决定控件在其父布局中的显示权重,一般用于线性布局中。其值越小,则对应的layout_width或layout_height的优先级就越高(一般到100作用就不太明显了);一般横向布局中,决定的是layout_width的优先级;纵向布局中,决定的是layout_height的优先级。传统的layout_weight使用方法是将当前控件的layout_width和layout_height都设置成fill_parent,这样就可以把控件的显示比例完全交给layout_weight;这样使用的话,就出现了layout_weight越小,显示比例越大的情况(即权重越大,显示所占的效果越小)。不过对于2个控件还好,如果控件过多,且显示比例也不相同的时候,控制起来就比较麻烦了,毕竟反比不是那么好确定的。于是就有了现在最为流行的0px设值法。看似让人难以理解的layout_height=0px的写法,结合layout_weight,却可以使控件成正比例显示,轻松解决了当前Android开发最为头疼的碎片化问题之一。二)清单文件配置:【不建议使用这种方式,需要对不同的界面写不同的布局】需要在AndroidManifest.xml文件的<manifest>元素如下添加子元素<supports-screensandroid:largeScreens="true"android:normalScreens="true"android:anyDensity="true"android:smallScreens="true" android:xlargeScreens="true"></supports-screens>以上是为我们的屏幕设置多分辨率支持(更准确的说是适配大、中、小三种密度)。Android:anyDensity="true",这一句对整个的屏幕都起着十分重要的作用,值为true,我们的应用程序当安装在不同密度的手机上时,程序会分别加载hdpi,mdpi,ldpi文件夹中的资源。相反,如果值设置为false,即使我们在hdpi,mdpi,ldpi,xdpi文件夹下拥有同一种资源,那么应用也不会自动地去相应文件夹下寻找资源。而是会在大密度和小密度手机上加载中密度mdpi文件中的资源。有时候会根据需要在代码中动态地设置某个值,可以在代码中为这几种密度分别设置偏移量,但是这种方法最好不要使用,最好的方式是在xml文件中不同密度的手机进行分别设置。这里地图的偏移量可以在values-xpdi,values-hpdi,values-mdpi,values-ldpi四种文件夹中的dimens.xml文件进行设置。三)、其他:说明:在不同分辨率的手机模拟器下,控件显示的位置会稍有不同通过在layout中定义的布局设置的参数,使用dp(dip),会根据不同的屏幕分辨率进行适配但是在代码中的各个参数值,都是使用的像素(px)为单位的技巧:1、尽量使用线性布局,相对布局,如果屏幕放不下了,可以使用ScrollView(可以上下拖动)ScrowView使用的注意:在不同的屏幕上显示内容不同的情况,其实这个问题我们往往是用滚动视图来解决的,也就是ScrowView;需要注意的是ScrowView中使用layout_weight是无效的,既然使用ScrowView了,就把它里面的控件的大小都设成固定的吧。2、指定宽高的时候,采用dip的单位,dp单位动态匹配3、由于android代码中写的单位都是像素,所有需要通过工具类进行转化4、尽量使用9-patch图,可以自动的依据图片上面显示的内容被拉伸和收缩。其中在编辑的时候,灰色区域是被拉伸的,上下两个点控制水平方向的拉伸,左右两点控制垂直方向的拉伸3、dp和px之间的关系dp:是dip的简写,指密度无关的像素。指一个抽象意义上的像素,程序用它来定义界面元素。一个与密度无关的,在逻辑尺寸上,与一个位于像素密度为160dpi的屏幕上的像素是一致的。要把密度无关像素转换为屏幕像素,可以用这样一个简单的公式:pixels=dips*(density/160)。举个例子,在DPI为240的屏幕上,1个DIP等于1.5个物理像素。布局时最好使用dp来定义我们程序的界面,因为这样可以保证我们的UI在各种分辨率的屏幕上都可以正常显示。/** * 根据手机的分辨率从 px(像素) 的单位 转成为 dp */  
public static int px2dip(Context context, float pxValue) {  final float scale = context.getResources().getDisplayMetrics().density;  return (int) (pxValue / scale + 0.5f);  
}  
/** 
* 根据手机的分辨率从 dip 的单位 转成为 px(像素) 
*/  
public static int dip2px(Context context, float dpValue) {  final float scale = context.getResources().getDisplayMetrics().density;  return (int) (dpValue * scale + 0.5f);  
}  

设置APN

ContentValues values = new ContentValues();
values.put(NAME, "CMCC cmwap");
values.put(APN, "cmwap");
values.put(PROXY, "10.0.0.172");values.put(PORT, "80");
values.put(MMSPROXY, "");
values.put(MMSPORT, "");
values.put(USER, "");
values.put(SERVER, "");
values.put(PASSWORD, "");
values.put(MMSC, "");         
values.put(TYPE, "");
values.put(MCC, "460");
values.put(MNC, "00");
values.put(NUMERIC, "46000");
reURI = getContentResolver().insert(Uri.parse("content://telephony/carriers"), values);
//首选接入点"content://telephony/carriers/preferapn"

调节屏幕亮度

public void setBrightness(int level) { ContentResolver cr = getContentResolver(); Settings.System.putInt(cr, "screen_brightness", level); Window window = getWindow(); LayoutParams attributes = window.getAttributes(); float flevel = level; attributes.screenBrightness = flevel / 255; getWindow().setAttributes(attributes); 
} 

重启

第一,root权限,这是必须的 
第二,Runtime.getRuntime().exec("su -c reboot"); 
第三,模拟器上运行不出来,必须真机 
第四,运行时会提示你是否加入列表 , 同意就好

拍照、录音、录像

package com.cons.dcg.collect;import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;
import android.app.*;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.*;
import android.widget.*;public class RecordActivity extends Activity implements OnClickListener {private static final int RESULT_CAPTURE_IMAGE = 1;// 照相的requestCodeprivate static final int REQUEST_CODE_TAKE_VIDEO = 2;// 摄像的照相的requestCodeprivate static final int RESULT_CAPTURE_RECORDER_SOUND = 3;// 录音的requestCodeprivate String strImgPath = "";// 照片文件绝对路径private String strVideoPath = "";// 视频文件的绝对路径private String strRecorderPath = "";// 录音文件的绝对路径@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);this.setContentView(R.layout.problem_report);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);switch (requestCode) {case RESULT_CAPTURE_IMAGE://拍照if (resultCode == RESULT_OK) {Toast.makeText(this, strImgPath, Toast.LENGTH_SHORT).show();}break;case REQUEST_CODE_TAKE_VIDEO://拍摄视频if (resultCode == RESULT_OK) {Uri uriVideo = data.getData();Cursor cursor=this.getContentResolver().query(uriVideo, null, null, null, null);if (cursor.moveToNext()) {/** _data:文件的绝对路径 ,_display_name:文件名 */strVideoPath = cursor.getString(cursor.getColumnIndex("_data"));Toast.makeText(this, strVideoPath, Toast.LENGTH_SHORT).show();}}break;case RESULT_CAPTURE_RECORDER_SOUND://录音if (resultCode == RESULT_OK) {Uri uriRecorder = data.getData();Cursor cursor=this.getContentResolver().query(uriRecorder, null, null, null, null);if (cursor.moveToNext()) {/** _data:文件的绝对路径 ,_display_name:文件名 */strRecorderPath = cursor.getString(cursor.getColumnIndex("_data"));Toast.makeText(this, strRecorderPath, Toast.LENGTH_SHORT).show();}} break;}}/*** 照相功能*/private void cameraMethod() {Intent imageCaptureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);strImgPath = Environment.getExternalStorageDirectory().toString() + "/CONSDCGMPIC/";//存放照片的文件夹String fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".jpg";//照片命名File out = new File(strImgPath);if (!out.exists()) {out.mkdirs();}out = new File(strImgPath, fileName);strImgPath = strImgPath + fileName;//该照片的绝对路径Uri uri = Uri.fromFile(out);imageCaptureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);imageCaptureIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);startActivityForResult(imageCaptureIntent, RESULT_CAPTURE_IMAGE);}/*** 拍摄视频*/private void videoMethod() {Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0);startActivityForResult(intent, REQUEST_CODE_TAKE_VIDEO);}/*** 录音功能*/private void soundRecorderMethod() {Intent intent = new Intent(Intent.ACTION_GET_CONTENT);intent.setType("audio/amr");startActivityForResult(intent, RESULT_CAPTURE_RECORDER_SOUND);}/*** 提示信息* @param text* @param duration*/private void showToast(String text, int duration) {Toast.makeText(ProblemReport.this, text, duration).show();}
}

隐藏软键盘

getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE |  WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);

隐藏以及显示软键盘以及不自动弹出键盘的方法

1、//隐藏软键盘   ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(WidgetSearchActivity.this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);   2、//显示软键盘,控件ID可以是EditText,TextView   ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE)).showSoftInput(控件ID, 0); 

BitMap、Drawable、inputStream及byte[] 互转

1) BitMap  to   inputStream:ByteArrayOutputStream baos = new ByteArrayOutputStream();bm.compress(Bitmap.CompressFormat.PNG, 100, baos);InputStream isBm = new ByteArrayInputStream(baos .toByteArray());2)BitMap  to   byte[]:Bitmap defaultIcon = BitmapFactory.decodeStream(in);ByteArrayOutputStream stream = new ByteArrayOutputStream();defaultIcon.compress(Bitmap.CompressFormat.JPEG, 100, stream);byte[] bitmapdata = stream.toByteArray();3)Drawable  to   byte[]:Drawable d; // the drawable (Captain Obvious, to the rescue!!!)Bitmap bitmap = ((BitmapDrawable)d).getBitmap();ByteArrayOutputStream stream = new ByteArrayOutputStream();defaultIcon.compress(Bitmap.CompressFormat.JPEG, 100, bitmap);byte[] bitmapdata = stream.toByteArray();4)byte[]  to  Bitmap :Bitmap bitmap =BitmapFactory.decodeByteArray(byte[], 0,byte[].length);

drawable转bitmap

/*** drawableתbitmap* * @param drawable* @return*/private Bitmap drawableToBitamp(Drawable drawable){if (drawable instanceof BitmapDrawable){BitmapDrawable bd = (BitmapDrawable) drawable;return bd.getBitmap();}int w = drawable.getIntrinsicWidth();int h = drawable.getIntrinsicHeight();Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);drawable.setBounds(0, 0, w, h);drawable.draw(canvas);return bitmap;}

Android目录结构

  • data

    • app:用户安装的应用
    • data:应用的专属文件夹
    • system:系统的配置信息,注册表文件
    • anr:anr异常的记录信息
  • dev:devices的缩写

    • 存放设备所对应的文件
  • mnt:mount的缩写

    • 挂载在系统上的设备:sdcard,u盘
  • proc:硬件配置,状态信息

    • cpuinfo、meminfo
  • sbin:system bin

    • 系统重要的二进制执行文件
    • adbd:服务器的adb进程
  • system:

    • app:存放系统应用,默认不能删除
    • bin:Android中可执行的linux指令文件
    • etc:host:主机名和ip地址的映射
    • fonts:Android中自带的字体
    • framework:存放谷歌提供的java api
    • lib:核心功能的类库,C/C++文件
    • media/audio:存放Android的音效文件
    • tts:语音发声引擎,默认不支持中文
    • usr:用户设备的配置信息,键盘编码和按键编码的映射
    • xbin:是专为开发人员准备的二进制指令

Android下的Linux指令

  • su:superuser
    • 切换到超级用户
  • rm:remove,删除文件
    • rm 文件名
  • ls:列出目录下的所有文件和文件夹
    • ls -l:查看文件的详细信息
    • ls -a:查看隐藏文件
  • cd:切换到某个目录
  • cat:查看文件内容
    • cat 文件名
    • 不要cat二进制可执行文件
  • mv:move 修改文件名
    • mv 原文件名 新文件名
  • mkdir:创建文件夹
    • mkdir 文件夹名字
  • rmdir:删除文件夹
    • rmdir 文件夹名字
  • touch:创建新文件
    • touch 文件名
  • chmod:change mode,切换文件访问权限
    • chmod 777 文件名
  • echo:回显数据;重定向数据
    • echo 数据 > 文件名
  • sleep:睡眠几秒
  • df:显示指定目录的容量
  • id:打印当前用户的id
    • uid=0:root
    • uid=1000:system
    • uid=2000:shell
    • uid=10000+:一般应用程序的id
  • ps:列出系统中运行的所有进程
  • kill:杀死指定pid的进程
    • kill pid
  • chown:change owner,修改拥有者
    • chown 0.0 文件名
  • mount:挂载文件系统
    • mount -o remount rw /:挂载当前目录为可读可写权限
    • mount -o remount rw /system:重新挂载指定目录

Android中特有的指令

  • am:ActivityManager,可以进行跟activity相关的操作

    • am start -n com.test.createfile/com.test.createfile.MainActivity:开启指定Activity
    • am kill com.test.createfile:结束非前台进程
    • am force-stop com.test.createfile:结束进程
  • pm:PackageManager

    • pm disable 包名:冻结指定应用
    • pm enable 包名:解冻指定应用
  • monkey -p com.test.createfile 1000:自动点击指定应用1000次

刷模拟器,rom写文件(su)

  • 如果想让真实手机运行这些指令,手机必须要有root权限
  • 刷root原理:把su二进制文件拷贝到/system/bin或者/system/xbin
  • Android刷root软件,工作的原理全部都是利用系统的漏洞实现
  • rom:可以理解为android系统的安装文件
  • 把su文件和superuser.apk写入img文件
  • 执行su指令
    Runtime.getRuntime().exec(“su”);

修改字体

  • 把ttf文件刷进img中
  • Android系统默认的中文字体为DroidSansFallBack.ttf
  • 用你想使用的字体ttf文件替换掉这个文件即可

修改开机动画

  • 从真机中得到bootanimation.zip
  • 把bootanimation.zip放入system/media目录下

删除锁屏密码

  • 删除data/system下的key文件
    • 文本密码为password.key
    • 手势密码为gesture.key

关于9path

上传代码到github

1、github创建库
2、进入创建好的Android项目目录
3、配置邮箱和用户名,这样就可以表示是谁提交的了
git config --global user.name "Lemoner"
git config --flobal user.email "jiang.xingbing@outlook.com"
4、开始拷贝下来的GitHub仓库地址了,把它拷贝过来
git clone https://github.com/Lemoner/demo.git
5、看到一个跟GitHub仓库同名的目录,把里面的文件都拷贝到上一级目录,GitHub的同名目录就可以删掉了。下面输入命令将文件添加进版本控制:git add .
注意add后面的空格是一定要加的,不然会报错。
添加进来之后,执行提交命令git commit -m "My First Commit"
这样就将修改提交到了本地仓库
接下来将本地仓库内容上传到GitHub上git push origin master
最后一步如果没有登录可能需要你的GitHub密码,直接按照提示输入就好了

本文链接:https://my.lmcjl.com/post/9955.html

展开阅读全文

4 评论

留下您的评论.