(二十五)Android 中的AIDL!!!

最后更新于:2022-04-01 19:46:32

大家好,好久不见,今天要给大家分享的是android aidl的使用。在Android中, 每个应用程序都可以有自己的进程. 在写UI应用的时候, 经常要用到Service. 在不同的进程中, 怎样传递对象呢? 显然, Java中不允许跨进程内存共享. 因此传递对象, 只能把对象拆分成操作系统能理解的简单形式, 以达到跨界对象访问的目的. 在J2EE中,采用RMI的方式, 可以通过序列化传递对象. 在Android中, 则采用AIDL的方式. 理论上AIDL可以传递Bundle,实际上做起来却比较麻烦.  AIDL(AndRoid接口描述语言)是一种借口描述语言; 编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部通信进程的目的. 如果需要在一个Activity中, 访问另一个Service中的某个对象, 需要先将对象转化成AIDL可识别的参数(可能是多个参数), 然后使用AIDL来传递这些参数, 在消息的接收端, 使用这些参数组装成自己需要的对象.  AIDL的IPC的机制和COM或CORBA类似, 是基于接口的,但它是轻量级的。它使用代理类在客户端和实现层间传递值. 如果要使用AIDL, 需要完成2件事情: 1. 引入AIDL的相关类.; 2. 调用aidl产生的class.    今天的两个实例用到两个Android工程,一个是AIDL的服务端另一个是客户端。   **服务端的实现步骤:** 首先看一下服务端,工程目录如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0ecedc1e.gif) 首先创建IaidlServerService.aidl文件,代码如下(一个简单方法,另一个返回对象方法),当我们点击保存时会在gen目录下生成对应的java文件,如上图红色部分:   package com.chapter8.aidl;import com.chapter8.aidl.Book;interface IAIDLServerService { String sayHello(); Book getBook();}  第二步:因为这个接口里有传递对象,所以对象要特殊处理一下,这里继承了Parcelable,Book.java代码如下: 如果大家不明的地方,请参见,下面连接的文章: [Android高手进阶教程(十七)之---Android中Intent传递对象的两种方法(Serializable,Parcelable)!](http://blog.csdn.net/Android_Tutor/archive/2010/07/16/5740845.aspx) ~~~ package com.chapter8.aidl;import android.os.Parcel;import android.os.Parcelable;public class Book implements Parcelable { private String bookName; private int bookPrice; public Book(){ } public Book(Parcel parcel){ bookName = parcel.readString(); bookPrice = parcel.readInt(); } public String getBookName() { return bookName; } public void setBookName(String bookName) { this.bookName = bookName; } public int getBookPrice() { return bookPrice; } public void setBookPrice(int bookPrice) { this.bookPrice = bookPrice; } public int describeContents() { return 0; } public void writeToParcel(Parcel parcel, int flags) { parcel.writeString(bookName); parcel.writeInt(bookPrice); } public static final Parcelable.Creator CREATOR = new Creator() { public Book createFromParcel(Parcel source) { return new Book(source); } public Book[] newArray(int size) { return new Book[size]; } };}  ~~~ 第三步:写一个与Book类对应的aidl,命名为Book.aidl,代码非常简单,代码如下: parcelable Book;  第四步:新建一个名为AidlServerService的Service.代码如下: ~~~ package com.chapter8.aidl;import com.chapter8.aidl.IAIDLServerService.Stub;import com.chapter8.aidl.IAIDLServerService;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;public class AidlServerService extends Service { @Override public IBinder onBind(Intent intent) { return mBinder; } /** * 在AIDL文件中定义的接口实现。 */ private IAIDLServerService.Stub mBinder = new Stub() { public String sayHello() throws RemoteException { return "Hello"; } public Book getBook() throws RemoteException { Book mBook = new Book(); mBook.setBookName("Android应用开发"); mBook.setBookPrice(50); return mBook; } };}  ~~~ 第五步:在AndroidManifest.xml注册Service,代码如下: ~~~   ~~~ 第六步:运行服务端工程,到设备上,好让客户端调用,服务端的Activity什么都没做.效果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0ed18ff4.gif) **客户端的具体实现步骤:** 第一步:新建客户端工程,目录结构如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0ed2d666.gif) 第二步:引入Aidl文件以及用到的类,如上面的com.chapter8.aidl包。直接从服务端里代码copy过来就OK. 第三步:修改main.xml布局文件,增加一个按钮,代码如下: ~~~
';

(二十四)Android WebView的缓存!!!

最后更新于:2022-04-01 19:46:29

各位读者大家好,最近比较忙好久没有写blog了,今天挤点时间和大家分享一下Android中WebView的缓存。我们在项目中也时常会用到WebView这个控件,当我们加载html时候,会在我们data/应用package下生成database与cache两个文件夹如下图如示:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0ec07bd6.gif) 我们请求的url记录是保存在webviewCache.db里,而url的内容是保存在webviewCache文件夹下. 为了让大家更容易理解,我做一个简单的例子,我定义一个html文件,在里面加载了一个淘宝的衣服图片的url,用WebView加载出来,然后再试着从缓存里把这张图片读取出来。 下面大家可以按照我的步骤一步一步来实践: 第一步:新建一个Android工程命名为WebViewCacheDemo.目录结构如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0ec55fab.gif) 第二步:在assets目录下新建一个html文件,命名为index.html,(这里加载了一个淘宝的图片): http://img04.taobaocdn.com/imgextra/i4/608825099/T2nGXBXXpaXXXXXXXX_!!608825099.jpg_310x310.jpg  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0ec6cd50.gif)   第三步:修改main.xml布局文件一个WebView控件一个Button(点击加载缓存图片用),代码如下: ~~~
';

(二十三)Android中的日历读写操作!!!

最后更新于:2022-04-01 19:46:27

大家好,好久没有更新blog了,今天给大家分享一下Android中一些自带日历的操作方法,这里主要用到了ContentProiver的知识.如果大家不明白ContentProvider建议先查一下资料,知道它是干什么的。这样更容易下面的例子. 好了废话不说,这里提个醒,Android中的日历,**只有真机才有,模拟上是没有的,所以测试环境一定要真机!!** 因为日历是系统自带的,所以我们读写它一定要申请权限,也就是在AndroidManifest.xml加如下两行代码(一个读一个写): ~~~ ~~~ Android中日历用了三个URL,分别是日历用户的URL,事件的URL,事件提醒URL,三个URL在Android2.1之前是如下的样子: ~~~ calanderURL = "content://calendar/calendars";calanderEventURL = "content://calendar/events";calanderRemiderURL= "content://calendar/reminders"; ~~~ 但是在Android2.2版本以后,三个URL有了改变,变成如下的样子: ~~~ calanderURL = "content://com.android.calendar/calendars";calanderEventURL = "content://com.android.calendar/events";calanderRemiderURL = "content://com.android.calendar/reminders";   ~~~ 还是老样子,为了让大家更好的理解,我写了一个简单的Demo,大家按照我的步骤一步一步的来: 第一步:新建一个Android工程命名为CalendarDemo. 第二步:修改main.xml布局文件,增加了三个按钮,代码如下: ~~~
';

(二十二)Android中几种图像特效处理的集锦!!

最后更新于:2022-04-01 19:46:25

大家好,这一节给大家分享的是Android中几种图像特效处理的小技巧,比如圆角,倒影,还有就是图片缩放,Drawable转化为Bitmap,Bitmap转化为Drawable等等. 废话少说了,直接讲解今天的实例,本例主要是先获取壁纸(getWallpaper()),然后对当前壁纸的一些特效处理.大家按步骤一步一步来: 第一步:新建一个Android工程命名为ImageDemo,工程结构如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0eb10591.gif) 第二步:新建一个.java文件,命名为ImageUtil.java,在里面定义一些图片处理方法,代码如下: ~~~ package com.android.tutor;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.LinearGradient;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PixelFormat;import android.graphics.PorterDuffXfermode;import android.graphics.Rect;import android.graphics.RectF;import android.graphics.Bitmap.Config;import android.graphics.PorterDuff.Mode;import android.graphics.Shader.TileMode;import android.graphics.drawable.Drawable;public class ImageUtil { //放大缩小图片 public static Bitmap zoomBitmap(Bitmap bitmap,int w,int h){ int width = bitmap.getWidth(); int height = bitmap.getHeight(); Matrix matrix = new Matrix(); float scaleWidht = ((float)w / width); float scaleHeight = ((float)h / height); matrix.postScale(scaleWidht, scaleHeight); Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); return newbmp; } //将Drawable转化为Bitmap public static Bitmap drawableToBitmap(Drawable drawable){ int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0,0,width,height); drawable.draw(canvas); return bitmap; } //获得圆角图片的方法 public static Bitmap getRoundedCornerBitmap(Bitmap bitmap,float roundPx){ Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap .getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(rect); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; } //获得带倒影的图片方法 public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap){ final int reflectionGap = 4; int width = bitmap.getWidth(); int height = bitmap.getHeight(); Matrix matrix = new Matrix(); matrix.preScale(1, -1); Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, height/2, width, height/2, matrix, false); Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height/2), Config.ARGB_8888); Canvas canvas = new Canvas(bitmapWithReflection); canvas.drawBitmap(bitmap, 0, 0, null); Paint deafalutPaint = new Paint(); canvas.drawRect(0, height,width,height + reflectionGap, deafalutPaint); canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null); Paint paint = new Paint(); LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0, bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff, TileMode.CLAMP); paint.setShader(shader); // Set the Transfer mode to be porter duff and destination in paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); // Draw a rectangle using the paint with our linear gradient canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint); return bitmapWithReflection; } } ~~~ 第三步:修改main.xml布局文件,主要放了两个ImageView控件,代码如下: ~~~ ~~~ 第四步:修改主核心程序,ImageDemo.java,代码如下: ~~~ package com.android.tutor;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.widget.ImageView;public class Imagedemo extends Activity { private ImageView mImageView01,mImageView02; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); setupViews(); } private void setupViews(){ mImageView01 = (ImageView)findViewById(R.id.image01); mImageView02 = (ImageView)findViewById(R.id.image02); //获取壁纸返回值是Drawable Drawable drawable = getWallpaper(); //将Drawable转化为Bitmap Bitmap bitmap = ImageUtil.drawableToBitmap(drawable); //缩放图片 Bitmap zoomBitmap = ImageUtil.zoomBitmap(bitmap, 100, 100); //获取圆角图片 Bitmap roundBitmap = ImageUtil.getRoundedCornerBitmap(zoomBitmap, 10.0f); //获取倒影图片 Bitmap reflectBitmap = ImageUtil.createReflectionImageWithOrigin(zoomBitmap); //这里可以让Bitmap再转化为Drawable// Drawable roundDrawable = new BitmapDrawable(roundBitmap); // Drawable reflectDrawable = new BitmapDrawable(reflectBitmap); // mImageView01.setBackgroundDrawable(roundDrawable);// mImageView02.setBackgroundDrawable(reflectDrawable); mImageView01.setImageBitmap(roundBitmap); mImageView02.setImageBitmap(reflectBitmap); } } ~~~ 第五步:运行上述工程,查看效果如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0eb29e52.gif)   OK大功告成了!!   本文参考文献:http://wiki.impjq.net/doku.php?id=code:android-code:image-convert&rev=1275640889&mddo=print
';

(二十一)Android中创建与几种解析xml的方法!

最后更新于:2022-04-01 19:46:23

  大家好今天我今天给大家讲解一下android中xml的创建以及一些解析xml的常用方法。 首先是创建,我们用XmlSerializer这个类来创建一个xml文件,其次是解析xml文件,常用的有dom,sax,XmlPullParser等方法,由于sax代码有点复杂,本节只讲解一下dom与XmlPullParser解析,sax我将会在下一节单独讲解,至于几种解析xml的优缺点我就不再讲述了。 为了方便理解,我做了一个简单的Demo。首先首界面有三个按钮,点击第一个按钮会在sdcard目录下创建一个books.xml文件,另外两个按钮分别是调用dom与XmlPullParser方法解析xml文件,并将结果显示在一个TextView里。大家可以按照我的步骤一步步来: 第一步:新建一个Android工程,命名为XmlDemo. 第二步:修改main.xml布局文件,代码如下: ~~~
';

(二十)Android与JavaScript方法相互调用!

最后更新于:2022-04-01 19:46:20

在Android中通过WebView控件,可以实现要加载的页面与Android方法相互调用,我们要实现WebView中的addJavascriptInterface方法,这样html才能调用android方法,在这里我个人觉得有点和DWR相似。 为了让大家容易理解,我写了一个简单的Demo,具体步骤如下: 第一步:新建一个Android工程,命名为WebViewDemo(这里我在assets里定义了一个html页面)。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0ea19fa6.gif) 第二步:修改main.xml布局文件,增加了一个WebView控件还有Button控件,代码如下: ~~~
';

(十九)Android开发中,使用线程应该注意的问题!

最后更新于:2022-04-01 19:46:18

我们都知道Hanlder是线程与Activity通信的桥梁,我们在开发好多应用中会用到线程,有些人处理不当,会导致当程序结束时,线程并没有被销毁,而是一直在后台运行着,当我们重新启动应用时,又会重新启动一个线程,周而复始,你启动应用次数越多,开启的线程数就越多,你的机器就会变得越慢。 为了方便 大家理解,我写一个简单的Demo.功能就是每2秒中将应用的Title更换一次。具体步骤如下: 第一步:新建一个Android工程命名为ThreadDemo。 第二步:修改ThreadDemo.java,代码如下: ~~~ package com.tutor.thread;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.util.Log;public class ThreadDemo extends Activity { private static final String TAG = "ThreadDemo"; private int count = 0; private Handler mHandler = new Handler(); private Runnable mRunnable = new Runnable() { public void run() { //为了方便 查看,我们用Log打印出来 Log.e(TAG, Thread.currentThread().getName() + " " +count); count++; setTitle("" +count); //每2秒执行一次 mHandler.postDelayed(mRunnable, 2000); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //通过Handler启动线程 mHandler.post(mRunnable); } } ~~~ 第三步:运行上述工程,查看运行效果: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e9b81a3.gif)   当然上面不是重点,退出应用时,线程还在跑,打开Logcat视窗或者cmd终端查看,如下(刚吃了午餐回来,线程还在跑着): ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e9d2854.gif)   当我们再次启动应用时,会重新启动一个新的线程,如下图所示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e9f103d.gif)   所以我们在应用退出时,要将线程销毁,我们只要在Activity中的,onDestory()方法处理一下就OK了,如下代码所示: ~~~ @Override protected void onDestroy() { mHandler.removeCallbacks(mRunnable); super.onDestroy(); } ~~~   所以ThreadDemo.java的完整代码如下: ~~~ package com.tutor.thread;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.util.Log;public class ThreadDemo extends Activity { private static final String TAG = "ThreadDemo"; private int count = 0; private Handler mHandler = new Handler(); private Runnable mRunnable = new Runnable() { public void run() { //为了方便 查看,我们用Log打印出来 Log.e(TAG, Thread.currentThread().getName() + " " +count); count++; setTitle("" +count); //每2秒执行一次 mHandler.postDelayed(mRunnable, 2000); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //通过Handler启动线程 mHandler.post(mRunnable); } @Override protected void onDestroy() { //将线程销毁掉 mHandler.removeCallbacks(mRunnable); super.onDestroy(); }} ~~~   Ok~今天就写到这里,我午休去也~大家有不明白的可以留言!
';

(十八)列出Android设备中所有启动的服务,及判断某个服务是否开启!

最后更新于:2022-04-01 19:46:16

大家好,好久不见,今天在开发中遇到的一个问题给大家分享一下,我先前做了一个音乐播放器,因为播放音乐一般都是用服务来处理的。 当用户点击播放按钮时,音乐在服务中播放,然后用用户退出程序(服务进程还在,音乐还继续),所以妥用户点再次进入应用时,我们播放器要处于播放状态,这里我作了简单的处理,判断这个音乐服务是否开启来完成的。 今天给大家的小例子是列出Android设备中所有启动的服务,及判断某个服务是否开启,具体步骤如下了: 第一步:新建一个Android工程,命名为RunningService。 第二步:修改RunningService.java代码如下: ~~~ package com.tutor.runningservice;import java.util.List;import android.app.Activity;import android.app.ActivityManager;import android.os.Bundle;import android.widget.TextView;public class RunningService extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.main); TextView mTextView = new TextView(this); ActivityManager mActivityManager = (ActivityManager)getSystemService(ACTIVITY_SERVICE); List mServiceList = mActivityManager.getRunningServices(30); //我要判断的服务名字,我在launcher2里加了一个音乐服务 final String musicClassName = "com.android.launcher2.MusicService"; boolean b = MusicServiceIsStart(mServiceList, musicClassName); mTextView.setText("你要判断的服务状态为: " +b+"/n" + getServiceClassName(mServiceList)); setContentView(mTextView); } //通过Service的类名来判断是否启动某个服务 private boolean MusicServiceIsStart(List mServiceList,String className){ for(int i = 0; i < mServiceList.size(); i ++){ if(className.equals(mServiceList.get(i).service.getClassName())){ return true; } } return false; } //获取所有启动的服务的类名 private String getServiceClassName(List mServiceList){ String res = ""; for(int i = 0; i < mServiceList.size(); i ++){ res+=mServiceList.get(i).service.getClassName()+ " /n"; } return res; }} ~~~   第三步:运行上述工程,查看效果!   不看不知道,一看吓一跳,乖乖,开了这么多服务,难怪手机很快就没电了。   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e973d73.gif)   上面的一些服务好多是系统自带的,并且不可见的,我们可以到Settings->Applications->Running services查看 一共才看到十来个服务。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e992287.gif)   OK,今天就这么多,呵呵,继续上班中..............
';

(十七)Android中Intent传递对象的两种方法(Serializable,Parcelable)!

最后更新于:2022-04-01 19:46:13

大家好,好久不见,今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是Bundle.putParcelable(Key, Object);当然这些Object是有一定的条件的,前者是实现了Serializable接口,而后者是实现了Parcelable接口,为了让大家更容易理解我还是照常写了一个简单的Demo,大家就一步一步跟我来吧! 第一步:新建一个Android工程命名为ObjectTranDemo(类比较多哦!)目录结构如下图:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e90b518.gif) 第二步:修改main.xml布局文件(这里我增加了两个按钮)代码如下 ~~~
';

Android 中的拿来主义(编译,反编译,AXMLPrinter2,smali,baksmali)!

最后更新于:2022-04-01 19:46:11

**一、前言:** 大家好,今天给大家分享一下Android中的拿来主义,我们时常会碰到一个自己觉得很漂亮很帅气的应用(apk),所以我们会尝试用WinRAR等之类工具查看,而一般的应用程序打包后的目录通常是这样的如下图: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e80f5d9.gif "Android 中的拿来主义(编译,反编译,AXMLPrinter2,smali,baksmali)! - sikaodelang - sikaodelang的博客") 当然res里的图片是可以拿来就用的(笔者的好多应用的图片都是从别人的apk里扣出来的),而诸如layout里的布局及权限文件(AndroidManifest.xml)已经是一堆乱码了,完全看不懂,想看看别人是怎么布局的都不容易。还有源代码都被编译成了classes.dex,完全看不出什么线索。基于以上的困惑,笔者给大家分享一下Android中的拿来主义。 **二、所需工具(点击各自连接进入下载页面):** 1.[AXMLPrinter2.jar](http://code.google.com/p/android4me/downloads/list) 2.[baksmali.jar](http://code.google.com/p/smali/) 3.[smali.jar](http://code.google.com/p/smali/) **三、准备工作** 为了方便起见,作者把AXMLPrinter2.jar,还有baksmali.jar,还有smali.jar(下下来为了方便重命名),放在Android SDK tools文件夹中如下图所示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e82dbf1.gif "Android 中的拿来主义(编译,反编译,AXMLPrinter2,smali,baksmali)! - sikaodelang - sikaodelang的博客") 为了便于大家更容易程序比对,作者写了一个简单的应用(叫APKInstaller)目录结构如下图所示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e85f14a.gif "Android 中的拿来主义(编译,反编译,AXMLPrinter2,smali,baksmali)! - sikaodelang - sikaodelang的博客") **四、开始拿来主义** **1.用AXMLPrinter2.jar查看apk中的布局xml文件:** 将ApkInstaller应用生成的ApkInstaller.apk(为了方便起见放到tools目录里)用WinRAR等工具打开,将res/layout/main.xml解压出来(也还是放在tools目录里哦) 打开main.xml文件,内容如下(一堆天文): ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e876d69.gif "Android 中的拿来主义(编译,反编译,AXMLPrinter2,smali,baksmali)! - sikaodelang - sikaodelang的博客") 这时候AXMLPrinter2.jar派上用场了,打开cmd终端,一直进入到tools目录下,输入如下命令: **java -jar AXMLPrinter2.jar main.xml > main.txt.** (如下图所示) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e88d660.gif "Android 中的拿来主义(编译,反编译,AXMLPrinter2,smali,baksmali)! - sikaodelang - sikaodelang的博客") 打开main.txt代码如下(是不是有个123了呵呵~): ~~~ ~~~ 为了比对打开源程序中的main.xml代码如下(大家比对一下吧): ~~~ ~~~ **2.用baksmali.jar反编译classes.dex:** 将ApkInstaller.apk里的classes.dex解压到tools目录里,然后baksmali.jar就派上用场了,在cmd命令行里输入如下命令: j**ava -jar baksmali.jar -o classout/ classes.dex**.(如下图所示:) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e8a77d3.gif) 你将会发现在tools里多一个classout文件夹里面(我代码的包目录结构清晰可见呀),如下图所示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e8c49c9.gif) 从上面看出除了Android本身资源的类R开头的,我的源程序里只有一个ApkInstaller.java,完全吻合,真TMD的猥琐呵呵~ 下面我们看一下ApkInstaller.smali内容是什么,如以下代码: ~~~ .class public Lcom/tutor/apkinstaller/ApkInstaller;.super Landroid/app/Activity;.source "ApkInstaller.java"# instance fields.field private apkWeb:Landroid/webkit/WebView;# direct methods.method public constructor ()V .registers 1 .prologue .line 8 invoke-direct {p0}, Landroid/app/Activity;->()V return-void.end method# virtual methods.method public onCreate(Landroid/os/Bundle;)V .registers 5 .parameter "savedInstanceState" .prologue .line 13 invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V .line 14 const/high16 v2, 0x7f03 invoke-virtual {p0, v2}, Lcom/tutor/apkinstaller/ApkInstaller;->setContentView(I)V .line 15 const/high16 v2, 0x7f05 invoke-virtual {p0, v2}, Lcom/tutor/apkinstaller/ApkInstaller;->findViewById(I)Landroid/view/View; move-result-object v2 check-cast v2, Landroid/webkit/WebView; iput-object v2, p0, Lcom/tutor/apkinstaller/ApkInstaller;->apkWeb:Landroid/webkit/WebView; .line 16 iget-object v2, p0, Lcom/tutor/apkinstaller/ApkInstaller;->apkWeb:Landroid/webkit/WebView; invoke-virtual {v2}, Landroid/webkit/WebView;->getSettings()Landroid/webkit/WebSettings; move-result-object v1 .line 17 .local v1, webSettings:Landroid/webkit/WebSettings; const/4 v2, 0x1 invoke-virtual {v1, v2}, Landroid/webkit/WebSettings;->setJavaScriptEnabled(Z)V .line 19 const-string v0, "http://frankiewei.net/apk/demos/main/index.html#home" .line 20 .local v0, apkUrl:Ljava/lang/String; iget-object v2, p0, Lcom/tutor/apkinstaller/ApkInstaller;->apkWeb:Landroid/webkit/WebView; invoke-virtual {v2, v0}, Landroid/webkit/WebView;->loadUrl(Ljava/lang/String;)V .line 21 return-void.end method ~~~ 同样为了比对我们看一下ApkInstaller.java的源代码如下: ~~~ package com.tutor.apkinstaller;import android.app.Activity;import android.os.Bundle;import android.webkit.WebSettings;import android.webkit.WebView;public class ApkInstaller extends Activity { private WebView apkWeb; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); apkWeb = (WebView)findViewById(R.id.apk_web); WebSettings webSettings = apkWeb.getSettings(); webSettings.setJavaScriptEnabled(true); String apkUrl = "http://frankiewei.net/apk/demos/main/index.html#home"; apkWeb.loadUrl(apkUrl); }} ~~~   我相信大家 已经能看出来门道来了吧,hoho~   **3.用smali.jar编译classout成classes.dex:** 我们上一步已经将classes.dex反编译成了.smali文件,好了,我们看看smali文件看够了,在偿试把它编译成classes.dex吧, 输入如下命令:**java -jar smali.jar classout/ -o classes.dex.**如下图所示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aaf0e8e79a3.gif)   我们可以将新生成的classes.dex塞入ApkInstaller.apk里覆盖原来的classes.dex文件,这样我们的apk还是一样能用的哦~   Ok~今天就暂时写到这里,这片文章真是不容易呀,写了这么长时间,之间还出现过被来自武汉IP的人把这篇文章删除 过,我又重新写了一遍。希望大家多多进步!thx~
';

(十六)Android中万能的BaseAdapter(Spinner,ListView,GridView)的使用!

最后更新于:2022-04-01 19:46:09

大家好!今天给大家讲解一下BaseAdapter(基础适配器)的用法,适配器的作用主要是用来给诸如(Spinner,ListView,GridView)来填充数据的。而(Spinner,ListView,GridView)都有自己的适配器(记起来麻烦)。但是BaseAdapter(一招鲜)对他们来说却是通用的,为什么这么说呢,首先我们看一下API文档: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5997260a.gif) 我们看一下BaseAdapter已经实现了ListAdapter和SpinnerAdapter的接口,而GridView的适配器是实现了ListAdapter接口,只不过是二维的。所以说BaseAdapter对他们三者来说是通用的。   下面我来说一下BaseAdapter的主要用法.就是我们定义一个类(如:MyAdapter)而这个类继承BaseAdapter.因为它是implements了ListAdapter和SpinnerAdapter的接口,所以要实现里面的方法,代码如下(未作任何改动的):   ~~~ private class MyAdapter extends BaseAdapter{ @Override public int getCount() { // TODO Auto-generated method stub return 0; } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return null; } @Override public long getItemId(int position) { // TODO Auto-generated method stub return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub return null; } } ~~~   为了便于大家理解,老规矩写一个简单的Demo,大家按我的步骤来就OK了.   第一步:新建一个Android工程命名为BaseAdapterDemo.   第二步:修改main.xml代码如下: ~~~ ~~~ 第三步:修该BaseAdapterDemo.java代码如下: ~~~ package com.tutor.baseadapter;import android.app.Activity;import android.graphics.Color;import android.os.Bundle;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.GridView;import android.widget.ListView;import android.widget.Spinner;import android.widget.TextView;public class BaseAdapterDemo extends Activity { private Spinner mSpinner; private ListView mListView; private GridView mGridView; private MyAdapter mMyAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); setupViews(); } public void setupViews(){ mMyAdapter = new MyAdapter(); mSpinner = (Spinner)findViewById(R.id.spinner); mSpinner.setAdapter(mMyAdapter); mListView = (ListView)findViewById(R.id.listview); mListView.setAdapter(mMyAdapter); mGridView = (GridView)findViewById(R.id.gridview); mGridView.setAdapter(mMyAdapter); mGridView.setNumColumns(2); } //定义自己的适配器,注意getCount和getView方法 private class MyAdapter extends BaseAdapter{ @Override public int getCount() { // 这里我就返回10了,也就是一共有10项数据项 return 10; } @Override public Object getItem(int arg0) { return arg0; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // position就是位置从0开始,convertView是Spinner,ListView中每一项要显示的view //通常return 的view也就是convertView //parent就是父窗体了,也就是Spinner,ListView,GridView了. TextView mTextView = new TextView(getApplicationContext()); mTextView.setText("BaseAdapterDemo"); mTextView.setTextColor(Color.RED); return mTextView; } }} ~~~   第四步:运行程序效果图如下: 效果图一:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5998a316.gif) 效果图二: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae599bc013.gif)     等等,平时我在这里就和大家告别了,今天还没完呵呵,因为下面是我们的重点了,我们平常看的应用列表什么的,不是单单的一个TextView就可以了事的,所以我们可以在Layout里事先 定义好布局。这里我新建了一个名叫baseadapter_provider.xml文件,代码如下: ~~~ ~~~   将getView()方法修改如下: ~~~ @Override public View getView(int position, View convertView, ViewGroup parent) { // position就是位置从0开始,convertView是Spinner,ListView中每一项要显示的view //通常return 的view也就是convertView //parent就是父窗体了,也就是Spinner,ListView,GridView了.// TextView mTextView = new TextView(getApplicationContext());// mTextView.setText("BaseAdapterDemo");// mTextView.setTextColor(Color.RED);// return mTextView; //LayoutInflater不会的参照我的 Android 高手进阶教程(五) convertView = LayoutInflater.from(getApplicationContext()).inflate (R.layout.baseadapter_provider,null); TextView mTextView = (TextView)convertView.findViewById(R.id.textview); mTextView.setText("BaseAdapterDemo" + position); mTextView.setTextColor(Color.RED); return convertView; } ~~~ 再次运行看一下效果图如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae599df9e0.gif)   Ok,搞定了,呵呵,到这里我就要和大家 说再见了,大家 有什么不明白的地方可以留言,要源码的留下邮箱。thx~
';

(十五)通过Location获取Address的使用!

最后更新于:2022-04-01 19:46:07

大家好,上一节我讲了一下如何通过LocationManager来获取Location,没有看过上一节的同学,可以点击如下链接返回查看: [**Android高手进阶教程十四之---Android Location的使用!**](http://blog.csdn.net/Android_Tutor/archive/2010/06/15/5672911.aspx) 我们获取Location的目的之一肯定是有获取这个位置的详细地址,而我们有了Location在来获取Address就相对简单多了,因为GoogleApi已经封装好了方法,我们只需呀通过Location获取GeoPoint,然后在通过GeoPoint来获取我们想要的Address.下面是我做的一个简单的Demo.   第一步新建一个Android工程LocationDemo,注意这里选用的是(Google APIs),下面是文件目录结构: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5993e03a.gif)   第二步: 修改main.xml(相比第十四节增加了一个address的TextView),代码如下: ~~~ ~~~ 第三步:修改LocationDemo.java(增加了两个方法)代码如下: ~~~ package com.android.tutor;import java.util.List;import java.util.Locale;import com.google.android.maps.GeoPoint;import android.app.Activity;import android.content.Context;import android.location.Address;import android.location.Geocoder;import android.location.Location;import android.location.LocationManager;import android.os.Bundle;import android.widget.TextView;public class LocationDemo extends Activity { private TextView longitude; private TextView latitude; private TextView address; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); longitude = (TextView)findViewById(R.id.longitude); latitude = (TextView)findViewById(R.id.latitude); address = (TextView)findViewById(R.id.address); Location mLocation = getLocation(this); GeoPoint gp = getGeoByLocation(mLocation); Address mAddress = getAddressbyGeoPoint(this, gp); longitude.setText("Longitude: " + mLocation.getLongitude()); latitude.setText("Latitude: " + mLocation.getLatitude()); address.setText("Address: " + mAddress.getCountryName()+"," + mAddress.getLocality()); } //Get the Location by GPS or WIFI public Location getLocation(Context context) { LocationManager locMan = (LocationManager) context .getSystemService(Context.LOCATION_SERVICE); Location location = locMan .getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location == null) { location = locMan .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); } return location; } //通过Location获取GeoPoint public GeoPoint getGeoByLocation(Location location) { GeoPoint gp = null; try { if (location != null) { double geoLatitude = location.getLatitude() * 1E6; double geoLongitude = location.getLongitude() * 1E6; gp = new GeoPoint((int) geoLatitude, (int) geoLongitude); } } catch (Exception e) { e.printStackTrace(); } return gp; } //通过GeoPoint来获取Address public Address getAddressbyGeoPoint(Context cntext, GeoPoint gp) { Address result = null; try { if (gp != null) { Geocoder gc = new Geocoder(cntext, Locale.CHINA); double geoLatitude = (int) gp.getLatitudeE6() / 1E6; double geoLongitude = (int) gp.getLongitudeE6() / 1E6; List
lstAddress = gc.getFromLocation(geoLatitude, geoLongitude, 1); if (lstAddress.size() > 0) { result = lstAddress.get(0); } } } catch (Exception e) { e.printStackTrace(); } return result; }} ~~~ 第四步:最重要一步在AndroidManiefest.xml中导入Google Api(第14行代码)库,代码如下: ~~~ ~~~   第五步:运行上述工程,效果如下图如示: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae59955028.gif)   OK,今天就到这里,如果有什么不明白的,或者想要源代码的,请留下问题或者邮箱。Thx~
';

(十四)Android Location的使用!!

最后更新于:2022-04-01 19:46:04

大家好,今天说说**Location**, **Location**在**Android**开发中还是经常用到的,比如 通过经纬度获取天气,根据**Location**获取所在地区详细**Address**(比如**Google Map**开发).等。而在**Android **中通过**LocationManager**来获取**Location**.通常获取**Location**有**GPS**获取,**WIFI**获取。 我今天做一个简单的小**Demo**,来教大家如何获取**Location**,从而获取经纬度。下一节将教大家通过**Location**来获取**Address**.   首先第一步:   创建一个**Android**工程命名为**LocationDemo**.   第二步:修改**main.xml**代码如下: ~~~ ~~~   第三步:修改**LocationDemo.java**,代码如下: ~~~ package com.android.tutor;import android.app.Activity;import android.content.Context;import android.location.Location;import android.location.LocationManager;import android.os.Bundle;import android.widget.TextView;public class LocationDemo extends Activity { private TextView longitude; private TextView latitude; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); longitude = (TextView)findViewById(R.id.longitude); latitude = (TextView)findViewById(R.id.latitude); Location mLocation = getLocation(this); longitude.setText("Longitude: " + mLocation.getLongitude()); latitude.setText("Latitude: " + mLocation.getLatitude()); } //Get the Location by GPS or WIFI public Location getLocation(Context context) { LocationManager locMan = (LocationManager) context .getSystemService(Context.LOCATION_SERVICE); Location location = locMan .getLastKnownLocation(LocationManager.GPS_PROVIDER); if (location == null) { location = locMan .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); } return location; }} ~~~   第四步:增加权限,修改**AndroidManifest.xml**代码如下(第16行为所增行): ~~~ ~~~   第五步:运行**LocationDemo**工程,所得效果如下(真机深圳测试):   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5991fea6.gif)
';

(十三)Android 数据库SQLiteDatabase的使用!!

最后更新于:2022-04-01 19:46:02

  大家好,好久没有更新博客了,最近由于身体不适让大家久等了,好了,直接进入主题~ **Android *提供了三种数据存储方式,第一种是文件存储;第二种是**SharedPreferences**存储;第三种就是数据库**SQLiteDatabase**存储。 文件存储我就不用多说了,而**SharedPreferences**可以存取简单的数据(int,double,float.etc),它经常用于数据缓存,因为它读取存储简单。详细可以参见本系列。[Android高手进阶教程(七)之----Android 中Preferences的使用!](http://blog.csdn.net/Android_Tutor/archive/2010/04/26/5531849.aspx) 今天我们将讲一下**SQLiteDatabase**的使用**。**而掌握**SqliteDatabase**,将会我们接下来掌握**ContentProvider**打下良好的基石**。** 为了让大家更好的掌握,我们手把手完成该节的**Demo**。 第一步:新建一个Android工程,命名为SQLiteDatabaseDemo. ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae59828436.gif) 第二步:创建一个新的类**BooksDB.java**这个类要继承于android.database.sqlite.SQLiteOpenHelper抽象类,我们要实现其中两个方法:onCreate(),onUpdate.具体代码如下: ~~~ package com.android.tutor;import android.content.ContentValues;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;public class BooksDB extends SQLiteOpenHelper { private final static String DATABASE_NAME = "BOOKS.db"; private final static int DATABASE_VERSION = 1; private final static String TABLE_NAME = "books_table"; public final static String BOOK_ID = "book_id"; public final static String BOOK_NAME = "book_name"; public final static String BOOK_AUTHOR = "book_author"; public BooksDB(Context context) { // TODO Auto-generated constructor stub super(context, DATABASE_NAME, null, DATABASE_VERSION); } //创建table @Override public void onCreate(SQLiteDatabase db) { String sql = "CREATE TABLE " + TABLE_NAME + " (" + BOOK_ID + " INTEGER primary key autoincrement, " + BOOK_NAME + " text, "+ BOOK_AUTHOR +" text);"; db.execSQL(sql); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = "DROP TABLE IF EXISTS " + TABLE_NAME; db.execSQL(sql); onCreate(db); } public Cursor select() { SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db .query(TABLE_NAME, null, null, null, null, null, null); return cursor; } //增加操作 public long insert(String bookname,String author) { SQLiteDatabase db = this.getWritableDatabase(); /* ContentValues */ ContentValues cv = new ContentValues(); cv.put(BOOK_NAME, bookname); cv.put(BOOK_AUTHOR, author); long row = db.insert(TABLE_NAME, null, cv); return row; } //删除操作 public void delete(int id) { SQLiteDatabase db = this.getWritableDatabase(); String where = BOOK_ID + " = ?"; String[] whereValue ={ Integer.toString(id) }; db.delete(TABLE_NAME, where, whereValue); } //修改操作 public void update(int id, String bookname,String author) { SQLiteDatabase db = this.getWritableDatabase(); String where = BOOK_ID + " = ?"; String[] whereValue = { Integer.toString(id) }; ContentValues cv = new ContentValues(); cv.put(BOOK_NAME, bookname); cv.put(BOOK_AUTHOR, author); db.update(TABLE_NAME, cv, where, whereValue); }} ~~~     第三步:修改main.xml布局如下,由两个EditText和一个ListView组成,代码如下: ~~~ ~~~ 第四步:修改SQLiteDatabaseDemo.java代码如下: ~~~ package com.android.tutor;import android.app.Activity;import android.content.Context;import android.database.Cursor;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.BaseAdapter;import android.widget.EditText;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;public class SQLiteDatabaseDemo extends Activity implements AdapterView.OnItemClickListener { private BooksDB mBooksDB; private Cursor mCursor; private EditText BookName; private EditText BookAuthor; private ListView BooksList; private int BOOK_ID = 0; protected final static int MENU_ADD = Menu.FIRST; protected final static int MENU_DELETE = Menu.FIRST + 1; protected final static int MENU_UPDATE = Menu.FIRST + 2; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); setUpViews(); } public void setUpViews(){ mBooksDB = new BooksDB(this); mCursor = mBooksDB.select(); BookName = (EditText)findViewById(R.id.bookname); BookAuthor = (EditText)findViewById(R.id.author); BooksList = (ListView)findViewById(R.id.bookslist); BooksList.setAdapter(new BooksListAdapter(this, mCursor)); BooksList.setOnItemClickListener(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); menu.add(Menu.NONE, MENU_ADD, 0, "ADD"); menu.add(Menu.NONE, MENU_DELETE, 0, "DELETE"); menu.add(Menu.NONE, MENU_DELETE, 0, "UPDATE"); return true; } public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); switch (item.getItemId()) { case MENU_ADD: add(); break; case MENU_DELETE: delete(); break; case MENU_UPDATE: update(); break; } return true; } public void add(){ String bookname = BookName.getText().toString(); String author = BookAuthor.getText().toString(); //书名和作者都不能为空,或者退出 if (bookname.equals("") || author.equals("")){ return; } mBooksDB.insert(bookname, author); mCursor.requery(); BooksList.invalidateViews(); BookName.setText(""); BookAuthor.setText(""); Toast.makeText(this, "Add Successed!", Toast.LENGTH_SHORT).show(); } public void delete(){ if (BOOK_ID == 0) { return; } mBooksDB.delete(BOOK_ID); mCursor.requery(); BooksList.invalidateViews(); BookName.setText(""); BookAuthor.setText(""); Toast.makeText(this, "Delete Successed!", Toast.LENGTH_SHORT).show(); } public void update(){ String bookname = BookName.getText().toString(); String author = BookAuthor.getText().toString(); //书名和作者都不能为空,或者退出 if (bookname.equals("") || author.equals("")){ return; } mBooksDB.update(BOOK_ID, bookname, author); mCursor.requery(); BooksList.invalidateViews(); BookName.setText(""); BookAuthor.setText(""); Toast.makeText(this, "Update Successed!", Toast.LENGTH_SHORT).show(); } @Override public void onItemClick(AdapterView parent, View view, int position, long id) { mCursor.moveToPosition(position); BOOK_ID = mCursor.getInt(0); BookName.setText(mCursor.getString(1)); BookAuthor.setText(mCursor.getString(2)); } public class BooksListAdapter extends BaseAdapter{ private Context mContext; private Cursor mCursor; public BooksListAdapter(Context context,Cursor cursor) { mContext = context; mCursor = cursor; } @Override public int getCount() { return mCursor.getCount(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView mTextView = new TextView(mContext); mCursor.moveToPosition(position); mTextView.setText(mCursor.getString(1) + "___" + mCursor.getString(2)); return mTextView; } }} ~~~ 第五步:运行程序效果如下:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5984b1fe.gif) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae59864b9c.gif)   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5987d157.gif) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5989e8fb.gif)   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae598bac1f.gif)    ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae598d70f9.gif)   第六步:查看我们所建的数据库。有两种方法:第一种用命令查看:adb shell ls data/data/com.android.tutor/databases。 另一种方法是用DDMS查看,在data/data下面对应的应用程序的包名 下会有如下数据库,如图所示:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae598f088b.gif)     由于代码都是现写,时间原因,没有全部加注释,如果大家 有什么不懂的地方,可以留言,我会尽快答复,如果需源代码,请留下你的Email 地址,ok,今天就到这里,大家晚安! ****
';

(十二)Android 在一个应用中如何启动另外一个已安装的应用!!!

最后更新于:2022-04-01 19:46:00

今天晚上Jimmy问了我一个问题,就是如何在一个应用中 通过某个事件,而去启动另外一个已安装的应用。所以愿意和大家分享一下! 而为了能让大家更加容易的理解,我写了一个简单的Demo,我们的程序有俩个按钮,其中一个点击会启动我自己写的应用(一个3D应用为例),而另外一个按钮会启动系统自带的应用(如,日历,闹钟,计算器等等).这里我一日历为例子!   首先看一下我们的效果图(点击第一个按钮为例):   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae597ec101.gif)  ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5980f3c9.gif)     下面是Demo的详细步骤:   一、新建一个Android工程命名为StartAnotherApplicationDemo.   二、修改main.xml布局,代码如下:   ~~~
';

(十一)Android 通用获取Ip的方法(判断手机是否联网的方法)!!!

最后更新于:2022-04-01 19:45:58

大家好,我们这一节讲一下,Android获取Ip的一些方法,在我们开发中,有判断手机是否联网,或者想获得当前手机的Ip地址,当然WIFI连接的和 我们3G卡的Ip地址当然是不一样的.   首先我尝试了如下方法:   ~~~ WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);WifiInfo wifiInfo = wifiManager.getConnectionInfo();int ipAddress = wifiInfo.getIpAddress(); ~~~ 但是获得的居然是一个整数,我尝试了用些数学方法都没有成功!,所以这种方法不可取!   最后查了一些资料,发现如下方法是比较通用的,我尝试了WIFI和G3卡,都获取了争取的Ip地址:代码如下:   ~~~ public String getLocalIpAddress() { try { for (Enumeration en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) { NetworkInterface intf = en.nextElement(); for (Enumeration enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress()) { return inetAddress.getHostAddress().toString(); } } } } catch (SocketException ex) { Log.e(LOG_TAG, ex.toString()); } return null;} ~~~   当我的手机处于飞行状态是,获得Ip地址为空,刚好符合要求!!!   希望对大家有所帮助!谢谢~
';

(十)Android PopupWindow的使用!!!

最后更新于:2022-04-01 19:45:55

大家好,我们这一节讲的是Android PopupWindow的使用! 在我理解其实PopupWindow其实类似于一个不能动的Widget(仅从显示效果来说!)   它是浮在别的窗口之上的.   下面我将给大家做一个简单的Demo,类似于音乐播放器的Widget的效果,点击Button的时候出来PopupWindow,首先我们看一下效果图:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5979bb5a.gif)   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae597ba537.gif)   下面是核心代码:   ~~~ package com.android.tutor;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup.LayoutParams;import android.widget.Button;import android.widget.PopupWindow;public class PopupWindowDemo extends Activity implements OnClickListener{ private Button btn; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btn = (Button)findViewById(R.id.btn); btn.setOnClickListener(this); } @Override public void onClick(View v) { Context mContext = PopupWindowDemo.this; if (v.getId() == R.id.btn) { LayoutInflater mLayoutInflater = (LayoutInflater) mContext .getSystemService(LAYOUT_INFLATER_SERVICE); View music_popunwindwow = mLayoutInflater.inflate( R.layout.music_popwindow, null); PopupWindow mPopupWindow = new PopupWindow(music_popunwindwow, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); mPopupWindow.showAtLocation(findViewById(R.id.main), Gravity.RIGHT|Gravity.BOTTOM, 0, 0); } }} ~~~ 需要强调的是这里PopupWindow必须有某个事件触发才会显示出来,不然总会抱错,不信大家可以试试!   随着这个问题的出现,就会同学问了,那么我想初始化让PopupWindow显示出来,那怎么办了,不去寄托于其他点击事件,   在这里我用了定时器Timer来实现这样的效果,当然这里就要用到Handler了,如果大家不理解的可以返回 ### [Android高手进阶教程(九)之----Android Handler的使用!!](http://blog.csdn.net/Android_Tutor/archive/2010/05/08/5568806.aspx)看一看,加深了解:   下面是核心代码:   ~~~ package com.android.tutor;import java.util.Timer;import java.util.TimerTask;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup.LayoutParams;import android.widget.PopupWindow;public class PopupWindowDemo extends Activity{ private Handler mHandler = new Handler(){ public void handleMessage(Message msg) { switch (msg.what) { case 1: showPopupWindow(); break; } }; }; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //create the timer Timer timer = new Timer(); timer.schedule(new initPopupWindow(), 100); } private class initPopupWindow extends TimerTask{ @Override public void run() { Message message = new Message(); message.what = 1; mHandler.sendMessage(message); } } public void showPopupWindow() { Context mContext = PopupWindowDemo.this; LayoutInflater mLayoutInflater = (LayoutInflater) mContext .getSystemService(LAYOUT_INFLATER_SERVICE); View music_popunwindwow = mLayoutInflater.inflate( R.layout.music_popwindow, null); PopupWindow mPopupWindow = new PopupWindow(music_popunwindwow, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT); mPopupWindow.showAtLocation(findViewById(R.id.main), Gravity.CENTER, 0, 0); }} ~~~   效果如下图:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae597d1661.gif)   这样就可以初始化PopupWindow了,呵呵,这一节的布局文件有点多,如果大家想要源码的话,留下你们的Email,我会尽快发送给大家的 ,今天就到这里,大家有什么不明白的欢迎留言!!!谢谢~   要源码的太多,我快崩溃了,所以上传了。下载地址: [http://d.download.csdn.net/down/2871531/Android_Tutor](http://d.download.csdn.net/down/2871531/Android_Tutor)
';

(九)Android Handler的使用!!!

最后更新于:2022-04-01 19:45:53

大家好我们这一节讲的是Android Handler的使用,在讲Handler之前,我们先提个小问题,就是如何让程序5秒钟更新一下Title.   首先我们看一下习惯了Java编程的人,在不知道Handler的用法之前是怎么样写的程序,代码如下所示:   ~~~ package com.android.tutor;import java.util.Timer;import java.util.TimerTask;import android.app.Activity;import android.os.Bundle;public class HandlerDemo extends Activity { //title为setTitle方法提供变量,这里为了方便我设置成了int型 private int title = 0; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Timer timer = new Timer(); timer.scheduleAtFixedRate(new MyTask(), 1, 5000); } private class MyTask extends TimerTask{ @Override public void run() { setTitle("Welcome to Mr Wei's blog " + title); title ++; } }} ~~~   然而当我们执行程序,并不能达到我们预期的效果,所以Android 引进了Handler 这个特殊的类,可以说它是Runnable和Activity交互的桥梁 ,所以我们只要在run方法中发送Message,而在Handler里,通过不同的Message执行不同的任务。   所以我们修改后的代码如下:   ~~~ package com.android.tutor;import java.util.Timer;import java.util.TimerTask;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;public class HandlerDemo extends Activity { //title为setTitle方法提供变量,这里为了方便我设置成了int型 private int title = 0; private Handler mHandler = new Handler(){ public void handleMessage(Message msg) { switch (msg.what) { case 1: updateTitle(); break; } }; }; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Timer timer = new Timer(); timer.scheduleAtFixedRate(new MyTask(), 1, 5000); } private class MyTask extends TimerTask{ @Override public void run() { Message message = new Message(); message.what = 1; mHandler.sendMessage(message); } } public void updateTitle(){ setTitle("Welcome to Mr Wei's blog " + title); title ++; }} ~~~ 下面我们看一下效果图:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae59771de3.gif) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae59784a27.gif)
';

(八)Android Widget开发案例(世界杯倒计时!)

最后更新于:2022-04-01 19:45:51

今天我们要写一下Android Widget的开发,由于快点凌晨,我就不说的太具体了,同志们就模仿吧!首先看一下效果图:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae596eaffe.gif)   下面是Demo的详细步骤:   一、新建一个Android工程命名为:WidgetDemo.   二、准备素材,一个是Widget的图标,一个是Widget的背景。存放目录如下图:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5971e1d4.gif)   三、修改string.xml文件如下: ~~~ Hello World, WidetDemo! DaysToWorldCup   ~~~ 四、建立Widget内容提供者文件,我们在res下建立xml文件夹,并且新建一个widget_provider.xml代码入下:   ~~~ ~~~   五、修改main.xml布局,代码如下:   ~~~ ~~~   六、修改WidgetDemo.java代码如下: ~~~ package com.android.tutor;import java.util.Calendar;import java.util.Date;import java.util.GregorianCalendar;import java.util.Timer;import java.util.TimerTask;import android.appwidget.AppWidgetManager;import android.appwidget.AppWidgetProvider;import android.content.ComponentName;import android.content.Context;import android.widget.RemoteViews;public class WidetDemo extends AppWidgetProvider { /** Called when the activity is first created. */ @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { Timer timer = new Timer(); timer.scheduleAtFixedRate(new MyTime(context,appWidgetManager), 1, 60000); super.onUpdate(context, appWidgetManager, appWidgetIds); } private class MyTime extends TimerTask{ RemoteViews remoteViews; AppWidgetManager appWidgetManager; ComponentName thisWidget; public MyTime(Context context,AppWidgetManager appWidgetManager){ this.appWidgetManager = appWidgetManager; remoteViews = new RemoteViews(context.getPackageName(),R.layout.main); thisWidget = new ComponentName(context,WidetDemo.class); } public void run() { Date date = new Date(); Calendar calendar = new GregorianCalendar(2010,06,11); long days = (((calendar.getTimeInMillis()-date.getTime())/1000))/86400; remoteViews.setTextViewText(R.id.wordcup, "距离南非世界杯还有" + days+"天"); appWidgetManager.updateAppWidget(thisWidget, remoteViews); } } } ~~~   七、修改配置文件AndroidManifest.xml,代码如下: ~~~ ~~~   八、点击运行(Ctrl+F11),之,运行成功后,我们长时间点击桌面,会出现如下俩个,依次点击,就可以看到最上面的效果图:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5973a829.gif) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae59751947.gif)   今天就到这里了,我困了呵呵,我发现时间好像不对劲,lol~我也不去多想了,大家知道的告诉我下!对日历这些东西不是太了解,谢谢!!
';

(七)Android 中Preferences的使用!

最后更新于:2022-04-01 19:45:49

大家好,我们这一节讲的是Android Preferences 的学习,Preferences 在Android当中被用来记录应用,以及用户喜好等等,它可以用来保存 简单的数据类型,如Int,Double,Boolean等。Preferences中保存的数据可以理解为Map型。我们通过**PreferenceManager**以及`**getDefaultSharedPreferences(Context)**来获取它,比如当我们想获得整数我们可以用`**`getInt(String key, int defVal)`**.获取里面的某个键值,当我们想修改时候我们用**`putInt(String key, int newVal),`**`最后用`**`edit(),`**`方法提交!千万不要忘记了哦~`   为了让大家跟好的理解我做了一个简单的Demo,程序主要有个TextView控件,上面写着用户使用改应用的次数。效果如下图所示:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae5968e733.gif)   下面是实现Demo的大体步骤:   一、新建一个Android工程命名为:PreferencesDemo。   二、在修改main.xml布局文件,这里只是在TextView控件里加了一个id.代码如下:   ~~~ ~~~   三、修改PreferenceDemo.java的代码,全部代码如下:   ~~~ package com.android.tutor;import android.app.Activity;import android.content.SharedPreferences;import android.os.Bundle;import android.preference.PreferenceManager;import android.widget.TextView;public class PreferencesDemo extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); SharedPreferences mPerferences = PreferenceManager .getDefaultSharedPreferences(this); int counter = mPerferences.getInt("counter", 0); TextView mTextView = (TextView)findViewById(R.id.text); mTextView.setText("This app has been started " + counter + " times."); SharedPreferences.Editor mEditor = mPerferences.edit(); mEditor.putInt("counter", ++counter); mEditor.commit(); }} ~~~   四、运行代码,实现上述效果.   五、查看Preferences文件,首先打开命令终端:adb shell一下,然后cd data/data进入该目录,ls一下我们会发现一大堆包文件,入下图所示:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae596ac3d8.gif)   cd com.android.tutor(这里是我程序的包名)/shared_prefs,ls一下会发现.xml文件如下图:   ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-10_57aae596cb464.gif)   打开.xml文件,格式如下(为什么这样大家自己去理解):   ~~~ ~~~   OK,今天就到此为止,以上全是个人愚见,如果有什么地方不对的,请指正,谢谢大家!
';