CPForAndroid和Android项目模板
MyDroidTemplate Eclipse项目模板和一个用于与CodeProject交互的Droid应用程序
- MyDroidTemplate 模板项目源代码(在 Eclipse 3.4 和 3.6 中测试通过,[清理和刷新项目])- 123.7 KB
- CPForAndroid 项目网站
- CPForAndroid 源代码
MyDroidTemplate |
CPForAndroid
|
- 引言
- 参考文献
引言
本文将探讨我在开发 CPForAndroid 时发现的一些有趣的组件,这些组件对于学习开发 Android 应用程序的人可能很有用。还有一个模板应用程序,其中包含大多数应用程序所需的类,如数据库函数和菜单,这些在 Eclipse 的新建项目向导中找不到。
- android.view.Menu(用于创建选项菜单。)
- android.app.AlertDialog(用于显示对话框视图的有用类。)
- android.app.ProgressDialog(几乎所有应用都需要它们,但需要单独的线程才能正常工作。)
- android.database.sqlite.SQLiteDatabase(提供管理 SQLite 数据库方法的类。)
- android.database.sqlite.SQLiteOpenHelper(用于管理数据库版本、打开、创建和升级的配套类。)
- android.widget.TabHost (用于构建选项卡式视图的类。)
- 如何构建 .apk(Android 应用程序打包为 .apk 格式。)
- 如何将 .apk 添加到 Android Market(让世界了解你的应用。)
我猜想有很多读者熟悉 SQLite。我还没有机会使用轻量级嵌入式 SQL 数据库引擎库,并且很高兴它被用于 Android 开发。我决定制作一个小型的 SQLite 模板,由两个类组成,以便在将来的项目中重用。在尝试这个之后很短的时间内,我决定将我制作的一些内容与 alessandroFranzi 的 Creative Commons 许可的类 SQLiteDatabaseAdapter 合并(这就是我们在这里喜欢做的,对吧?代码重用 :smile:)。SQLite 似乎是帮助记住用户上次阅读的 CPForAndroid RSS 文章的有效解决方案。
Android SDK 和 Eclipse 集成开发环境 (IDE)
我相信 Codeproject 上有更多关于如何设置 Android 开发的深入教程,但这里是我为本文整理的一个快速参考指南
注意 (2014-11-06):以下步骤是在文章首次起草时创建的,请参考 此处 的文档以获取最新说明以及使用 Android Studio 的说明
- 确保你已安装 Eclipse IDE for Java。
- 下载 Android SDK,运行 SDK 设置时可能会遇到错误,或者转到 Window -> Preferences。然后导航到 Install/update - available software sites。然后你可以将 http://dl-ssl.google.com/android/eclipse/site.xml 添加到列表中。现在如果你需要下载 Android 开发工具,请返回 Eclipse 主屏幕并导航到 Help -> Install New Software。在“Work with”字段中粘贴相同的 URL:http://dl-ssl.google.com/android/eclipse/site.xml。然后选择所有可用的开发工具。重启,你现在就可以使用 Android 开发工具了。更多帮助请点击此处。
- 按照 快速入门 设置 Eclipse IDE。
MyDroidTemplate
![]() |
当你使用 New -> Android Project 向导从头开始构建 Android 项目时,它会构建应用程序的基础,但还有一些预期的项目缺失。此模板旨在提供一个可以精简和自定义的模板,而不是四处查找代码并添加。要使用此模板,请将 *MyDroidTemplate.zip* 解压到新位置(例如,在你的 Eclipse 'workspace' 文件夹中),然后将根文件夹重命名为你的新项目名称。接下来,选择 File -> Import -> Existing Projects into Workspace。然后你需要更新项目类名和命名空间到你的新名称。 |
以下是我添加到 Eclipse 生成的 *MyDroidTemplate.java* 文件中的一些内容
import android.util.Log; //Used for debug and error logging [Log.e(TAG, "e.getMessage()");]
public final String TAG = "MyDroidTemplate"; //Used in logging etc.
Menu
我曾在某处读到,大多数 Android 用户都期望应用程序中存在菜单,所以让我们在项目模板中添加一个。我在 '*.\MyDroidTemplate\res'* 下创建了一个名为 'menu' 的子文件夹(如果你不熟悉 Eclipse,请记住,当你添加 Eclipse IDE 之外的文件夹或文件时,需要按 F5 刷新你的项目)。这将包含有关如何绘制菜单按钮的详细信息。对于模板,我们只需要三个按钮:“Options”(选项)、“Quit”(退出)和“About”(关于)。
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/options"
android:title="Options"
android:icon="@android:drawable/ic_menu_preferences">
</item>
<item android:id="@+id/quit"
android:title="Quit"
android:icon="@android:drawable/ic_menu_close_clear_cancel">
</item>
<item android:id="@+id/about"
android:title="About"
android:icon="@android:drawable/ic_menu_info_details">
</item>
</menu>
接下来,我们需要一些方法来触发和绘制菜单。当 Eclipse 检测到需要类库时,它会在自动添加导入行方面做得很好。以下是此 OptionsMenu 所需的类:
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
在 `MyDroidTemplate` 类中,我们有以下方法来实现它(**注意**:我已注释掉我们尚未准备好的行,例如 AboutDialog 等)。
//*** ANDROID.VIEW.MENU START ***//
public boolean onCreateOptionsMenu(Menu menu)
{
// Create the menu from the menu_xml
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.options:
//DO OPTIONS()
return true;
case R.id.quit:
finish();
return true;
case R.id.about:
//new AboutDialog(this).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
//*** ANDROID.VIEW.MENU END ***//
AlertDialog
这是 AboutDialog 在模板中的添加方式。与所有 Android 视图一样,必须有一个相应的布局 XML 文件。我通过选择要添加 XML 的文件夹并选择“New -> Android XML File”,然后确保选中 layout 并将 'about.xml' 写入“File”文本框并点击 Finish 来在 Eclipse 中创建了一个。这是 about.xml,请注意我们主要添加 TextViews,以便以后可以格式化并发送文本(**注意**:我在 *\values\strings.xml* 中添加了一些颜色值)。[**注意**:*PopUpDialog.java* 和 *popup.xml* 已添加到模板中,这使你可以用一行代码创建弹出消息。]
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/options"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/app_name"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/white"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="12dip"
android:layout_marginBottom="4dip" />
<TextView
android:id="@+id/author"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textStyle="bold"
android:textSize="14sp"
android:textColor="@color/white"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="4dip"
android:layout_marginBottom="4dip" />
<TextView
android:id="@+id/graphics_byline"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textStyle="bold"
android:textSize="14sp"
android:textColor="@color/white"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="4dip"
android:layout_marginBottom="4dip" />
<TextView
android:id="@+id/license"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textStyle="bold"
android:textSize="14sp"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="4dip"
android:layout_marginBottom="8dip" />
<TextView
android:id="@+id/what_is_this"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textStyle="bold"
android:textSize="14sp"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="8dip"
android:layout_marginBottom="8dip" />
<TextView
android:id="@+id/website"
android:autoLink="web"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textStyle="bold"
android:textSize="14sp"
android:textColor="@color/white"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="8dip"
android:layout_marginBottom="4dip" />
<TextView
android:id="@+id/bugs"
android:autoLink="web"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textStyle="bold"
android:textSize="14sp"
android:textColor="@color/white"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="4dip"
android:layout_marginBottom="12dip" />
</LinearLayout>
</ScrollView>
现在我们必须有一个 Java 类来处理 AboutDialog 框。我们可以通过右键单击“src”文件夹并选择“New -> class”在 Eclipse 中创建它。对于“Package”,我浏览到 'com.android.MyDroidTemplate',然后在“Name”字段中输入 'AboutDialog' 并点击 Finish 按钮。下面是 *AboutDialog.java* 和 *Utils.java*。我发现 AboutDialog 是一个适合复制以创建新对话框的类。`Utils` 类包含一些可重用代码,用于获取不断变化的应用程序详细信息。(**注意**:再次,我已将内容添加到 *\values\strings.xml* 以存储应用程序的常用文本。)
//AboutDialog.java
package com.android.MyDroidTemplate;
import android.app.AlertDialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
public class AboutDialog {
@SuppressWarnings("unused")
private static final String TAG = "AboutDialog";
private final Context mCtx;
public AboutDialog(Context ctx) {
super();
this.mCtx = ctx;
}
public void show() {
final LayoutInflater factory = LayoutInflater.from(mCtx);
View dialogView = factory.inflate(R.layout.about, null);
innerUpdate(dialogView);
AlertDialog.Builder adBuilder = new AlertDialog.Builder(mCtx).setTitle(
R.string.about).setIcon(android.R.drawable.ic_dialog_info)
.setView(dialogView);
adBuilder.show();
}
private void innerUpdate(View dialogView) {
TextView appName = (TextView) dialogView.findViewById(R.id.app_name);
TextView author = (TextView) dialogView.findViewById(R.id.author);
TextView graphics_byline = (TextView) dialogView.findViewById(R.id.graphics_byline);
TextView license = (TextView) dialogView.findViewById(R.id.license);
TextView whatIsThis = (TextView) dialogView.findViewById(R.id.what_is_this);
TextView website = (TextView) dialogView.findViewById(R.id.website);
TextView bugs = (TextView) dialogView.findViewById(R.id.bugs);
// app name & version
String appText = Utils.getAppName(mCtx, mCtx.getPackageName()) + " v"
+ Utils.getAppVersionName(mCtx, mCtx.getPackageName());
appName.setText(appText);
// author
author.setText(R.string.author);
// license
license.setText(R.string.license);
// text
whatIsThis.setText(R.string.about_text);
// website
website.setText(mCtx.getString(R.string.website) + ":\n\n"
+ mCtx.getString(R.string.website_url));
// email
bugs.setText("Suggestions or Bugs:\n\n"
+ mCtx.getString(R.string.issues));
}
}
以及 *Utils.java*
//Utils.java
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
public class Utils {
public static boolean checkForInstalledApp(Context ctx, String pkgName) {
try {
PackageManager pm = ctx.getPackageManager();
pm.getPackageInfo(pkgName, 0);
// Log.d(TAG, pkgString + " is installed");
return true;
} catch (NameNotFoundException e) {
// Log.d(TAG, pkgString + " is not installed");
}
return false;
}
public static String getAppName(Context ctx, String pkgName) {
try {
PackageManager pm = ctx.getPackageManager();
ApplicationInfo appInfo = pm.getApplicationInfo(pkgName, 0);
String label = pm.getApplicationLabel(appInfo).toString();
return label;
} catch (NameNotFoundException e) {
return "";
}
}
public static String getAppVersionName(Context ctx, String pkgName) {
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pkgInfo = pm.getPackageInfo(pkgName, 0);
String ver = pkgInfo.versionName;
return ver;
} catch (NameNotFoundException e) {
return "0";
}
}
public static int getAppVersionCode(Context ctx, String pkgName) {
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pkgInfo = pm.getPackageInfo(pkgName, 0);
return pkgInfo.versionCode;
} catch (NameNotFoundException e) {
return 0;
}
}
}
SQLite 数据库类
*SQLiteDatabaseAdapter.java*(提供管理 SQLite 数据库方法的类)和 *DbDataLayer.java*(用于管理数据库版本、打开、创建和升级的配套类)已添加以支持 SQLite 数据库。我将不发布整个类,而是解释创建和获取数据库信息的重要方法。大多数情况下,唯一需要自定义的类是 `DbDataLayer`(如果你以后需要执行升级,请修改 SQLiteDatabaseAdapter 中的 `OnUpgrade` 方法)。`DbDataLayer` 需要你的数据库名称和表名。它还需要你的表数据结构,采用标准的 SQL 'create table
' 语句。最后,你需要修改 `AddRecord` 方法,使其能够正确地向表架构添加记录。
//DbDataLayer.java
private static final String DATABASE_NAME = "mydbname.db"; //CUSTOMIZE
private static final String TABLE_NAME = "mytablename";//CUSTOMIZE
此外,你还需要自定义表创建以满足你的需求(见下文)。你会注意到模板默认创建一个名为 'mytablename
' 的表,并在数据库 'mydbname.db
' 中包含 'ID'、'Link'、'Title' 和 'Pubdate' 列。
//DbDataLayer.java
public DbDataLayer(Context c)
{
//CUSTOMIZE FOR YOUR TABLE
String sql = "create table "+ TABLE_NAME + " " +
"("+ BaseColumns._ID + " integer primary key autoincrement, " +
"Link text not null, " +
"Title text not null, " +
"Pubdate text not null); ";
_dbHelper = new SQLiteDatabaseAdapter(c, DATABASE_NAME, null , 1, sql);
}
现在,在执行任何读写操作之前,可以按以下方式初始化数据库
//MyDroidTemplate.java
public DbDataLayer d ;
public class MyDroidTemplate extends Activity {
public DbDataLayer db ;
...
...
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
//DO SOMETHING
db = new DbDataLayer(getBaseContext());//Initialize the database
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
调用以下方法向数据库写入数据
//DbDataLayer.java
//CUSTOMIZE FOR YOUR DATABASE ENTRIES
public void AddRecord(String title, String link, String pubdate) {
SQLiteDatabase db = _dbHelper.getWritableDatabase();
try {
ContentValues values = new ContentValues();
values.put("Link", link);
values.put("Title", title);
values.put("Pubdate", pubdate);
db.insert(TABLE_NAME, "", values);
}catch (Exception e)
{
Log.e(tag,"AddRecord Exception [" + e.getMessage() + "]");
} finally {
if (db != null)
db.close();
}
}
ProgressDialog 类
这是到目前为止最难实现的功能之一,而且我仍然不满意。因此,任何建议和反馈都将非常有益。但是,我在模板中需要一个 `Progressbar` 功能,所以这是我为第 1 版准备的内容。调用 `showDialog` 会触发 `onCreateDialog`,后者会显示请求的 `ProgressDialog`。
//MyDroidTemplate
import android.app.ProgressDialog;
public class MyDroidTemplate extends Activity {
...
static final int PROGRESS_DIALOG = 0; //Used for DownloadedThread PRogressBar handling
DownloaderThread progressThread; //Used for DownloadedThread PRogressBar handling
ProgressDialog progressDialog; //Used for DownloadedThread PRogressBar handling
//*** PROGRESSBAR THREAD START ***//
// Define the Handler that receives messages from the thread and update the progress
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dismissDialog(PROGRESS_DIALOG);
progressThread.setState(DownloaderThread.STATE_DONE);
}
};
protected Dialog onCreateDialog(int id) {
switch(id) {
case PROGRESS_DIALOG:
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Loading...");
progressThread = new DownloaderThread(handler);
progressThread.start();
return progressDialog;
default:
return null;
}
}
/** Nested class that performs progress */
private class DownloaderThread extends Thread {
Handler mHandler;
final static int STATE_DONE = 0;
final static int STATE_RUNNING = 1;
int mState;
int total;
DownloaderThread(Handler h) {
mHandler = h;
}
public void run() {
mState = STATE_RUNNING;
while (mState == STATE_RUNNING)
{
Message msg = mHandler.obtainMessage();
try {
//Do The Work
Thread.sleep(10000);
} catch (Exception e) {
Log.e("ERROR", "Thread Interrupted Exception [" + e.getMessage() + "]");
}
mHandler.sendMessage(msg);
}}
/* sets the current state for the thread,
* used to stop the thread */
public void setState(int state) {
mState = state;
}
}
TabView 模板 (android.widget.TabHost)
模板中包含一组类,以防你需要选项卡式视图支持。*MyTabView.java* 和 *mytabview.xml* 处理 2 个选项卡(你可以添加更多)的主显示,这些选项卡是通过 *MyTabActivity.java* 和 *MyTabActivity2.java* 创建的。*MyTabActivity.java* 使用简单的 `String` 数组填充 `ListView`,*MyTabActivity2.java* 则使用自定义适配器(*MyLVAdapter.java* [My List View Adapter])进行填充。
Android 调试桥 (adb.exe)
Android Debug Bridge (adb.exe) 允许你直接访问模拟器实例或 Android 设备进行调试。例如,对于此模板应用,我可以使用它在进行一些条目后查看数据库(**注意**:*adb.exe* 位于 'android-sdk-windows\tools' 文件夹中)。启动模拟器,然后启动 Android 应用程序。下面是我放在文本文件中的命令,以便我方便地复制和粘贴(**注意**:有些命令需要修改才能访问正确的数据库和表名)。
C:\android-sdk-windows\tools>adb shell
cd data
cd data
cd com.android.MyDroidTemplate
cd databases
sqlite3 mydbname.db
cd data
cd data
cd com.android.MyDroidTemplate
cd databases
#ls
ls
mydbname.db
# sqlite3 mydbname.db
sqlite3 mydbname.db
SQLite version 3.5.9
Enter ".help" for instructions
sqlite> select * from mytablename;
select * from mytablename;
1|http://msn.com|MSN|Mon Aug 30 08:00
2|http://codeproject.com|Codeproject|Mon Aug 30 09:00
3|http://cpforandroid.googlecode.com|CPForAndroid|Mon Aug 30 10:00
sqlite>
CPForAndroid:一个与 CodeProject.com 交互的 Droid 应用
立即在你的 Android 手机上的 Market 上获取 `CPForAndroid`。尝试后请评分!! |
CPForAndroid 一个用于与 CodeProject.com 交互的应用!关注你喜欢的编程社区的最新动态。对眼睛友好且有趣。
|
https://market.android.com/details?id=org.android.CPForAndroidPlusPlus
如果你有兴趣帮助开发或提供反馈,请访问 开发和支持网站。
发布你的应用到 Market
- 请确保你在清单文件中声明了 '
android:minSdkVersion
' 属性(https://developer.android.com.cn/guide/appendix/api-levels.html),然后将你的应用导出为 .apk 文件 [File -> Export]。这将生成 .apk 所需的证书。(尽快备份你的 KEYSTORE!!!以后你会感谢我的。) - 发布你的应用程序到 Android Market 需要 $25.00。http://market.android.com/publish
- 完成注册过程。
- 根据发布说明上传你的文件。
技巧
这些只是我在过程中需要查找的一些项目。你可能会发现它们在编写代码时很有用。
- Android 内置可绘制对象列表
- 你可能对应用程序的布局有一些想法,并想草绘出来。请 使用这个有用的模板 来绘制不同的 droid 布局。
- 在线和可下载的应用程序,可帮助生成布局 xml。
- 在线 QR Code 生成器。一旦你的应用程序上线,你就会想把它放在你的网站上,这样用户就可以轻松下载了。
结论
在我的移动设备上浏览 Codeproject.com 就足以激励我学习使用 Android SDK 及其模拟器进行开发。将所有内容记录在这里,将在 6 到 12 个月后,当我有了另一个 Android 应用的想法时,对我有所帮助。希望其他人会发现本文很有帮助,并且 `MyDroidTemplate` 是一个有用的 Android 项目骨架起点。除了模板,我还提供了一些有用的链接来帮助你开发应用程序,以及一个关于如何将你的应用程序上传到 Android Market 的快速参考。我计划很快发布一个视频,供那些没有 Android 手机也没有 Eclipse IDE 的读者观看,以了解本文的内容。
此模板是 CPForAndroid 的副产品。`CPForAndroid` 是一个用于跟踪 Codeproject.com 的 Android 应用程序。它是一个开源项目,对所有人开放。只需访问开发和支持网站了解更多信息。快来帮忙吧;人越多越热闹!
参考文献
更新
- 8/30/2010
- 已上传 `MyDroidTemplate` v1.0.0.0(在 Eclipse 3.4 中测试)
- 9/1/2010
- 在 Eclipse 3.6 中测试 `MyDroidTemplate` v1.0.0.0(因此在 3.4 和 3.6 中均已验证)
- 9/5/2010
- 向 `MyDroidTemplate` 添加了 *PopUpDialog.java* 和 *popup.xml*
- 已上传 `MyDroidTemplate.zip` 版本 1.1
- 已更新 *template_files208x421.png*
- 已更新 *cpforandroid_main.png*
- 已更新 *MyDroidTemplateIDE478x260.png*
- `CPForAndroid` 现在版本为 1.17,可在 Android Market 上获取
- 9/8/2010
- 在类 `DbDataLayer` 方法 `DoesExist()` 中添加了 cur.deactivate() 以避免任何错误
- 添加了示例 Toast 行
- 已上传 `MyDroidTemplate` versionName="1.2" versionCode="3"
- 9/13/2010
- 已上传 `MyDroidTemplate.zip` 版本 1.3
- 向 `Utils` 类添加了 `ToastMsg`
- 添加了 *MyTabView.java* 和 *mytabview.xml*
- 添加了 *MyTabActivity.java* 和 *mytabact.xml*
- 添加了 *MyTabActivity2.java*(使用 `MyLVAdapter`)
- 在 *main.xml* 布局中添加了“Show TabView”按钮
- 为 *MyLVView.java* 添加了 *listview_row.xml*
- 添加了 *MyLVView.java*
- 添加了 *MyLVAdapter.java*
- 在异常 `catch` 语句中添加了 `e.printStackTrace();` 以获得更好的调试效果
- 2/11/2011
- `CPForAndroid` 现在是 CPForAndroid++
- 更新了 qcode 和 Market Publishing 部分
- 11/06/2014
- `MyDroidTemplate.java` 在 Android Studio (beta) 0.8.14 和 Android 4.4.2 中成功测试(已转换项目)
- CPForAndroid++ 由于一些 string.xml 错误无法编译,我还没有时间去调查
- 更新了“Android SDK 和 Eclipse 集成开发环境 (IDE)”部分