Android 程序打包及签名

mikel阅读(771)

为什么要签名???

开发Android的人这么多,完全有可能大家都把类名,包名起成了一个同样的名字,这时候如何区分?签名这时候就是起区分作用的。

由于开发商可能通过使用相同的Package Name来混淆替换已经安装的程序,签名可以保证相当名字,但是签名不同的包不被替换。

APK如果使用一个key签名,发布时另一个key签名的文件将无法安装或覆盖老的版本,这样可以防止你已安装的应用被恶意的第三方覆盖或替换掉。

这样签名其实也是开发者的身份标识。交易中抵赖等事情发生时,签名可以防止抵赖的发生。

 

签名的注意事项

  • 所有的Android应用都必须有数字签名,没有不存在数字签名的应用,包括模拟器上运行的。Android系统不会安装没有数字证书的应用。
  • 签名的数字证书不需要权威机构来认证,是开发者自己产生的数字证书,即所谓的自签名。
  • 正式发布一个Android应用时,必须使用一个合适的私钥生成的数字证书来给程序签名,不能使用ADT插件或者ANT工具生成的调试证书来发布。
  • 数字证书都是有有效期的,Android只是在应用程序安装的时候才会检查证书的有效期。如果程序已经安装在系统中,即使证书过期也不会影响程序的正常功能。

签名的方法

1:打开Eclipse->选择你要签名的项目->右击->android tools->Export signed Application package 弹出如下窗口

image

2:选中你要签名的项目,然后next,

image

因为我们是第一次签名,还没有签名证书,所以先create new keystore,以后就不用再创建了,直接选择已存在的证书。

选择证书保存的位置,填入密码,然后next,

3:

image

 

填写签证的信息,包括:别名,密码,有效期,姓名,组织,组织名称,所在城市,所在省份,国家等,然后finish。

4:最后弹出一个窗口,选择你要保存apk包的位置。

点击finish之后,稍等片刻就生成了你自己的Android安装包了。

image

详细讲解Android对自己的应用代码进行混淆加密防止反编译

mikel阅读(742)

详细讲解Android对自己的应用代码进行混淆加密防止反编译_于任道_新浪博客,于任道,1.查看项目中有没有proguard.cfg。

2.如果没有那就看看这个文件中写的什么吧,看完后将他复制到你的项目中。

optimizationpasses 5

dontusemixedcaseclassnames

dontskipnonpubliclibraryclasses

dontpreverify

-verbose

-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-keep public class * extends Android.app.Activity

-keep public class * extends Android.app.Application

-keep public class * extends android.app.Service

-keep public class * extends android.content.BroadcastReceiver

-keep public class * extends android.content.ContentProvider

-keep public class * extends android.app.backup.BackupAgentHelper

-keep public class * extends android.preference.Preference

-keep public class com.android.vending.licensing.ILicensingService

 

keepclasseswithmembernames class * {

native ;

}

 

keepclasseswithmembers class * {

public (android.content.Context, android.util.AttributeSet);

}

 

keepclasseswithmembers class * {

public (android.content.Context, android.util.AttributeSet, int);

}

 

keepclassmembers enum * {

public static **[] values();

public static ** valueOf(java.lang.String);

}

-keep class * implements android.os.Parcelable {

public static final android.os.Parcelable$Creator *;

}

3.复制到项目中后打开project.properties文件

 

4.打开后在项目中加上一句话:proguard.config=proguard.cfg

5.这样就开始按照正常的签名对自己的应用进行签名,生成后的apk经过反编译后就会和源代码有很大的不一样,不过这一步你会遇到很多问题,根本就签名不成功。例如:①如果工程引入了android-support-v4的jar类库,那么在工程打包混淆时,就会出现报错提示你:You may need to specify additional library jars (using ‘-libraryjars’)。②引用第三方包等问题

 

6.那就详细讲解5中出现的问题

如果工程引入了android-support-v4的jar类库,那你就在proguard.cfg里的后面,添加如下内容:

-libraryjars /android-support-v4.jar

-dontwarn android.support.v4.**

-keep class android.support.v4.** { *; }

-keep public class * extends android.support.v4.**

-keep public class * extends android.app.Fragment

然后你再打包看看,应该可以正常生成apk安装包了。

 

如果出现:”类1 can’t find referenced class 类2″ 字面上的意思就是类1找不到类2的引用;它会建议你:”You may need to specify additional library jars (using ‘-libraryjars’).”;

需要使用-libraryjars加上项目中使用到的第三方库就OK了。

例如:-libraryjars /android-support-v4.jar

注意:这里引用方式是当前工程的根目录(也可以配置其他目录),也就是说,你要把第三方jar放到当前目录下,否则就会警告说找不到jar文件!

 

如果出现: can’t find superclass or interface android.os.Parcelable$ClassLoaderCreator,碰到这样的情况,可以使用-dontwarn com.xx.yy.**,不对错误提出警告。

注意:使用这个方式的话,要确保自己没有用到这个库里面的类!否则就会抛ClassNotFoundException!

 

如果在工程中确实用到了该类,采用上面方式还是不行。这个时候就要再增加一项:-keep class com.xx.yy.** { *;},让当前类不混淆。

 

总结:

对于引用第三方包的情况,可以采用下面方式避免打包出错:

-libraryjars /aaa.jar

-dontwarn com.xx.yy.**

-keep class com.xx.yy.** { *;}

最后打包成功,祝君成功混淆加密!

 

7.附上完整的proguard.cfg

optimizationpasses 5

dontusemixedcaseclassnames

dontskipnonpubliclibraryclasses

dontpreverify

-verbose

-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

 

dontwarn com.slidingmenu.**

-keep class com.slidingmenu.** { *;}

 

libraryjars /libs/android-support-v4.jar

dontwarn android.support.v4.**

-keep class android.support.v4.** { *; }

-keep public class * extends android.support.v4.**

-keep public class * extends android.app.Fragment

-keep public class * extends android.app.Activity

-keep public class * extends android.app.Application

-keep public class * extends android.app.Service

-keep public class * extends android.content.BroadcastReceiver

-keep public class * extends android.content.ContentProvider

-keep public class * extends android.app.backup.BackupAgentHelper

-keep public class * extends android.preference.Preference

-keep public class com.android.vending.licensing.ILicensingService

 

keepclasseswithmembernames class * {

native ;

}

 

keepclasseswithmembers class * {

public (android.content.Context, android.util.AttributeSet);

}

 

keepclasseswithmembers class * {

public (android.content.Context, android.util.AttributeSet, int);

}

 

keepclassmembers enum * {

public static **[] values();

public static ** valueOf(java.lang.String);

}

 

-keep class * implements android.os.Parcelable {

public static final android.os.Parcelable$Creator *;

}

[转载]Android--Activity中使用Intent传值 - 承香墨影 - 博客园

mikel阅读(957)

来源: [转载]Android–Activity中使用Intent传值 – 承香墨影 – 博客园

Intent,又称为意图,是一种运行时绑定机制,它能在程序运行的过程中链接两个不同的组件(Activity、Service、 BroadcastReceiver)。通过Intent,程序可以向Android表达某种请求或意愿,Android会根据意愿的内容选择适当的组件 来请求。

在这些组件之间的通讯中,主要是由Intent协助完成的。Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描 述,Android则根据此Intent的描述,负责找到对应的组件,将Intent传递给调用的组件,并完成组件的调用。因此,Intent在这里起着 一个媒体中介的作用,专门提供组件互相调用的相关信息,实现调用者与被调用者之间的解耦。

  通过Intent请求Activity,必须在AndroidManifest.xml文件中对被请求的Activity新增标签配置,否则会导致错误。
  Intent一般包含两个主要信息,action、data。
  • action:表示这个Intent此次操作的动作。
  • data:表示这次动作涉及的数据。

 

通过一个例子来展示Activity中使用Intent导向新Activity并传递数据。此程序仅在两个页面之间相互跳转,但是每次跳转会创 建新的Activity,所以在startActivity()之后需要调用finish()销毁当前Activity,如果不销毁,多次跳转后,程序的 Activity栈中会存放多个Activity,点击设备的返回按钮,会发现会一直向后退。

主要步骤:

  1. 新建Android项目,增加新布局文件other.xml,新增Activity类otherActivity.class,用于接受Intent并展示other.xml。
  2. 在MainActivity类中,声明一个Intent类,通过Intent的构造函数指明源和目标。
  3. 获得Intent后,使用Intent.putExtra()方法对其传入数据。
  4. 调用Activity.startActivity启动这个Intent。
  5. 在otherActivity类中,使用Activity.getIntent()获得当前Activity的Intent。
  6. 获得Intent后,使用Intent.getXxxExtra()方法获得其中保存的数据。
  7. 在AndroidManifest.xml配置otherActivity节点。

示例代码

步骤2–3:

复制代码
 1 public class MainActivity extends Activity {
 2     private TextView textView;
 3     private Button btn;
 4     @Override
 5     protected void onCreate(Bundle savedInstanceState) {
 6         super.onCreate(savedInstanceState);
 7         setContentView(R.layout.activity_main);
 8         
 9         textView=(TextView)findViewById(R.id.textView1);
10         btn=(Button)findViewById(R.id.button1);
11         btn.setOnClickListener(new View.OnClickListener() {            
12             @Override
13             public void onClick(View v) {
14                 // Intent构造函数:Intent来源;Intent目的。
15                 Intent intent =new Intent(MainActivity.this,otherActivity.class);
16                 intent.putExtra("data", "当前是页面2,信息来自页面1");
17                 startActivity(intent);//启动Activity
18          finish();
18             }
19         });        
20     }
21 }
复制代码

步骤4–5:

复制代码
 1 public class otherActivity extends Activity {
 2     private Button btn;
 3     private TextView textView;
 4     @Override
 5     protected void onCreate(Bundle savedInstanceState) {
 6         // TODO Auto-generated method stub
 7         super.onCreate(savedInstanceState);
 8         setContentView(R.layout.other);
 9         
10         textView=(TextView)findViewById(R.id.textView2);
11         btn=(Button)findViewById(R.id.button2);
12         
13         //通过Activity.getIntent()获取当前页面接收到的Intent。
14         Intent intent =getIntent();
15         //getXxxExtra方法获取Intent传递过来的数据
16         String msg=intent.getStringExtra("data");
17         textView.setText(msg);
18         
19         btn.setOnClickListener(new View.OnClickListener() {            
20             @Override
21             public void onClick(View v) {                
22                 Intent intent=new Intent(otherActivity.this,MainActivity.class);
23                 startActivity(intent);
24                 finish();
25             }
26         });        
27     }
28 }
复制代码

步骤7:

复制代码
 1     <application
 2         android:allowBackup="true"
 3         android:icon="@drawable/ic_launcher"
 4         android:label="@string/app_name"
 5         android:theme="@style/AppTheme" >
 6         <activity
 7             android:name="cn.bgxt.IntentForAc.MainActivity"
 8             android:label="@string/app_name" >
 9             <intent-filter>
10                 <action android:name="android.intent.action.MAIN" />
11                 <category android:name="android.intent.category.LAUNCHER" />
12             </intent-filter>
13         </activity>
14         <activity android:name=".otherActivity"/>
15     </application>
复制代码

 

从Activity中返回数据

上面例子中只是介绍了Activity通过Intent传递数据,然而在实际应用中,不仅仅需要向Activity传递数据,而且要从Activity中返回数据,虽然返回数据和传递数据类似,但是还是有部分区别。

主要区别如下:

  1. 传递数据需要使用Activity.startActivityForResult()方法启动Activity,需要传递请求码,而不是Activity.startActivity()。
  2. 返回数据的时候,调用Activity.setResult()方法设置返回Intent以及返回码。
  3. 需要重写源Activity的onActivityResult()方法以便于接受返回的Intent,在onActivityResult()中会判断请求码和响应码。

通过一个例子说明从Activity返回数据。此程序有两个Activity,在MainActivity中输入加法运算的计算数,跳转到otherActivity中输入计算结果,并在点击返回后,把计算结果输出到MainActivity中。

示例代码

MainActivity:

复制代码
 1 public class MainActivity extends Activity {
 2 
 3     private EditText one,two,result;
 4     private Button btn;
 5     
 6     @Override
 7     protected void onCreate(Bundle savedInstanceState) {
 8         super.onCreate(savedInstanceState);
 9         setContentView(R.layout.activity_main);
10         
11         one=(EditText)findViewById(R.id.one);
12         two=(EditText)findViewById(R.id.two);
13         result=(EditText)findViewById(R.id.result);
14         btn=(Button)findViewById(R.id.btnGo);
15         btn.setOnClickListener(new View.OnClickListener() {
16             
17             @Override
18             public void onClick(View v) {
19                 // TODO Auto-generated method stub
20                 int ione=Integer.parseInt(one.getText().toString());
21                 int itwo=Integer.parseInt(two.getText().toString());
22                 
23                 Intent intent=new Intent(MainActivity.this, otherActivity.class);
24                 intent.putExtra("one", ione);
25                 intent.putExtra("two", itwo);                
26                 
27                 //启动需要监听返回值的Activity,并设置请求码:requestCode
28                 startActivityForResult(intent, 1);
29             }
30         }); 
31         
32     }
33     
34     @Override
35     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
36         super.onActivityResult(requestCode, resultCode, data);
37         //当otherActivity中返回数据的时候,会响应此方法
38         //requestCode和resultCode必须与请求startActivityForResult()和返回setResult()的时候传入的值一致。
39         if(requestCode==1&&resultCode==2)
40         {
41             int three=data.getIntExtra("three", 0);
42             result.setText(String.valueOf(three));
43         }
44     }
45 
46     @Override
47     public boolean onCreateOptionsMenu(Menu menu) {
48         // Inflate the menu; this adds items to the action bar if it is present.
49         getMenuInflater().inflate(R.menu.main, menu);
50         return true;
51     }
52 }
复制代码

otherActivity:

复制代码
 1 public class otherActivity extends Activity {
 2     TextView tvShow;
 3     EditText etResult;
 4     @Override
 5     protected void onCreate(Bundle savedInstanceState) {
 6         super.onCreate(savedInstanceState);
 7         setContentView(R.layout.other);
 8         
 9         tvShow=(TextView)findViewById(R.id.tvShow);
10         etResult=(EditText)findViewById(R.id.etResult);
11         
12         Intent intent=getIntent();
13         int a=intent.getIntExtra("one", 0);
14         int b=intent.getIntExtra("two", 0);
15         tvShow.setText(a+" + "+b+" = "+" ? ");        
16         
17         Button btnResult=(Button)findViewById(R.id.btnReturn);
18         btnResult.setOnClickListener(new View.OnClickListener() {            
19             @Override
20             public void onClick(View v) {
21                 //新声明一个Intent用于存放放回的数据
22                 Intent i=new Intent();
23                 int result=Integer.parseInt(etResult.getText().toString());
24                 i.putExtra("three", result);
25                 setResult(2, i);//设置resultCode,onActivityResult()中能获取到
26                 finish();//使用完成后结束当前Activity的生命周期
27             }
28         });                
29     }
30 }
复制代码

 

Java中的Random()函数

mikel阅读(1262)

今天在做Java练习的时候注意到了Java里面的一个随机函数——Random,刚开始只是知道这个函数具有随机取值的作用,于是上网搜索了资料一番,做了一下一些关于Random函数的总结:
 
Java中存在着两种Random函数:
一、java.lang.Math.Random;
调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0,即取值范围是[0.0,1.0)的左闭右开区间,返回值是一个伪随机选择的数,在该范围内(近似)均匀分布。
例如下面的实验代码
 Java中的Random()函数
编译通过后运行结果如下图
 Java中的Random()函数
观察会发现代码的用一个循环10次循环输出num的取值,均随机分布在[0,3)之间!在使用Math.Random()的时候需要注意的地方时该函数是返回double类型的值,所以在要赋值给其他类型的变量的时候注意需要进行塑形转换。
二、java.util.Random;
在Java的API帮助文档中,总结了一下对这个Random()函数功能的描述:
1、java.util.Random类中实现的随机算法是伪随机,也就是有规则的随机,所谓有规则的就是在给定种(seed)的区间内随机生成数字;
2、相同种子数的Random对象,相同次数生成的随机数字是完全相同的;
3、Random类中各方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的几率均等;
下面Random()的两种构造方法
1.Random():创建一个新的随机数生成器。
2.Random(long seed):使用单个 long 种子创建一个新的随机数生成器。
我们可以在构造Random对象的时候指定种子(这里指定种子有何作用,请接着往下看),如:
Random r1 = new Random(20);
或者默认当前系统时间对应的相对时间有关的数字作为种子数:
Random r1 = new Random();
需要说明的是:你在创建一个Random对象的时候可以给定任意一个合法的种子数,种子数只是随机算法的起源数字,和生成的随机数的区间没有任何关系。如下面的Java代码:
Random rand =new Random(25);
int i;
i=rand.nextInt(100);
初始化时25并没有起直接作用(注意:不是没有起作用),rand.nextInt(100);中的100是随机数的上限,产生的随机数为0-100的整数,不包括100。
下面是Java.util.Random()方法摘要
1.protected int next(int bits):生成下一个伪随机数。
2.boolean nextBoolean():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的boolean值。
3.void nextBytes(byte[] bytes):生成随机字节并将其置于用户提供的 byte 数组中。
4.double nextDouble():返回下一个伪随机数,它是取自此随机数生成器序列的、在0.0和1.0之间均匀分布的 double值。
5.float nextFloat():返回下一个伪随机数,它是取自此随机数生成器序列的、在0.0和1.0之间均匀分布float值。
6.double nextGaussian():返回下一个伪随机数,它是取自此随机数生成器序列的、呈高斯(“正态”)分布的double值,其平均值是0.0标准差是1.0。
7.int nextInt():返回下一个伪随机数,它是此随机数生成器的序列中均匀分布的 int 值。
8.int nextInt(int n):返回一个伪随机数,它是取自此随机数生成器序列的、在(包括和指定值(不包括)之间均匀分布的int值。
9.long nextLong():返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 long 值。
10.void setSeed(long seed):使用单个 long 种子设置此随机数生成器的种子。
 
方法摘要也就这些,下面给几个例子:
1.生成[0,1.0)区间的小数:double d1 = r.nextDouble();
2.生成[0,5.0)区间的小数:double d2 = r.nextDouble() * 5;
3.生成[1,2.5)区间的小数:double d3 = r.nextDouble() * 1.5 + 1;
4.生成-231到231-1之间的整数:int n = r.nextInt();
5.生成[0,10)区间的整数:
int n2 = r.nextInt(10);//方法一
n2 = Math.abs(r.nextInt() % 10);//方法二
前面曾讲到过构造Random对象的时候指定种子的问题,到底指定种子有什么作用呢,这里直接用代码例子来做说明:
 Java中的Random()函数
在定义的时候分别指定了相同的种子之后,在分别用r1和r2去[0,30)的随机数,结果编译执行后悔发现结果都是呈现AABB型的,说明r1和r2取的随机数是一模一样的(下图为实验截图)。
 Java中的Random()函数
如果我改动代码,改成下面这样:
 Java中的Random()函数
再编译输出后,就再也不会得到AABB型的结果,根据代码的区别,就可以知道指定种子数,和不指定种子数的区别在于哪里了。
 Java中的Random()函数
 
最后再来简单对比一下这两个随机函数到底的特点:
1.java.Math.Random()实际是在内部调用java.util.Random()的,它有一个致命的弱点,它和系统时间有关,也就是说相隔时间很短的两个random比如:
double a = Math.random();
double b = Math.random();
即有可能会得到两个一模一样的double。
2.java.util.Random()在调用的时候可以实现和java.Math.Random()一样的功能,而且他具有很多的调用方法,相对来说比较灵活。所以从总体来看,使用java.util.Random()会相对来说比较灵活一些。

Android笔记:invalidate()和postInvalidate() 的区别及使用

mikel阅读(728)

Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。

invalidate() 是用来刷新View的,必须是在UI线程中进行工作。比如在修改某个view的显示时,调用invalidate()才能看到重新绘制的界面。 invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉。 一个Android 程序默认情况下也只有一个进程,但一个进程下却可以有许多个线程。

在这么多线程当中,把主要是负责控制UI界面的显示、更新和控件交互的线程称为UI线程,由于onCreate()方法是由UI线程执行的,所以也可以把UI线程理解为主线程。其余的线程可以理解为工作者线程。

invalidate()得在UI线程中被调动,在工作者线程中可以通过Handler来通知UI线程进行界面更新。

而postInvalidate()在工作者线程中被调用

 

 

利用invalidate()刷新界面

实例化一个Handler对象,并重写handleMessage方法调用invalidate()实现界面刷新;而在线程中通过sendMessage发送界面更新消息。
// 在onCreate()中开启线程

new Thread(new GameThread()).start();、

// 实例化一个handler

Handler myHandler = new Handler() {
// 接收到消息后处理
public void handleMessage(Message msg) {
switch (msg.what) {
case Activity01.REFRESH:
mGameView.invalidate(); // 刷新界面
break;
}

super.handleMessage(msg);
}
};

class GameThread implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
Message message = new Message();
message.what = Activity01.REFRESH;
// 发送消息
Activity01.this.myHandler.sendMessage(message);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}

使用postInvalidate()刷新界面

使用postInvalidate则比较简单,不需要handler,直接在线程中调用postInvalidate即可。

class GameThread implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}

// 使用postInvalidate可以直接在线程中更新界面
mGameView.postInvalidate();
}
}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

百度地图错误 java.lang.NoClassDefFoundError: com/baidu/platform/comjni/engine/AppEngine

mikel阅读(861)

在代码中使用了百度地图,同时也使用了混淆代码。但是在安装了app后,发现在使用百度地图的时候有错误:

java.lang.NoClassDefFoundError: com/baidu/platform/comjni/engine/AppEngine

在google之后:

http://bbs.lbsyun.baidu.com/viewthread.php?tid=543

在工程目录下的:proguard-project.txt 中添加如下文字:

-keep class com.baidu.**{*;}
-keep class vi.com.gdi.bgl.**{*;}

如此即可

版权声明:本文为博主原创文章,未经博主允许不得转载。

ImageView的属性android:scaleType,即ImageView.setScaleType(ImageView.ScaleType)

mikel阅读(756)

1 imageView.setScaleType(ImageView.ScaleType.FIT_XY );

 

复制代码
 1  这里我们重点理解ImageView的属性android:scaleType,即ImageView.setScaleType(ImageView.ScaleType)。android:scaleType是控制图片如何resized/moved来匹对ImageView的size。ImageView.ScaleType / android:scaleType值的意义区别:
 2  
 3 CENTER /center  按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示
 4  
 5 CENTER_CROP / centerCrop  按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽)
 6  
 7 CENTER_INSIDE / centerInside  将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽
 8  
 9 FIT_CENTER / fitCenter  把图片按比例扩大/缩小到View的宽度,居中显示
10  
11 FIT_END / fitEnd   把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置
12  
13 FIT_START / fitStart  把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置
14  
15 FIT_XY / fitXY  把图片不按比例扩大/缩小到View的大小显示
16  
17 MATRIX / matrix 用矩阵来绘制
复制代码

一开始我不明白MATRIX矩阵,网上搜索后发现原来MATRIX矩阵可以动态缩小放大图片来显示,这里不展开深入的了解,只是贴出相关语句,缩小图片:

复制代码
 1 //获得Bitmap的高和宽 
 2 int bmpWidth=bmp.getWidth(); 
 3 int bmpHeight=bmp.getHeight(); 
 4  
 5 //设置缩小比例 
 6 double scale=0.8; 
 7 //计算出这次要缩小的比例 
 8 scaleWidth=(float)(scaleWidth*scale); 
 9 scaleHeight=(float)(scaleHeight*scale); 
10  
11 //产生resize后的Bitmap对象 
12 Matrix matrix=new Matrix(); 
13 matrix.postScale(scaleWidth, scaleHeight); 
14 Bitmap resizeBmp=Bitmap.createBitmap(bmp, 0, 0, bmpWidth, bmpHeight, matrix, true);
复制代码

 

复制代码
1 <ImageView 
2 android:id="@+id/image" 
3     android:layout_width="fill_parent"  
4     android:layout_height="fill_parent" 
5     android:scaleType="center" 
6     android:src="@drawable/candle" 
7 />
复制代码

Android imageView图片按比例缩放

mikel阅读(856)

点击打开链接 原作者

Android:scaleType可控制图片的缩放方式,示例代码如下:

  1. <ImageView Android:id=“@+id/img”
  2.     android:src=“@drawable/logo”
  3.     android:scaleType=“centerInside”
  4.     android:layout_width=“60dip”
  5.     android:layout_height=“60dip”
  6.     android:layout_centerVertical=“true”/>

 

说明:centerInside表示按比例缩放图片,使得图片长 (宽)的小于等于视图的相应维度。
  注意:控制的图片为资源而不是背景,即 android:src=”@drawable/logo”,而非android:background=”@drawable/logo”,我就笨笨地 犯了这个低级错误,导致错怪人家scaleType不起作用。程序中动态加载图片也类似,如:应该 imgView.setImageResource(R.drawable.*); 而非imgView.setBackgroundResource(R.drawable.*);
附:更详细的scaleType说明:

android:scaleType是控制图片如何resized/moved来匹对ImageView的size。

ImageView.ScaleType / android:scaleType值的意义区别:

CENTER /center  按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示

CENTER_CROP / centerCrop  按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽)

CENTER_INSIDE / centerInside  将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽

FIT_CENTER / fitCenter  把图片按比例扩大/缩小到View的宽度,居中显示

FIT_END / fitEnd   把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置

FIT_START / fitStart  把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置

FIT_XY / fitXY  把图片不按比例扩大/缩小到View的大小显示

MATRIX / matrix 用矩阵来绘制,动态缩小放大图片来显示。

** 要注意一点,Drawable文件夹里面的图片命名是不能大写的。

Android布局查看工具HierarchyView

mikel阅读(969)

Android布局查看工具HierarchyView
发表于485 天前 ⁄ 编程开发 ⁄ 暂无评论
HierarchyView.bat 是Android SDK中自带了一个查看UI布局层级结构的工具。在模拟器运行的情况下,使用该工具可以将当前的Activity中的UI组件们以对象树的形式展现出来, 每一个组件所包含的属性也能窥探得到。在对象树上的任意节点可以看到该节点及以下节点的显示效果。

使用HierarchyView能深入全面的理解xml布局文件,更可以通过它来学习别人优秀的布局技巧。下面是一些基本使用步骤:

(1)启动模拟器。

(2)到Androidtools目录下,双击可以启动hierarchyviewerbat文件,打开一个图形界面。

(3)点击 load View hierarchy按钮,就可以捕获模拟器当前activity的画面布局信息。
(4)hierarchy通过树形结构展示布局形式。双击树节点可以展示单独的UI部分。

(5)当模拟器activity画面改变后,点击““refresh””可以加载新的页面布局信息。

通过Hierarchy Viewer你就可以学习别人优秀的布局方式,
同时也更能更深入更全面更整体的把握xml布局文件。
体会UI和代码(java code)以及资源(res)的相互分离。

界面如图:

Android——DisplayMetrics之我见

mikel阅读(859)

写这篇文章主要是因为这个问题困扰我很久,今天终于搞明白了,分享出来供以后查阅。

一、起因

为了适应多屏幕分辨率,可以在res目录下建立不同的layout文件,例如想适应C8500(320*240)和 Milestone(854*480),可以在res目录下建立layout-320*240和layout-854*480两个目录,然后在其中定义不 同的布局文件就可以了;但在实际中并没有凑效;这是为什么呢;

在真机下调试才发现有问题,Android有个类DisplayMetrics可以得到分辨率等信息,方法如下:

DisplayMetrics metrics;getWindowManager().getDefaultDisplay().getMetrics(metrics);

metrics.widthPixels           屏幕宽

metrics.heightPixels          屏幕高

metrics.density                  屏幕密度

其它用不到的属性就不写了,调试中发现C8500得到的是427*320,而而Milestone得到是569*320;这是为什么呢?难道是Android API有问题?

二、探索

实际上是自己对Android多屏幕分辨率理解不深刻,那么问题出在哪儿呢?这里需要用到一个公式pixels = dps * (density / 160),在SDK中有提到,需要说明一点公式中的density与metrics.density不是一个东西,它们的关系 是:metrics.density = density / 160,density的值有120、160、240、320(这在SDK中也有说明);好了直接套用公式就OK了C8500实际分辨率为 320*240,密度(也就是metrics.density的值)为0.75,用公式算出来正好是427*320;Milestone实际分辨率是 854*480,密度是1.5,算出来是569*320(有四舍五入的);

好吧,按照以上的结论直接在res目录下建立layout-427*320和layout-569*320;分别编写不同的布局文件,OK!问题解决,终于可以适应两个手机屏幕了。

三、没有结束……

真的就这么搞定了吗?似乎没有,把AndroidManifest.xml中android:minSdkVersion=”3″(一直都是3), 中3改为4,问题又来了,界面又乱了,在两个手机都乱了;怎么回事呢?再调试,我那个晕,C8500手机屏幕分辨率又变了,变回320*240,套用上面 的公式反而又错了,程序又找不到布局文件了,界面自然就乱了,这是WHY   WHY   WHY????

别着急,再来看看问题出在哪儿。查找SDK,加上自己对Android多分辨率的支持的理解,真正的原因应该是当 android:minSdkVersion=”3″时也就是此时支持android1.5,在 Android 1.5以及更早的版本中,只支持3.2″ 屏幕上的HVGA (320×480)分辨率,开发人员也不需要考虑界面的适配性问题。从Android 1.6之后,平台支持多种尺寸和分辨率的设备,这也就意味着开发人员在设计时要考虑到屏幕的多样性。

由此可见,在android:minSdkVersion=”3″时,还没有多分辨率的概念,因而此时,DisplayMetrics得到的宽和高 是与密度相关的,也就是说此时得到的宽和高都是以dp或dip为单位的,要转换成px才是我们通常据说的分辨率。自android1.6及以 后,DisplayMetrics得到的宽和高都是以px为单位的,不需要转换。

总结一下:android的兼容性意味着应用程序api的降级。api的降级意味着在高端机(版本高配置高)上的显示效果配不上。

转:http://cxxowl.sinaapp.com/?p=12