Android入门总结

      最近在做一些Android的程序,开发一个我们一个系统的手持端。虽说在2007年Android平台刚刚推出的时候我就做过一些上面的开发,但是现在已经是2.3最新版本了,Android还是有大量的变化的,因此跟从头学起的差别不是很大。我并不想在这里教会别人怎么去开发,教程网上太多了,只是对于我用到的东西做一点总结,概略而不缺失难点的细节。

  1. 基本开发方法
    Android开发一般使用的环境是Eclipse,安装Android的SDK和ADT插件,值得注意的是我在安装的过程中出想过只安装了2.2版本的SDK,于是开发只能使用这一版本的问题,希望朋友注意,最好能够安装一个比较全的版本。
    新建项目之后,会有项目的目录结构,AndroidManifest.xml文件是整个软件的配置文件,在这其中,一般需要配置的是程序需要的权限,语法格式如下:
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.RESTART_PACKAGES"/>
    你生成的apk文件在安装时会给用户提示是否授予这些权限,如果不在这个文件里说明,使用到诸如网络通讯、访问通讯录等功能时就会报错。
    activity也配置在这其中,比如:
      <activity android:name=".MainActivity"
             android:label="@string/main_title">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    可是设置Activity的标题,对应的类名等属性,新添加一个Activity就需要这里加入这个Activity的说明。
    然后,我们可以在res文件夹下的values文件夹下的strings.xml文件中定义我们自己想要的常量,在layout文件夹下定义界面的布局,就可以进行具体代码的开发工作了。
  2. Android上的数据存储
    Android上有多种数据存储方式,包括:
    a) 使用SharedPreferences。这种方式以NVP(键值对)的形式存储,而最终会存储到你定义的一个XML文件中,具体的方法可以搜索下相关资料,非常简单
    b) 文件存储数据。Android的文件存储跟普通JAVA的文件存储一样,使用流的形式。
    c) SQLite数据库存储数据,类似于数据库表形式的存储方法,非常方便,因为精简,所以比普通的SQL还要舒服些。主要通过继承自SQLiteOpenHelper的一个类来实现创建删除数据库的操作,对应的增删改查在SQLiteDatabase中都有对应的接口,通过SQLiteOpenHelper子类的getReadable/WritableDatabase()方法获取。有趣的是除非空间已满和指定只读外,这两个方法获取的操作对象是一样的,而且我感觉这个方法获取的是缓冲池形式的操作对象,比如:
      SQLiteDatabase a = getReadableDatabase();
      SQLiteDatabase b = getReadableDatabase();
      b.close();
      a.query(...)  //此处操作a可能会报已关闭的错误。
    具体是否是这样的我没有仔细探究,我是在系统中维护另一个单例的SQLiteDatabase对象出现了类似的错误,所以推测内部实现是如此的。
    d) 使用ContentProvider存储数据,一般用于程序之间共享数据。
    e) 网络存储数据。
    此处需要额外说明的是我们在程序中通常会使用配置页面,Android提供了一个非常简单的实现方式,继承自PreferenceActivity的类可以用于设置参数界面,其配置文件为"PreferenceScreen"标签。这部分的参数存储和现实都不需要手动控制,会自动使用SharedPreferences进行存储和修改,界面也不用编写,一个简单的示例如下所示:
    1 <?xml version="1.0" encoding="utf-8"?>
    2 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    3 <PreferenceCategory android:title="自动操作设置">
    4 <CheckBoxPreference
    5 android:key="AutoDelBeforeDownload"
    6 android:title="下载时自动清空原始记录"
    7 android:defaultValue="false"
    8 />
    9 <CheckBoxPreference
    10 android:key="AutoDelAfterUpload"
    11 android:title="上传时自动删除成功记录"
    12 android:defaultValue="false"
    13 />
    14 </PreferenceCategory>
    15 <PreferenceCategory android:title="远程服务地址设置">
    16 <EditTextPreference
    17 android:key="ServerIP"
    18 android:title="设置远程服务IP地址"
    19 android:summary="点击输入"
    20 android:dialogTitle="远程服务IP地址设置"
    21 android:defaultValue="192.168.30.223"
    22 />
    23 <EditTextPreference
    24 android:key="ServerPort"
    25 android:title="设置远程服务端口"
    26 android:summary="点击输入"
    27 android:dialogTitle="远程服务地址设置"
    28 android:defaultValue="8080"
    29 />
    30 </PreferenceCategory>
    31 </PreferenceScreen>

    在界面类中的onCreate()函数中添加如下代码即可:
      addPreferencesFromResource(R.xml.preferences);
    如果需要,可以重载onKeyDown()方法来在界面退出的时候设置系统环境变量,代码示例如下:

    1 @Override
    2 public boolean onKeyDown(int keyCode, KeyEvent event){
    3 if(keyCode == KeyEvent.KEYCODE_BACK){
    4 ConfigProcessor.getContextConfig(this);
    5 return super.onKeyDown(keyCode, event);
    6 }else{
    7 return super.onKeyDown(keyCode, event);
    8 }
    9 }
  3. KSOAP2的使用
    由于我所做的程序是依托现有系统实现了,因此一些数据要从现有的系统中去读取并返回一些数据,经过一些比较,选择了Web Service作为通讯工具。Android上对于Web Service的支持也比较好,KSOAP2是一个常用的包。当然,开发时要将ksoap2-android-assembly-2.4-...这个jar包引入到系统中。在使用的时候比较简单,代码示例如下:
    try {
    SoapObject rpc
    = new SoapObject(MobileConstant.NAMESPACE,
    MobileConstant.LOGIN_METHORT_NAME); //设置namespace和方法名称
    rpc.addProperty(
    "arg0", lName);  //设置参数
    rpc.addProperty(
    "arg1", pass);
    SoapSerializationEnvelope envelope
    = new SoapSerializationEnvelope(
    SoapEnvelope.VER11);
    AndroidHttpTransport ht
    = new AndroidHttpTransport(MobileContext
    .getInstance().getService_URL()); //wsdl的url

    envelope.bodyOut
    = rpc;
    envelope.setOutputSoapObject(rpc);
    ht.call(
    null, envelope);
    SoapObject result
    = (SoapObject) envelope.bodyIn;
    int cnt = result.getPropertyCount();
    if (cnt > 0) { //服务的返回值是一个数组,第一个元素是oid,第二个是用户的显示名
    String userOID
    = result.getProperty(0).toString();
    String userShowName
    = result.getProperty(1).toString();
    // 保存必须的上下文信息。
    MobileContext.getInstance().setLoginName(lName);
    MobileContext.getInstance().setUserOID(userOID);
    MobileContext.getInstance().setUserShowName(userShowName);
    // 保存用户名密码到文件
    SharedPreferences preferences = PreferenceManager
    .getDefaultSharedPreferences(
    this);
    SharedPreferences.Editor editor
    = preferences.edit();
    if (cb_isSave.isChecked()) {
    editor.putString(
    getResources().getString(R.string.saved_name),
    lName);
    editor.putString(
    getResources().getString(R.string.saved_password),
    pass);
    }
    else {
    editor.putString(
    getResources().getString(R.string.saved_name),
    "");
    editor.putString(
    getResources().getString(R.string.saved_password),
    "");
    }
    editor.commit();
    return true;
    }
    else {
    new AlertDialog.Builder(this)
    .setMessage(
    "用户名或密码错误!")
    .setTitle(
    "错误")
    .setNeutralButton(
    "关闭",
    new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dlg,
    int sumthin) {
    }
    }).show();
    return false;
    }
    }
    catch (Exception e) {
    new AlertDialog.Builder(this)
    .setMessage(
    "远程服务请求失败,请检查网络连接或联系系统管理员!")
    .setTitle(
    "错误")
    .setNeutralButton(
    "关闭",
    new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dlg,
    int sumthin) {
    }
    }).show();
    }
    具体的解释就不多做了,包括SharedPreferences的使用都在里面了。
    此处遇到的还未解决的问题包括向服务器提交String[]形式的参数报错的问题,和如果服务不存在超时的问题。前者我不知道是否有办法解决,现在是用一个间隔符划分的字符串代替了数组的传输,后者应该加上一个多线程的进度条来实现比较好。如果有谁解决过这方面的问题,还请指教~
  4. 二维条形码的读取
    在设备上分配了一个唯一的编号,然后生成一个二维条形码,贴在机器上。这样,要求我们的手持程序可以解析二维条形码,读出其中的信息,Android上解读条形码的应用非常的简单,只需要同时安装一个BarcodeScanner.apk软件,在我们的程序里进行调用就可以了,调用代码如下:
    	private void doScanner() {
    		final boolean scanAvailable = MobileTools.isIntentAvailable(this,
    				"com.google.zxing.client.android.SCAN");
    		if (scanAvailable == false) {
    			new AlertDialog.Builder(this)
    					.setMessage("请先安装BarcodeScanner组件!")
    					.setTitle("提示")
    					.setNeutralButton("关闭",
    							new DialogInterface.OnClickListener() {
    								public void onClick(DialogInterface dlg,
    										int sumthin) {
    								}
    							}).show();
    			return;
    		}
    		Intent scannerIntent = new Intent(
    				"com.google.zxing.client.android.SCAN");
    		startActivityForResult(scannerIntent, 100);
    	}
    
    	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    		if (requestCode == 100) {
    			String resultStr = "读取失败";
    			if (resultCode == RESULT_OK) {
    				String contents = intent.getStringExtra("SCAN_RESULT");
    				String format = intent.getStringExtra("SCAN_RESULT_FORMAT");
    				resultStr = contents + "   " + format;
    			} else if (resultCode == RESULT_CANCELED) {
    				resultStr = "读取失败";
    			}
    			new AlertDialog.Builder(this)
    					.setMessage(resultStr)
    					.setTitle("条形码读取结果")
    					.setNeutralButton("关闭",
    							new DialogInterface.OnClickListener() {
    								public void onClick(DialogInterface dlg,
    										int sumthin) {
    								}
    							}).show();
    		}
    	}
    

    其中isIntentAvailable()函数用于验证某个需求的组件是否已经存在,其实现代码如下:
    	/**
    	 * Indicates whether the specified action can be used as an intent. This
    	 * method queries the package manager for installed packages that can
    	 * respond to an intent with the specified action. If no suitable package is
    	 * found, this method returns false.
    	 *
    	 * @param context The application's environment.
    	 * @param action The Intent action to check for availability.
    	 *
    	 * @return True if an Intent with the specified action can be sent and
    	 *         responded to, false otherwise.
    	 */
    	public static boolean isIntentAvailable(Context context, String action) {
    		final PackageManager packageManager = context.getPackageManager();
    		final Intent intent = new Intent(action);
    		List<ResolveInfo> list = packageManager.queryIntentActivities(intent,
    				PackageManager.MATCH_DEFAULT_ONLY);
    		return list.size() > 0;
    	}
    
原文地址:https://www.cnblogs.com/funnydavid/p/1918851.html