android 开发


多语言

内部类导致内存泄漏

ImageSwitcher内存泄漏(BitmapDrawable内存泄漏)

Bitmap导致OOM问题

增大应用的heapsize

在<application>添加 android:largeHeap="true"

有些公司的设备adb devices找不到

参考: http://blog.csdn.net/liuqz2009/article/details/7942569

有些公司的设备adb需要root权限

Android shell没有cp命令

使用dd代替 dd if=source_file of=dest_file

使用库项目

webview跳转链接时仍使用自己打开

private class MyWebViewClient extends WebViewClient {
      public boolean shouldOverrideUrlLoading(WebView view, String url) {
          // 使用当前的WebView加载页面
          view.loadUrl(url);
          return true;
      }
  }
this.setWebViewClient(new MyWebViewClient());

webview播放flash视频

  1. 安装flash插件: http://helpx.adobe.com/flash-player/kb/archived-flash-player-versions.html
  2. 在AndroidManifest.xml的application标签中添加android:hardwareAccelerated="true"

xml中写入复杂或多行字符串

<string><string-array>中加入formatted="false"属性 可视字符串为原始字符串 不需要特殊处理% 换行也会被忽略(需要换行手动加\n)

距离单位转换

Activity生命周期

Activity栈

<activity>里的android:launchMode与activity的跳转栈相关

intent.setFlags() 也是 activity的跳转栈相关

模拟器

代码混淆

不能混淆的部分:

  1. 会被反射的类
  2. 依赖于系统的接口,比如系统的回调方法
  3. 文件中指定类名的

apk反编译

APK签名

代码

获取相对路径

  private String getRelaPath(File root, File path) {
      return path.getAbsolutePath().substring(root.getAbsolutePath().length() + 1);
  }

service中使用Toast

  final String text = s;
  new Handler(Looper.getMainLooper()).post(new Runnable() {
      public void run() {
          Toast.makeText(getApplicationContext(), text,
                  Toast.LENGTH_SHORT).show();
      }
  });

显示等待框

m_Dialog=ProgressDialog.show(this, "请等待...", "正在拷贝资源文件,请稍后...",true);
new Thread(){
  @Override
  public void run() {
      super.run();
      //do something for long time
      m_Dialog.dismiss();
  }
}.start();

显示其它activity之上的view

WindowManager wm = (WindowManager) getApplicationContext()
		.getSystemService(WINDOW_SERVICE);
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; //overlay显示等级过高
//TYPE_SYSTEM_ALERT需要配合这些flag否则为modal类型
params.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
		| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
params.gravity = gravity;
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = h;
wm.addView(msgView, params);

注: 需要用wm.removeView(msgView);手动释放view

使用Paint计算字符串宽高

VideoView拉伸至指定大小

  private int width;
  private int height;
  @Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 只有直接指定大小才能伸展到设定的大小
setMeasuredDimension(width, height);
	}

通过代码全屏

在setContentView之前

requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

隐藏导航栏(Navigation Bar)

显示提示对话框(MessageBox)

  public static void ShowMessage(Context ctx, String msg) {
      AlertDialog.Builder dialog = new AlertDialog.Builder(ctx);
      dialog.setMessage(msg);
      dialog.show();

从raw文件夹拷贝文件

  public static void copyRaw2Sdcard(Context context, int id, File target, boolean rewrite) {
      File f = target;
      String targetPath = f.getAbsolutePath();
      if (!f.exists() || rewrite) {
          File dir = new File(targetPath.substring(0,
                  targetPath.lastIndexOf(File.separator)));
          if (!dir.exists() && !dir.mkdirs()) {
              Log.e("zz", "can't create directory!");
          }
          InputStream ins = context.getResources().openRawResource(id);
          try {
              byte[] buf = new byte[8 * 1024];
              int size;
              FileOutputStream fos = new FileOutputStream(f);
              while ((size = ins.read(buf)) != -1)
                  fos.write(buf, 0, size);
              ins.close();
              fos.close();
          } catch (FileNotFoundException e) {
              Log.e("zz",
                      "can't create file:" + e.getMessage());
          } catch (IOException e) {
              Log.e("zz",
                      "can't create file:" + e.getMessage());
          }
      }
  }

获取ip地址

  public static String getLocalIpAddress() {
      String ip = "";
      try {
          for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
              NetworkInterface intf = en.nextElement();
              for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                  InetAddress inetAddress = enumIpAddr.nextElement();
                  if (!inetAddress.isLoopbackAddress() && InetAddressUtils.isIPv4Address(inetAddress.getHostAddress()))  //这里做了一步IPv4的判定
                  {
                      ip = inetAddress.getHostAddress().toString();
                      return ip;
                  }
              }
          }
      } catch (SocketException e) {}
      return ip;
  }

安装软件包

	void installApk(Context context, File apkfile) {
		Intent intent = new Intent(Intent.ACTION_VIEW);
		intent.setDataAndType(Uri.fromFile(apkfile),
				"application/vnd.android.package-archive");
		context.startActivity(intent);
	}

用root权限运行shell命令

	public static boolean runAsRoot(String cmd) {
		Process process = null;
		DataOutputStream os = null;
		try {
			process = Runtime.getRuntime().exec("su"); // 切换到root帐号
			os = new DataOutputStream(process.getOutputStream());
			os.writeBytes(cmd + "\n");
			os.writeBytes("exit\n");
			os.flush();
			process.waitFor();
		} catch (Exception e) {
			return false;
		} finally {
			try {
				if (os != null) {
					os.close();
				}
				process.destroy();
			} catch (Exception e) {
			}
		}
		return true;
	}
	
    // 如需挂载/为rw
    mount -o remount,rw rootfs /
    用完后: mount -o remount,ro rootfs /
	
    // 示例:修改系统时间
    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd.HHmmss", Locale.US);
	Calendar cal = Calendar.getInstance();
	cal.set(Calendar.HOUR_OF_DAY, 4);
	String datetime = sdf.format(cal.getTime());
	String command = "date -s \"" + datetime + "\"";
	Log.e("zz", command);
	runAsRoot(command);

运行shell命令

	public static boolean run(String cmd) {
		Process process = null;
		DataOutputStream os = null;
		try {
			process = Runtime.getRuntime().exec(cmd);
		} catch (Exception e) {
			return false;
		} finally {
			try {
				if (os != null) {
					os.close();
				}
				process.destroy();
			} catch (Exception e) {
			}
		}
		return true;
	}

任何线程都可使用的toast

public class ToastMessageTask extends AsyncTask<String, String, String> {
	Context context;
	String toastMessage;
	int lengthtype;

	ToastMessageTask(Context context, String msg, int lengthtype) {
		this.context = context;
		this.toastMessage = msg;
		this.lengthtype = lengthtype;
	}

	@Override
	protected String doInBackground(String... params) {
		return "";
	}

	// This is executed in the context of the main GUI thread
	protected void onPostExecute(String result) {
		Toast toast = Toast.makeText(context, toastMessage,
				lengthtype);
		toast.show();
	}
}

使用:

new ToastMessageTask(ctx, "this is a toast", Toast.LENGTH_LONG).execute();

NDK

使用预编译的.a或.so

加上这段
include $(CLEAR_VARS)
LOCAL_MODULE := lua
LOCAL_SRC_FILES := liblua.a
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_MODULE是赋予之一个名字 使用时使用那个名字:
LOCAL_STATIC_LIBRARIES := lua
.so使用PREBUILT_STATIC_LIBRARY

sqlite

shell 操作 sqlite

貌似需要解锁的机器
adb shell
cd /data/data/xxx.xxx.xx/databases
sqlite3 databasename
命令需在前面加. 如".quit"
sql语句需加; 如"select * from xx;"

安装sqlite3工具

http://blog.csdn.net/ygc87/article/details/7452422

eclipse

导入工程

新建同名工程 然后`git co .`恢复被修改内容

导入android框架源码

  1. 任选一个eclipse工程 进入其Build path设定
  2. Libraries - Android4.2.2 - android.jar编辑其Source attachment 选择External folder... 选择源码文件夹(内含framworks等文件夹以及Makefile)

代码混淆

  1. 在project.properties文件中混淆配置文件proguard.config=proguard-project.txt
  2. 导出apk(build产生的debug签名的apk不会混淆)

eclipse故障排除

eclipse打开失败

log显示"org.eclipse.swt.SWTException: Failed to execute runnable (java.lang.NullPointerException"

shell操作

模拟按键

input keyevent <event_code> 例 模拟POWER按键: input keyevent 26

0 -->  "KEYCODE_UNKNOWN" 
1 -->  "KEYCODE_MENU" 
2 -->  "KEYCODE_SOFT_RIGHT" 
3 -->  "KEYCODE_HOME" 
4 -->  "KEYCODE_BACK" 
5 -->  "KEYCODE_CALL" 
6 -->  "KEYCODE_ENDCALL" 
7 -->  "KEYCODE_0" 
8 -->  "KEYCODE_1" 
9 -->  "KEYCODE_2" 
10 -->  "KEYCODE_3" 
11 -->  "KEYCODE_4" 
12 -->  "KEYCODE_5" 
13 -->  "KEYCODE_6" 
14 -->  "KEYCODE_7" 
15 -->  "KEYCODE_8" 
16 -->  "KEYCODE_9" 
17 -->  "KEYCODE_STAR" 
18 -->  "KEYCODE_POUND" 
19 -->  "KEYCODE_DPAD_UP" 
20 -->  "KEYCODE_DPAD_DOWN" 
21 -->  "KEYCODE_DPAD_LEFT" 
22 -->  "KEYCODE_DPAD_RIGHT" 
23 -->  "KEYCODE_DPAD_CENTER" 
24 -->  "KEYCODE_VOLUME_UP" 
25 -->  "KEYCODE_VOLUME_DOWN" 
26 -->  "KEYCODE_POWER" 
27 -->  "KEYCODE_CAMERA" 
28 -->  "KEYCODE_CLEAR" 
29 -->  "KEYCODE_A" 
30 -->  "KEYCODE_B" 
31 -->  "KEYCODE_C" 
32 -->  "KEYCODE_D" 
33 -->  "KEYCODE_E" 
34 -->  "KEYCODE_F" 
35 -->  "KEYCODE_G" 
36 -->  "KEYCODE_H" 
37 -->  "KEYCODE_I" 
38 -->  "KEYCODE_J" 
39 -->  "KEYCODE_K" 
40 -->  "KEYCODE_L" 
41 -->  "KEYCODE_M" 
42 -->  "KEYCODE_N" 
43 -->  "KEYCODE_O" 
44 -->  "KEYCODE_P" 
45 -->  "KEYCODE_Q" 
46 -->  "KEYCODE_R" 
47 -->  "KEYCODE_S" 
48 -->  "KEYCODE_T" 
49 -->  "KEYCODE_U" 
50 -->  "KEYCODE_V" 
51 -->  "KEYCODE_W" 
52 -->  "KEYCODE_X" 
53 -->  "KEYCODE_Y" 
54 -->  "KEYCODE_Z" 
55 -->  "KEYCODE_COMMA" 
56 -->  "KEYCODE_PERIOD" 
57 -->  "KEYCODE_ALT_LEFT" 
58 -->  "KEYCODE_ALT_RIGHT" 
59 -->  "KEYCODE_SHIFT_LEFT" 
60 -->  "KEYCODE_SHIFT_RIGHT" 
61 -->  "KEYCODE_TAB" 
62 -->  "KEYCODE_SPACE" 
63 -->  "KEYCODE_SYM" 
64 -->  "KEYCODE_EXPLORER" 
65 -->  "KEYCODE_ENVELOPE" 
66 -->  "KEYCODE_ENTER" 
67 -->  "KEYCODE_DEL" 
68 -->  "KEYCODE_GRAVE" 
69 -->  "KEYCODE_MINUS" 
70 -->  "KEYCODE_EQUALS" 
71 -->  "KEYCODE_LEFT_BRACKET" 
72 -->  "KEYCODE_RIGHT_BRACKET" 
73 -->  "KEYCODE_BACKSLASH" 
74 -->  "KEYCODE_SEMICOLON" 
75 -->  "KEYCODE_APOSTROPHE" 
76 -->  "KEYCODE_SLASH" 
77 -->  "KEYCODE_AT" 
78 -->  "KEYCODE_NUM" 
79 -->  "KEYCODE_HEADSETHOOK" 
80 -->  "KEYCODE_FOCUS" 
81 -->  "KEYCODE_PLUS" 
82 -->  "KEYCODE_MENU" 
83 -->  "KEYCODE_NOTIFICATION" 
84 -->  "KEYCODE_SEARCH" 
85 -->  "TAG_LAST_KEYCODE"

am命令

启动Activity
强制停止程序

截屏

screencap -p /sdcard/screen.png