Android Project 调用jar包形式的其他 Android Activity

来源:互联网 发布:沙迪克火花机怎样编程 编辑:程序博客网 时间:2024/04/30 01:47
☆ 预备知识:
1、关于JAR
基本介绍:
    JAR(Java Archive,Java 归档文件)是与平台无关的文件格式,它允许将许多文件组合成一个压缩文件。
    JAR 文件格式以流行的 ZIP 文件格式为基础。与 ZIP 文件不同的是,JAR 文件不仅用于压缩和发布,而且还用于部署和封装库、组件和插件程序,并可被像编译器和 JVM 这样的工具直接使用。在 JAR 中包含特殊的文件,如 manifests 和部署描述符,用来指示工具如何处理特定的 JAR。
使用范围:
一个 JAR 文件可以用于
□ 用于发布和使用类库
□ 作为应用程序和扩展的构建单元
□ 作为组件、applet 或者插件程序的部署单位
□ 用于打包与组件相关联的辅助资源
相关特点:
    JAR 文件格式提供了许多优势和功能,其中很多是传统的压缩格式如 ZIP 或者 RAR 所没有提供的。它们包括:
□ 安全性 可以对 JAR 文件内容加上数字化签名。这样,能够识别签名的工具就可以有选择地为您授予软件安全特权,这是其他文件做不到的,它还可以检测代码是否被篡改过
□ 减少下载时间 如果一个 applet 捆绑到一个 JAR 文件中,那么浏览器就可以在一个 HTTP 事务中下载这个 applet 的类文件和相关的资源,而不是对每一个文件打开一个新连接。
□ 压缩 JAR 格式允许您压缩文件以提高存储效率。
□ 传输平台扩展 Java 扩展框架(Java Extensions Framework)提供了向 Java 核心平台添加功能的方法,这些扩展是用 JAR 文件打包的(Java 3D 和 JavaMail 就是由 Sun 开发的扩展例子)。

☆ 回归正题:
    本文涉及到两个Android Project,调用者我们命名为“AlanBuilder”,被调用者命名为“LeeWidget”。在Eclipse里分别创建这两个Project。先实现LeeWidgetActivity.java的功能,然后右键点击工程,Export成JAR file,然后选择src目录里的activity相关的java文件,然后点击finish就ok了,这样export出来的jar包里就有activity这个类了。 AlanBuilder工程就直接在buildpath中add jars里选择这个jar包,然后程序中依然调用startactivity,就能用了。
存在问题:
    当然问题没有这么简单,问题来了。导出的jar不能包含Androidmanifast.xml和其他的资源,也就是说jar里activity的资源只能在用jar的工程中手动添加,而且不能支持图片等放在res里的资源。
    也就是说,假如你jar里的activity创建了一个控件,
TextView view = (TextView)this.findViewbyId(R.id.text01);
    这样就不行了,必须动态添加,不能用res里的资源,因为res里的资源在编译时就生成了,也就是R.java,这个是固定的,R.id.text01是一个static final int的常量,那你用jar的工程里也有自己的R.java,会有和插件activity中的资源id重名的可能。
如果在导出jar的时候添加了res的目录,那使用jar的工程在导入jar后就编译不过了。同样的,manifast也不能打在jar里,必须手动添加到使用jar的工程的manifast中。比如jar是一个activity,那使用jar的工程就要在自己的manifast中添加这个activity的声明。不然startactivity会报错说manifast没有添加这个activity的。
解决方法一:
    只能将资源都放在调用jar的工程里,jar里创建一个public的类,里面存储一个静态全局int数组,这个数组里都是id,然后在工程中,调用jar的activity前,将需要的资源id都放在这个全局数组里,然后jar里的资源id都是用这个全局数组定义的id。
    具体实现方法是子在LeeWidget里新建一个MResource类,MResource这个类很重要,主要是它的作用,利用反射根据资源名字获取资源ID(其实系统也自带了根据资源名字获取资源ID的方法getResources().getIdentifier("main_activity", "layout", getPackageName());第一个参数是资源的名字,第二个参数是资源的类型,例如layout, string等,第三个是包名字) [java] view plaincopy package com.example.activitylibrary;

import android.content.Context;
/** * 根据资源的名字获取其ID值 * @author mining * */ 
public class MResource { 
    public static int getIdByName(Context context, String className, String name) { 
    String packageName = context.getPackageName(); 
    Class r = null; 
    int id = 0; 
    try { 
        r = Class.forName(packageName + ".R");

        Class[] classes = r.getClasses();  
        Class desireClass = null;  

        for (int i = 0; i < classes.length; ++i) {  
            if (classes[i].getName().split("\\$")[1].equals(className)) {  
                desireClass = classes[i];  
                break;  
            }  
        }  

        if (desireClass != null)  
            id = desireClass.getField(name).getInt(desireClass);  
    } catch (ClassNotFoundException e) {  
        e.printStackTrace();  
    } catch (IllegalArgumentException e) {  
        e.printStackTrace();  
    } catch (SecurityException e) {  
        e.printStackTrace();  
    } catch (IllegalAccessException e) {  
        e.printStackTrace();  
    } catch (NoSuchFieldException e) {  
        e.printStackTrace();  
    }  
    return id;  
    }
    而上面存在问题的语句就可以改成TextView mTextView = (TextView) findViewById(MResource.getIdByName(getApplication(), "id", "textView1")); 
    然后我们还需要刚刚那个工程的资源文件,因为我们刚刚只打包了src,资源文件不能打包,因此我们需要自己拿出来,我们需要把Library.jar加入到libs里面去,然后用到的资源文件,如果layout,string之类的拷贝到对应工程的地方去。
    当然上面的方法存在很大的弊端,就是需要将资源文件手动拷贝出来,把Library.jar加入到libs里面去,然后用到的资源文件,如果layout,string之类的拷贝到对应工程的地方去。简单说,把包跟资源分开了,我们现在想做的是能整成一个包到时我要用这个包的时候,直接就能像引用android.R.drawble.XXX.png这样。
解决方法二:
    把图片资源放入assets包中一并打入jar包,布局就只能用代码了。jar包中代码可以成功引用jar包内的assets文件。
另:JNI层不可被打包入jar包,只能同jar包一同提供给第三方并放入工程目录下的libs包中)。 
    其中关键是,在打jar包时,你选择两个文件夹  src和 assets打包就可以了,如下图。 在Android中可以将资源文件放在assets目录(可以有子目录)中和程序一起打包为jar,在其他项目引用时可以只引用jar包,不需要导入资源文件,在编译应用时会将jar包assets目录中的文件跟应用中的assets目录中的文件合并,如果jar中的文件和应用中的文件重名在编译的时候会报错“Error generating final archive: Found duplicate file for APK”提示有重名文件。

LeeWidget源代码:
package com.esri.lee;


import java.io.IOException;
import java.io.InputStream;


import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.util.Log;
//import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.Toast;


public class LeeWidgetActivity extends Activity {
public static int state = 0;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);


setContentView(getLeeWidgetView(this));
}


public View getLeeWidgetView(final Context context) {
LayoutParams layoutParam_fillParent = new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
LayoutParams layoutParam_wrapContent = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);


RelativeLayout relativeLayout = new RelativeLayout(context);
relativeLayout.setLayoutParams(layoutParam_fillParent);


LinearLayout imageLinearLayout = new LinearLayout(context);
imageLinearLayout.setLayoutParams(layoutParam_fillParent);
// imageLinearLayout.setGravity(Gravity.CENTER);
ImageView imageEsri = new ImageView(context);
imageEsri.setImageBitmap(getBitmapFromAssets(context,"esri_image.png"));
imageLinearLayout.addView(imageEsri);
relativeLayout.addView(imageLinearLayout);


LinearLayout buttonLinearLayout = new LinearLayout(context);
buttonLinearLayout.setLayoutParams(layoutParam_fillParent);
buttonLinearLayout.setOrientation(LinearLayout.VERTICAL);
Button bnLog = new Button(context);
bnLog.setText("Log");
bnLog.setTextColor(Color.BLACK);
bnLog.setLayoutParams(layoutParam_wrapContent);
bnLog.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("LeeWidget", "Just test.");
Toast.makeText(context, "Just test.",
Toast.LENGTH_SHORT).show();
}
});
buttonLinearLayout.addView(bnLog);


Button bnReadState = new Button(context);
bnReadState.setText("Read State");
bnReadState.setTextColor(Color.BLACK);
bnReadState.setLayoutParams(layoutParam_wrapContent);
bnReadState.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("LeeWidget", "State = " + state);
Toast.makeText(context, "State = " + state,
Toast.LENGTH_SHORT).show();
state++;
}
});
buttonLinearLayout.addView(bnReadState);
relativeLayout.addView(buttonLinearLayout);
return relativeLayout;
}


private Bitmap getBitmapFromAssets(Context context, String fileName) {
AssetManager assetManager = context.getAssets();
InputStream inputStream = null;
Bitmap bitmap = null;
try {
inputStream = assetManager.open(fileName);
bitmap = BitmapFactory.decodeStream(inputStream);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
Log.d("LeeWidget", "get bitmap failed");
return null;
}
return bitmap;
}


}

 

 


AlanBuilder源代码:
package com.esri.alan;


import com.esri.lee.LeeWidgetActivity;


import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;


public class BuilderMainActivity extends Activity {
ViewGroup viewGroup;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutInflater inflater = LayoutInflater.from(this);
viewGroup = (ViewGroup) inflater.inflate(R.layout.activity_main,null);
setContentView(viewGroup);
Button bn_test2 = (Button)findViewById(R.id.test2);
bn_test2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LeeWidgetActivity.state = 1000;
startActivity(new Intent(BuilderMainActivity.this, LeeWidgetActivity.class));
}
});
Button bn_test3 = (Button)findViewById(R.id.test3);
bn_test3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
LeeWidgetActivity leeWidgetActivity = new LeeWidgetActivity();
LeeWidgetActivity.state = 10000;
viewGroup.addView(leeWidgetActivity.getLeeWidgetView(BuilderMainActivity.this));
setContentView(viewGroup);
}
});
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}


}

 
原创粉丝点击