Makefile 与 Shell 的问题
大概只要知道 Makefile 的人,都知道 Makefile 可以调用 Shell 脚本。但是在实际使用时,并不那么简单,一些模棱两可的地方可能会让你抓狂。你若不信,可以先看几个例子,想象一下这些这些例子会打印什么内容,记下你想象的结果,然后在计算机上运行这些例子,对照看一下。
示例一:
if [ "$(BUILD)" = "debug" ]; then echo "build debug"; else echo "build release"; fi
all:
echo "done"
示例二:
all:
@CC=arm-linux-gcc
@echo $(CC)
示例三:
CC=arm-linux-gcc
all:
@echo $(CC)
示例四:
SUBDIR=src example
all:
@for subdir in $(SUBDIR); \
do\
echo "building " $(subdir); \
done
说明:
1. Shell 脚本在 target 里才有效,其它地方都被忽略掉了。所以示例一中, ”build debug” 之类的字符串根本打印不出来。示例一的正确写法是:
示例一:
all:
if [ "$(BUILD)" = "debug" ]; then echo "build debug"; else echo "build release"; fi
echo "done"
2. make 把每一行 Shell 脚本当作一个独立的单元,它们在单独的进程中运行。示例二中,两行 Shell 脚本在两个莫不相干的进程里运行,第一个进程把 CC 设置为 arm-linux-gcc ,第二个进程是不知道的,所以打印的结果自然不是 arm-linux-gcc 了。示例二的正确写法是:
示例二:
all:
@CC=arm-linux-gcc; echo $(CC)
或者:
all:
@CC=arm-linux-gcc; \
echo $(CC)
3. make 在调用 Shell 之前先进行预处理,即展开所有 Makefile 的变量和函数。这些变量和函数都以 $ 开头。示例三中, Shell 拿的脚本实际上是 echo arm-linux-gcc ,所以打印结果正确。
4. make 预处理时,所有以 $ 开头的,它都不会放过。要想引用 Shell 自己的变量,应该以 $$ 开头。另外要注意, Shell 自己的变量是不需要括号的。示例四的正确写法是:
示例四:
SUBDIR=src example
all:
@for subdir in $(SUBDIR); \
do\
echo "building " $$subdir; \
done
获取Launcher 启动列表
即 列出所有Launcher程序 通过PackageManager 来获取
[代码 步骤]
1. 定义内部类 LauncherItem 用于定义Application相关属性 比如:图标 名称 以及 ComponentName
public class LauncherItem {
Drawable icon;
String name;
ComponentName component;
LauncherItem(Drawable d, String s,ComponentName cn){
icon = d;
name = s;
component = cn;
}
};
2. 定义List<LauncherItem> lvalue 用于存放查询结果
public void addLauncher(){
lvalue = new ArrayList<LauncherItem>();
pkgMgt = this.getPackageManager();
//to query all launcher & load into List<>
Intent it = new Intent(Intent.ACTION_MAIN);
it.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> ra =pkgMgt.queryIntentActivities(it,0);
for(int i=0;i<ra.size();i++){
ActivityInfo ai = ra.get(i).activityInfo;
//String ainfo = ai.toString();
Drawable icon = ai.loadIcon(pkgMgt);
String label = ai.loadLabel(pkgMgt).toString();
ComponentName c = new ComponentName(ai.applicationInfo.packageName,ai.name);
LauncherItem item = new LauncherItem(icon,label,c);
lvalue.add(item);
}
}
3. 定义LauncherAdapter 并指定各个item显示样式
public class LauncherAdapter extends BaseAdapter {
Activity activity;
public LauncherAdapter(Activity a){
activity = a;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return lvalue.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
return composeItem(position);
}
public View composeItem(int position){
LinearLayout layout = new LinearLayout(activity);
layout.setOrientation(LinearLayout.HORIZONTAL);
ImageView iv = new ImageView(activity);
iv.setImageDrawable(lvalue.get(position).icon);
layout.addView(iv);
TextView tv = new TextView(activity);
tv.setText(lvalue.get(position).name);
tv.setPadding(10, 5, 0, 0);
layout.addView(tv);
return layout;
}
}
4. 启动某个item 当单击时
adapter = new LauncherAdapter(this);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
Intent intent =new Intent(Intent.ACTION_VIEW);
intent.setComponent(lvalue.get(arg2).component);
startActivity(intent);
}
});
5. emulator 结果结果
- 列出所有application
- 单击Alarm Clock 的情形:
有问题请跟帖 否则 请顶贴 谢谢!
我想查看下PackageManager 的queryIntentActivities方法是怎样实现的,但发现PackageManager 是抽象类,queryIntentActivities是抽象方法,获得PackageManager实例的getPackageManager方法,是ContextWrapper的方法,但在ContextWrapper中没有发现有setPackageManager或createPackageManager之类的方法,那我怎样才能找到PackageManager 的实现类呢
PackageManager pm;
Intent intent = pm.getLaunchIntentForPackage(packageName);
服务(Service)是运行在后台的一段代码。它可以运行在它自己的进程,也可以运行在其他应用程序的上下文(context)里面。其他的组件可以绑定到一个服务上面,通过远程过程调用(RPC)来调用这个方法。例如:媒体播放器的服务,当用户退出媒体选择用户界面,仍然希望音乐可以继续播放,这时就是由服务(Service)来保证当用户界面关闭时音乐继续播放的。
使用服务的方法
- 第一种是通过调用Context.startServece()启动,调用Context.stoptService()结束,startService()可以传递参数给Service。
- 第二种方式是通过调用Context.bindService()启动,调用Context.unbindService()结束,还可以通过ServiceConnection 访问Service。二者可以混合使用,可以先startServece()再unbindService()。
Service的生命周期
- startService()后,即使调用startService()的进程结束了,Service 仍然还存在,直到有进程调用stoptService(),或者Service 自己自杀(stopSelf())。
- bindService()后,Service 就和调用bindService()的进程同生共死,也就是说当调用bindService()的进程死了,那么它bind 的Service 也要跟着被结束,当然期间也可以调用unbindService()让Service 结束。
- 两种方式混合使用时,比如说你startService()了,我bindService()了,那么只有你stoptService()了而且我也unbindService()了,这个Service 才会被结束。
进程生命周期
- Android 系统将会尝试保留那些启动了的或者时绑定了的服务进程。
- 如果该服务正在进程的onCreate(),onStart()或者onDestroy()这些方法中执行时,那么主进程将会成为一个前台进程,以确保此代码不会被停止。
- 如果服务已经开始,那么它的主进程会就重要性而言低于所有可见的进程但高于不可见的进程,由于只有少数几个进程是用户可见的,所以只要不是内存特别低,该服务不会停止。
- 如果有多个客户端绑定了同一个服务,只要客户端中的一个对于用户是可见的,即认为该服务可见。
实现一个当用户界面关闭时音乐继续播放的程序,代码如下:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="peng.test"
android:versionCode="1"
android:versionName="1.0">
...
<application android:icon="@drawable/icon" android:label="@string/app_name">
<service android:name=".Music" >
<intent-filter>
<action android:name="peng.test.START_AUDIO_SERVICE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</service>
</application>
</manifest> src/peng/test/Music.java 服务类
package peng.test;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.util.Log;
public class Music extends Service {
private MediaPlayer player;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
player = MediaPlayer.create(this, R.raw.aimo);
Log.d("DEBUGTAG", "Music Start");
player.start();
}
public void onDestroy() {
super.onDestroy();
Log.d("DEBUGTAG", "Music Stop");
player.stop();
}
}src/peng/test/MyMusicPlayer.java Activity 类代码
package peng.test;
import android.app.Activity;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MyMusicPlayer extends Activity
implements OnClickListener {
private Button playMusic;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
playMusic = (Button)findViewById(R.id.btn_play);
playMusic.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.btn_play) {
startService(new Intent("peng.test.START_AUDIO_SERVICE"));
}
}
}