您的位置:首页 > 移动开发 > Android开发

Android页面间数据传递方式

2015-10-12 16:35 393 查看
Android页面间数据传递方式

一、Activity之间数据传递与共享

1、基于消息的通信机制 Intent---bounble,extra

A)Android为了屏蔽进程的概念,利用不同组件【Activity、Service】来表示进程之间的通信!其核心是Intent,通过Intent可以开启一个Activity或Service,不论这个Activity或者Service是当前应用还是其他应用。

B)数据类型有限,比如遇到不可序列化的数据Bitmap,InputStream,或者LinkList链表等数据类型就不太好。

C)Intent包括两部分:

目的[action]:要往哪里去;

内容[category、data]:路上带了些啥,区分性数据和内容型数据

D)Intent类型

显式:直接指定消息目的地,只适合同一进程内不同组件之间通信,如new Intent(this,Target.class)

隐式:AndroidMainifest.xml中注册,一般用于跨进程通信,如new Intent(String action)

E)实现Intent简单继承间通信 ,显式实现较为简单

在AndroidManifest.xml中定义

说明:

1)一个activity包含

零个或多个主要是作为匹配的标准,能否匹配成功由,、三个tag决定

2)一个包括

一个或多个:

零个或多个:

--说明该是该project运行的第一个界面

--说明该可以作为Launcher的,即系统操作界面

--缺省情况

零个或多个:指定携带的数据的类型,使用MIME类型描述方式来描述

eg:

video/mpeg表示编码格式为mpeg的视频,

也可以使用通配符video/*表示任意格式的视频文件类型;

在查询ContentProvider时,可以使用

查询上来的数据是多个记录

查询上来的数据是单个记录

如上设置,要重写SQLiteOpenHelper的getType(Uri uri)方法

eg:

@Override

public String getType(Uri uri) {

final int match = sUriMatcher.match(uri) ;

switch(match)

{

case NOTES :

case LIVE_FOLDER_NOTES:

return "vnd.android.cursor.dir/vnd.myq.note" ;



case NOTES_ID :

return "vnd.android.cursor.item/vnd.myq.note" ;



default:

throw new IllegalArgumentException("invalid uri : " + uri) ;

}

}

数据的URI由scheme(协议),host,port,path四部分:scheme://host:port/path
http://localhost:8080/test.jsp" />

3)一个Intent对应多种匹配结果的处理说明:

分响应消息的组件类型:

3.1)如果是Service那么这些Service都可以启动并处理消息

3.2)如果是Activity则会弹出对话框让用户选择

4)安全性问题

如果不同进程间的组件可以通过隐式消息互相通信,那程序不是可以轻易调用到其他的程序或者系统中的一些敏感程序的组件,这样会不会很不安全呢?

其实Android在安全方面有一个统一,完备和轻便的安全策略模型。

简单一点说就是:权限设置问题

我们可以自己定义permission,然后在需要的组件处设置该permission,那么用户要想该组件,必须要配置该permission,否则访问失败的!

eg:

4.1)定义permission



android:name="com.myq.android.permission.DATETIME_SERVICE"

android:permissionGroup="android.permission-group.MYQ_INFO"

android:protectionLevel="normal"

/>

4.2)配置permission





4.3)使用permission

2、 利用static静态数据,public static 成员变量

事实上,回收期并不可靠,尤其是在手机上,更加不可靠。因此,除非要使自己程序越老越糟糕,否则尽量远离static。

使用static常见错误:

ERROR/AndroidRuntime(4958): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget

3、 基于外部存储的传输

File/Preference/Sqlite,如果要针对第三方应用需要Content Provider

4、基于IPC通信机制

Context 与 service之间的传输,如Activity与Service之间通信,定义AIDL接口文件,示例:http://www.eoeandroid.com/thread-36249-1-1.html

有了Intent这种基于消息的进程内或进程间通信模型,我们就可以通过Intent去开启一个Service,可以通过Intent跳转到另一个Activity,不论上面的Service或Activity是在当前进程还是其它进程内即不论是当前应用还是其它应用的Service或Activity,通过消息机制都可以进行通信!

但是通过消息机制实现的进程间通信,有一个弊端就是,如果我们的Activity与Service之间的交往不是简单的Activity开启Service操作,而是要随时发一些控制请求,那么必须就要保证Activity在Service的运行过程中随时可以连接到Service。

eg:音乐播放程序

后台的播放服务往往独立运行,以方便在使用其他程序界面时也能听到音乐。同时这个后台播放服务也会定义一个控制接口,比如播放,暂停,快进等方法,任何时候播放程序的界面都可以连接到播放服务,然后通过这组控制接口方法对其控制。

如上的需求仅仅通过Intent去开启Service就无法满足了!从而Android的显得稍微笨重的IPC机制就出现了,然而它的出现只适用于Activity与Service之间的通信,类似于远程方法调用,就像是C/S模式的访问,通过定义AIDL接口文件来定义一个IPC接口,Server端实现IPC接口,Client端调用IPC接口的本地代理。

由于IPC调用是同步的,如果一个IPC服务需要超过几毫秒的时间才能完成的话,你应该避免在Activity的主线程中调用,否则IPC调用会挂起应用程序导致界面失去响应。在 这种情况下,应该考虑单起一个线程来处理IPC访问。



两个进程间IPC看起来就象是一个进程进入另一个进程执行代码然后带着执行的结果返回。

IPC机制鼓励我们“尽量利用已有功能,利用IPC和包含已有功能的程序协作完成一个完整的项目”

IPC实现demo:

我的

project -- MultiProcessTest

package -- com.myq.android.MultiProcessTest

1、AIDL文件,我是放在package下,

文件名称为:

IDateTimeService.aidl

文件内容为:

package com.myq.android.MultiProcessTest ;

interface IDateTimeService

{

String getCurrentDateTime(in String format) ;

}

如果正确配置,会在gen下,生成同名的java文件

简单摘要:

//我们需要实现的类Stub

public interface IDateTimeService extends android.os.IInterface

{

...

public static abstract class Stub

extends android.os.Binder

implements com.myq.android.MultiProcessTest.IDateTimeService

{

...

//获取实例的方法asInterface

public static com.myq.android.MultiProcessTest.IDateTimeService asInterface(android.os.IBinder obj)

{

...

}

...

}

//我们自己的业务方法,需要实现的

public java.lang.String getCurrentDateTime(java.lang.String format) throws android.os.RemoteException;

}

2、Service中实现IDateTimeService.Stub

eg:

package com.myq.android.MultiProcessTest;

import java.text.SimpleDateFormat;

import java.util.Date;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import android.os.RemoteException;

import android.util.Log;

public class DateTimeService extends Service {

public static final String DATETIME_SERVICE_ACTION = "com.myq.android.MultiProcessTest.DATETIMESERVICE_ACTION" ;

private static final String TAG = "--------DateTimeService-------" ;

private SimpleDateFormat sdf ;

private final IDateTimeService.Stub stub = new IDateTimeService.Stub()

{



public String getCurrentDateTime(String format) throws RemoteException {

return getCurrentDateTimeString(format) ;

}

} ;

private synchronized String getCurrentDateTimeString(String format)

{

sdf = new SimpleDateFormat(format) ;

final String temp = sdf.format(new Date()) ;

Log.i(TAG,"getCurrentDateTimeString--" + Thread.currentThread() + "--" + temp) ;

return temp ;

}

public IBinder onBind(Intent arg0)

{

Log.i(TAG, "onBind--" + Thread.currentThread()) ;

return stub;

}

}

3、Client端代码实现

private ServiceConnection mServiceConn = new ServiceConnection()

{



public void onServiceConnected(ComponentName name, IBinder service) {

mDateTimeService = IDateTimeService.Stub.asInterface(service) ;

}



public void onServiceDisconnected(ComponentName name) {

mDateTimeService = null ;

}

} ;

说明:

网上的好多资料都没有涉及IPC调用的AIDL的具体说明!

它本质上是Server端和Client端都具有相同的AIDL文件,要位于相同的包下,即package的包名药一样,然后才能正确的通过proxy访问,否则client与server的aidl文件处于不同package会出错的。

aidl模型如下:

|<--------------------aidl---------------------->|

client端-->proxy ----------parcel数据包-------- stub<---server端

从而proxy+parcel+stub构成了aidl.

只不过,proxy运行在客户进程,而stub运行在服务端进程。

当你通过aidl去访问服务端时,客户端会阻塞在proxy,服务端处理完后,通知proxy返回。

5、基于Application Context 相当于web的Application

可以通过Context.GetApplicationContext或者Context.GetApplication方法获得Application Context。但注意,这里获得只是Context对象,更理想的是获取一个类的对象。如下定义一个类:

package net.blogjava.mobile1;

import android.app.Application;

import android.graphics.Bitmap;

public class MyApp extends Application

{

private Bitmap mBitmap;

public Bitmap getBitmap()

{

return mBitmap;

}

public void setBitmap(Bitmap bitmap)

{

this .mBitmap = bitmap;

}



}

上面的类与普通的类没有什么本职区别,但该类继承Application,是其子类,这也是使用Application.Context的第一步,定义一个继承自Application的类。然后,就在这个子类下定义任何我们想使其全局存在的变量,如本例的Bitmap对象。当然,还需要在标签中使用android:name 属性来指定这个类。代码如下:

< application android:name =".MyApp" android:icon ="@drawable/icon" android:label ="@string/app_name" >



</ application>

最后,使用。从该子类中存取对象,代码如下

存入:

MyApp myApp = (MyApp)getApplication();



Bitmap bitmap = BitmapFactory.decodeResource( this .getResources(), R.drawable.icon);



myApp.setBitmap(bitmap);

取出:

ImageView imageview = (ImageView)findViewById(R.id.ivImageView);



MyApp myApp = (MyApp)getApplication();



imageview.setImageBitmap(myApp.getBitmap());

上述两段代码可在任何Service、Activity中使用,全局的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: