android:launchMode="singleTask"//所有activity只能运行一个实例.singleInstance每个activity只有唯一一个运行实例。
android:alwaysRetainTaskState="true"//总是返回关闭之前的状态
android:screenOrientation="portrait"//强制屏幕总是垂直方向,水平landscape
android:configChanges="orientation|keyboardHidden"//当所指定属性(Configuration Changes)发生改变时,通知程序调用 onConfigurationChanged()函数。参考http://www.cnblogs.com/adamzuocy/archive/2009/10/15/1583670.html
2.2.4
activity在onDestroy之前,会调用onSaveInstanceState()。
activity在重新创建之前,会调用onRestroeInstanceState()。
通过这两个方法来保存状态信息和获取状态信息。
2.3.3
startActivityForResult()启动activity并标记requestCode
onActivityResult()检查返回结果的状态。解析返回数据
源码。
使用Speech必须使用英文支持包。否则会报错。
package com.david;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.provider.SyncStateContract.Constants;
import android.speech.RecognizerIntent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class RecognizerIntentExample extends Activity {
private TextView textView;
private Button btn;
private static final int RECOGNIZER_EXAMPLE = 1001;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.text_result);
btn = (Button) findViewById(R.id.trigger);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,"Say a word or phrase\nand it will show as text");
startActivityForResult(intent, RECOGNIZER_EXAMPLE);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RECOGNIZER_EXAMPLE) {
ArrayList<String> result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
textView.setText(result.toString());
}
super.onActivityResult(requestCode, resultCode, data);
}
}
第三章
3.1.1 启动辅助线程
package com.david;
import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class PressAndPlay extends Activity {
private Button startButton;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startButton = (Button) findViewById(R.id.trigger);
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Thread initBkgdThread = new Thread(new Runnable() {
@Override
public void run() {
play_music();
}
});
initBkgdThread.start();
}
});
}
int[] notes = {R.raw.c5,R.raw.b4,R.raw.a4,R.raw.g4};
int NOTE_DURATION = 400;//MILLISEC
MediaPlayer m_mediaPlayer;
private void play_music() {
for (int ii = 0; ii < 12; ii++) {
if (!paused) {
if (m_mediaPlayer != null) {
m_mediaPlayer.release();
}
m_mediaPlayer = MediaPlayer.create(this, notes[ii%4]);
m_mediaPlayer.start();
try {
Thread.sleep(NOTE_DURATION);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
boolean paused = false;
@Override
protected void onResume() {
paused = false;
super.onResume();
}
@Override
protected void onPause() {
paused = true;
super.onPause();
}
}
a4.rtttl:<a4:d=4,o=5,b=250:a4;
b4.rtttl:mfun86:d=4,o=6,b=125:8g5,2c7,1c,b7,8f.,d
c5.rtttl:application:d=4,o=6,b=125:8g5,2c7,1c,b7,8f.,d
3.1.4 取消线程
if(myThread != null)
{
Thread dummy = myThread;
myThread = null;
dummy.interrupt();
}
daemon thread 守护线程。如果应用程序的主线程被杀死,所有守护线程也会被同时杀死。
myThread.setDaemon(true);
myThread.start();
定义:守护线程--也称“服务线程”,在没有用户线程可服务时会自动离开。
优先级:守护线程的优先级比较低,用于为系统中的其它对象和线程提供服务。
设置:通过setDaemon(true)来设置线程为“守护线程”;将一个用户线程设置为守护线程的方式是在 线程对象创建 之前 用线程对象的setDaemon方法。
example: 垃圾回收线程就是一个经典的守护线程,当我们的程序中不再有任何运行的
Thread,程序就不会再产生垃圾,垃圾回收器也就无事可做,所以当垃圾回收线程是
JVM上仅剩的线程时,垃圾回收线程会自动离开。它始终在低级别的状态中运行,用于
实时监控和管理系统中的可回收资源。
生命周期:守护进程(Daemon)是运行在后台的一种特殊进程。它独立于控制终端并且 周期性地执行某种任务或等待处理某些发生的事件。也就是说守护线程不依赖于终端,但是依赖于系统,与系统“同生共死”。那Java的守护线程是什么样子的呢。当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则JVM不会退出。
3.2.1
package com.david;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class BackGroundTimer extends Activity {
private TextView mTimeLabelTextView ;
private TextView mBtnText ;
private Button mButton;
private Handler handler = new Handler();
private long startTime = 0L;
private int buttonPress = 0;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTimeLabelTextView = (TextView) findViewById(R.id.text);
mBtnText = (TextView) findViewById(R.id.mBtnLabel);
mButton = (Button) findViewById(R.id.button1);
if (startTime == 0L) {
startTime = SystemClock.uptimeMillis();
handler.removeCallbacks(mUpdateTimeTask);
handler.postDelayed(mUpdateTimeTask, 100);
}
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mBtnText.setText("Pressed" + ++buttonPress + "times");
}
});
}
private Runnable mUpdateTimeTask = new Runnable() {
@Override
public void run() {
final long start = startTime;
long millis = SystemClock.uptimeMillis() - start;//持续时间
int seconds = (int) (millis / 1000);
int minutes = seconds / 60 ;
seconds = seconds % 60 ;
mTimeLabelTextView.setText(" "+minutes + ":" + String.format("%02d", seconds));
handler.postDelayed(this, 200);
}
};
@Override
protected void onResume() {
handler.postDelayed(mUpdateTimeTask, 100);
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
handler.removeCallbacks(mUpdateTimeTask);
}
}
3.2.2 倒数计时器
CountDownTimer
//倒数计时器
new CountDownTimer(30000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
mTimeLabelTextView.setText("seconds remaining:" + millisUntilFinished / 1000);
}
@Override
public void onFinish() {
mTimeLabelTextView.setText("done!");
}
}.start();
3.2.3 处理耗时的初始化 loading
public class BackGroundTimer extends Activity implements Runnable {
private static final int NUM_SAMPS = 1000;
private static double[][] correlation;
private TextView mTimeLabelTextView ;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loading);
Thread thread = new Thread(this);
thread.start();
}
private Handler handler = new Handler()
{
public void handleMessage(Message msg)
{
setContentView(R.layout.main);
}
};
@Override
public void run() {
initializeArrays();
handler.sendEmptyMessage(0);//发送空消息
}
//较长时间的操作
private void initializeArrays() {
if (correlation!=null) return;
correlation = new double[NUM_SAMPS][NUM_SAMPS];
for (int k = 0; k < NUM_SAMPS; k++) {
for (int m = 0; m < NUM_SAMPS; m++) {
correlation[k][m] = Math.cos(2*Math.PI * (k+m)/1000);
}
}
}
}
3.3 服务
activity:
public class BackGroundTimer extends Activity {
private static final int NUM_SAMPS = 1000;
private static double[][] correlation;
private TextView mTimeLabelTextView ;
private Button startBtn;
private Button stopBtn;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startBtn = (Button) findViewById(R.id.startBtn);
stopBtn = (Button) findViewById(R.id.stopBtn);
startBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startService(new Intent(BackGroundTimer.this,SimpleService.class));
}
});
stopBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopService(new Intent(BackGroundTimer.this,SimpleService.class));
}
});
}
simpleService:
public class SimpleService extends Service {
boolean paused = false;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service created", Toast.LENGTH_LONG).show();
paused = false;
Thread initBkgdThread = new Thread(new Runnable() {
@Override
public void run() {
play_music();
}
});
initBkgdThread.start();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
paused = true;
}
int[] notes = { R.raw.c5, R.raw.b4, R.raw.a4, R.raw.g4 };
int NOTE_DURATION = 400;// MILLISEC
MediaPlayer m_mediaPlayer;
private void play_music() {
for (int ii = 0; ii < 12; ii++) {
if (!paused) {
if (m_mediaPlayer != null) {
m_mediaPlayer.release();
}
m_mediaPlayer = MediaPlayer.create(this, notes[ii % 4]);
m_mediaPlayer.start();
try {
Thread.sleep(NOTE_DURATION);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
3.4 broadcast receiver
销毁activity,receiver也要释放掉。
3.5 应用widget
默认android会强制设定最短更新时间为每30分钟更新一次。
3.6 alert
//居中显示
tst.setGravity(Gravity.CENTER,tst.getXOffset() /2, tst.getYOffset() / 2);
//使用图片
Toast tst = Toast.makeText(this, "text", Toast.LENGTH_LONG);
ImageView view = new ImageView(this);
view.setImageResource(R.drawable.icon);
tst.setView(view);
tst.show();
使用alert
AlertDialog dialog = new AlertDialog.Builder(this).create();
//左边的按钮
dialog.setButton(Dialog.BUTTON_POSITIVE, "Try this level again",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mScore = 0;
}
});
//右边的按钮
dialog.setButton(Dialog.BUTTON_NEGATIVE, "advance to next level",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mLevel++;
}
});
//中间的按钮
dialog.setButton(Dialog.BUTTON_NEUTRAL, "BACK TO THE MAIN MENU",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mLevel = 0;
finish();
}
});
dialog.show();
3.6.3 显示通知
public class BackGroundTimer extends Activity {
private Button startBtn;
private Button stopBtn;
private NotificationManager nManager;
private static final int NOTIFY_ID = 100;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startBtn = (Button) findViewById(R.id.startBtn);
stopBtn = (Button) findViewById(R.id.stopBtn);
String ns = Context.NOTIFICATION_SERVICE;
nManager = (NotificationManager) getSystemService(ns);//获取系统服务
final Notification msg = new Notification(R.drawable.icon,"New Event of importance",
System.currentTimeMillis());
startBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = getApplicationContext();
CharSequence contentTitle = "ShowNotification Exam";
CharSequence contentText = "Browse android cookbook site";
Intent msgIntent = new Intent(Intent.ACTION_VIEW,Uri.parse("http://www.person.com"));
PendingIntent pIntent = PendingIntent.getActivity(BackGroundTimer.this, 0, msgIntent, Intent.FLAG_ACTIVITY_NEW_TASK);
msg.defaults |= Notification.DEFAULT_SOUND;
msg.flags |= Notification.FLAG_AUTO_CANCEL;
msg.setLatestEventInfo(context, contentTitle, contentText, pIntent);
nManager.notify(NOTIFY_ID,msg);
}
});
stopBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
nManager.cancel(NOTIFY_ID);
}
});
}
4.2.5 独立线程更新UI
public class BackGroundTimer extends Activity {
private Button actionBtn;
private TextView av;
private int text_string = R.string.action;
private int backGround_color = Color.DKGRAY;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
av = (TextView) findViewById(R.id.textView1);
actionBtn = (Button) findViewById(R.id.action);
actionBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
do_work();
}
});
}
final Handler mHandler = new Handler();
final Runnable mUpdateRunnable = new Runnable() {
@Override
public void run() {
av.setText(text_string);
av.setBackgroundColor(backGround_color);
}
};
private void do_work() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
mHandler.post(mUpdateRunnable);
computation(1);
text_string = R.string.first;
backGround_color = Color.BLUE;
mHandler.post(mUpdateRunnable);
computation(2);
text_string = R.string.second;
backGround_color = Color.GREEN;
mHandler.post(mUpdateRunnable);
}
});
thread.start();
}
final static int SIZE = 1000;
double tmp;
private void computation(int i) {
for (int k = 0; k < SIZE; k++) {
for (int m = 0; m < SIZE; m++) {
tmp = i*Math.log(k+1) / Math.log1p(m+1);
}
}
}
}
5.1.2 创建菜单 上下文菜单 子菜单
public class BackGroundTimer extends Activity {
private TextView av;
private final int GROUP_DEFAULT = 0;
private final int GROUP_DEL = 1;
private final int MENU_ADD = 1;
private final int MENU_SEND = 2;
private final int MENU_DEL = 3;
private static int itemNum = 0;
private final int ID_TEXT1 = 1,ID_TEXT2 = 2, ID_TEXT3 = 3,ID_DEFAULT = 0;
private String[] choices = { "Press Me", "Try Again", "Change Me" };
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
av = (TextView) findViewById(R.id.textView1);
registerForContextMenu((View) findViewById(R.id.focus_text));//注册为上下文菜单
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(GROUP_DEFAULT, MENU_ADD, 0, "Add");
menu.add(GROUP_DEFAULT, MENU_SEND, 0, "Send");
menu.add(GROUP_DEL, MENU_DEL, 0, "Del");
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (itemNum > 0) {
menu.setGroupVisible(GROUP_DEL, true);
} else {
menu.setGroupVisible(GROUP_DEL, false);
}
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ADD:
create_note();
return true;
case MENU_SEND:
send_note();
return true;
case MENU_DEL:
delete_note();
return true;
}
return super.onOptionsItemSelected(item);
}
private void delete_note() {
itemNum--;
}
private void send_note() {
Toast.makeText(this, "Item:"+itemNum, Toast.LENGTH_LONG).show();
}
private void create_note() {
itemNum++;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if (v.getId() == R.id.focus_text) {
SubMenu textMenu = menu.addSubMenu("Change Text");
textMenu.add(0,ID_TEXT1,0,choices[0]);
textMenu.add(0,ID_TEXT2,0,choices[1]);
textMenu.add(0,ID_TEXT3,0,choices[2]);
menu.add(0,ID_DEFAULT,0,"Original Text");
}
}
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case ID_DEFAULT:
av.setText(R.string.hello);
return true;
case ID_TEXT1:
case ID_TEXT2:
case ID_TEXT3:
av.setText(choices[item.getItemId()-1]);
return true;
}
return super.onContextItemSelected(item);
}
}
6.1 图像
备注:shift+ctrl+o 删除无用的import
ImageManipulation.java
package com.cookbook.image_manip;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.widget.ImageView;
public class ImageManipulation extends Activity {
private ImageView iv;
private final static String CAMERA_PIC_DIR = "/DCIM/Camera";//相片存放目录
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
iv = (ImageView) findViewById(R.id.myImage);
String imageDir = Environment.getExternalStorageDirectory().getAbsolutePath() + CAMERA_PIC_DIR;//sd卡目录
Intent i = new Intent(this,ListFile.class);
i.putExtra("directory", imageDir);
startActivityForResult(i, 0);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0 && resultCode == RESULT_OK) {
String tmp = data.getExtras().getString("clickedFile");
Bitmap imageToChange = BitmapFactory.decodeFile(tmp);
processImage(imageToChange);
}
}
/**
* 图片处理 切割成四块
* @param imageToChange
*/
private void processImage(Bitmap imageToChange) {
Bitmap bm = Bitmap.createScaledBitmap(imageToChange, 480, 320, false);//创建二次采样
int width = bm.getWidth();
int height = bm.getHeight();
int x = width>>1;
int y = height>>1;
int[] pixels1 = new int[(width*height)];
int[] pixels2 = new int[(width*height)];
int[] pixels3 = new int[(width*height)];
int[] pixels4 = new int[(width*height)];
bm.getPixels(pixels1, 0, width, 0, 0, width>>1, height>>1);
bm.getPixels(pixels2, 0, width, x, 0, width>>1, height>>1);
bm.getPixels(pixels3, 0, width, 0, y, width>>1, height>>1);
bm.getPixels(pixels4, 0, width, x, y, width>>1, height>>1);
if (bm.isMutable()) {
bm.setPixels(pixels2, 0, width, 0, 0, width>>1, height>>1);
bm.setPixels(pixels4, 0, width, x, 0, width>>1, height>>1);
bm.setPixels(pixels1, 0, width, 0, y, width>>1, height>>1);
bm.setPixels(pixels3, 0, width, x, y, width>>1, height>>1);
}
iv.setImageBitmap(bm);
}
}
ListFile.java
package com.cookbook.image_manip;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class ListFile extends ListActivity {
private List<String> directorEntries = new ArrayList<String>();
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
File clickedFile = new File(this.directorEntries.get(position));//获取点击的文件
Intent intent = getIntent();
intent.putExtra("clickedFile", clickedFile.toString());//传入选择的文件
setResult(RESULT_OK,intent);
finish();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = getIntent();
File directory = new File(i.getStringExtra("directory"));//获取主页面传来的目录
if (directory.isDirectory()) {
File[] files = directory.listFiles();
//按照修改日期排序
Arrays.sort(files,new Comparator<File>() {
@Override
public int compare(File f1, File f2) {
return -Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
}
});
//填充
directorEntries.clear();
for(File file : files)
{
this.directorEntries.add(file.getPath());
}
ArrayAdapter<String> directoryList = new ArrayAdapter<String>(this, R.layout.file_row,this.directorEntries);
this.setListAdapter(directoryList);
}
}
}
7.1 照相机
package com.david;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.provider.MediaStore.Images;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;
public class CameraApplication extends Activity implements SurfaceHolder.Callback{
private SurfaceView surfaceView;
private SurfaceHolder surfaceHolder;
private LayoutInflater inflater = null;
private Button takePicture;
private Camera camera;
byte[] tempData;
private final static String TAG = "cookbook.hardware";
private boolean mPreviewRunning = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);//半透明
requestWindowFeature(Window.FEATURE_NO_TITLE);//无标题
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏
setContentView(R.layout.main);
surfaceView = (SurfaceView) findViewById(R.id.surface);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);//在主应用实现回调
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//无缓冲类型
inflater = LayoutInflater.from(this);//填充布局
View overView = inflater.inflate(R.layout.cameraoverlay, null);
this.addContentView(overView, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
takePicture = (Button) findViewById(R.id.button);
takePicture.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
camera.takePicture(mShutterCallback, mPictureCallback, mjpeg);
}
});
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
ShutterCallback mShutterCallback = new ShutterCallback() {
@Override
public void onShutter() {
}
};
PictureCallback mPictureCallback = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
}
};
PictureCallback mjpeg = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
if (data != null) {
tempData = data;
done();
}
}
};
/**
* 获取生成的照片
*/
private void done() {
Bitmap bm = BitmapFactory.decodeByteArray(tempData, 0, tempData.length);
String url = Images.Media.insertImage(getContentResolver(), bm, null, null);
bm.recycle();
Bundle bundle = new Bundle();
if (url!=null) {
bundle.putString("url", url);
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK,mIntent);
}else {
Toast.makeText(this, "Picture can not be saved",Toast.LENGTH_SHORT).show();
}
finish();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e(TAG, "SURFACE CREATED");
camera = Camera.open();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.e(TAG, "surfaceChanged");
try {
if (mPreviewRunning) {
camera.stopPreview();
mPreviewRunning = false;
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(width, height);
camera.setParameters(parameters);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
mPreviewRunning = true;
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e(TAG, "SURFACE DESTROYED");
camera.stopPreview();
mPreviewRunning = false;
camera.release();
camera = null;
}
}
8.1 自动回复短信
ResponderService.java
package com.david;
import java.util.ArrayList;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.telephony.SmsMessage;
import android.telephony.SmsManager;
import android.util.Log;
import android.widget.Toast;
public class ResponderService extends Service {
private static final String RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED";//接受短信的ACTION
private static final String SENT_ACTION = "SENT_SMS";
private static final String DELIVERED_ACTION = "DELIVERED_SMS";
private String requester;
private String reply = "";
private SharedPreferences myPrefs;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
myPrefs = PreferenceManager.getDefaultSharedPreferences(this);
//注册receiver
registerReceiver(sentReceiver, new IntentFilter(SENT_ACTION));
registerReceiver(deliverReceiver, new IntentFilter(DELIVERED_ACTION));
registerReceiver(receiver, new IntentFilter(RECEIVED_ACTION));
registerReceiver(sender, new IntentFilter(SENT_ACTION));
}
/**
* 发送短信
*/
BroadcastReceiver sentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
switch (getResultCode()) {
case Activity.RESULT_OK:
smsSent();
break;
default:
smsFailed();
break;
}
}
};
/**
* 发送短信成功
*/
private void smsSent() {
Toast.makeText(this, "Sms sent", Toast.LENGTH_SHORT).show();
}
/**
* 发送短信失败
*/
private void smsFailed() {
Toast.makeText(this, "Sms sent failed", Toast.LENGTH_SHORT).show();
}
/**
* 接收到短信
*/
private void smsDelivered() {
Toast.makeText(this, "Sms delivered", Toast.LENGTH_SHORT).show();
}
/**
* 接受短信receiver
*/
BroadcastReceiver deliverReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
smsDelivered();
}
};
/**
* 接收短信Receiver
*/
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.v("ResponderService", "On Receive");
reply = "";
if (intent.getAction().equals(RECEIVED_ACTION)) {
Log.v("ResponderService", "On SMS Receive");
//获取短信内容
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < pdus.length; i++) {
Log.v("ResponderService", "Found Message");
messages[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
}
for (SmsMessage message : messages) {
requestReceived(message.getOriginatingAddress());
}
respond();
}
}
}
};
/**
* 回复短信
*/
private void respond() {
Log.v("ResponderService","Responde to " + requester);
reply = myPrefs.getString("reply", "Thank you for your message.I am busy now."
+ "I will call you later");//回复信息。如果没有值则用默认值代替。
SmsManager smsManager = SmsManager.getDefault();
Intent sentIntent = new Intent(SENT_ACTION);
PendingIntent sentPIntent = PendingIntent.getBroadcast(this, 0, sentIntent, 0);
Intent deliverIntent = new Intent(DELIVERED_ACTION);
PendingIntent deliverPIntent = PendingIntent.getBroadcast(this, 0, deliverIntent, 0);
ArrayList<String> msgsArrayList = smsManager.divideMessage(reply);
ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
ArrayList<PendingIntent> deliverIntents = new ArrayList<PendingIntent>();
for (int i = 0; i < msgsArrayList.size(); i++) {
sentIntents.add(sentPIntent);
deliverIntents.add(deliverPIntent);
}
//发送短信
smsManager.sendMultipartTextMessage(requester, null, msgsArrayList, sentIntents, deliverIntents);
}
BroadcastReceiver sender = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(SENT_ACTION)) {
if (getResultCode() != Activity.RESULT_OK) {
String reciptent = intent.getStringExtra("recipient");
requestReceived(reciptent);
}
}
}
};
/**
* 获取接收者信息
* @param reciptent 接收者
*/
private void requestReceived(String reciptent) {
Log.v("ResponderService", "In requestReceived");
requester = reciptent;
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unregisterReceiver(receiver);
unregisterReceiver(sender);
}
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
}
}
SmsResponder.java
package com.david;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class SmsResponder extends Activity {
private Button submit;
private TextView textView;
private EditText editText;
private SharedPreferences myPrefs;
private String reply;
private Editor updater;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
submit = (Button) findViewById(R.id.submit);
textView = (TextView) findViewById(R.id.display);
editText = (EditText) findViewById(R.id.editText);
myPrefs = PreferenceManager.getDefaultSharedPreferences(this);//获取共享设置存储对象
reply = myPrefs.getString("reply", "Thank you for your message.I am busy now."
+ "I will call you later");
textView.setText(reply);//设置默认回复信息内容
updater = myPrefs.edit();
editText.setHint(reply);//提示
submit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updater.putString("reply", editText.getText().toString());//设置共享设置的内容
updater.commit();//执行
SmsResponder.this.finish();//关闭页面
}
});
try {
//启动服务
Intent svc = new Intent(this,ResponderService.class);
startService(svc);
} catch (Exception e) {
Log.e("Oncreate", e.toString());
}
}
}
9.1.4添加用户许可协议。
package com.cookbook.eula_example;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import com.david.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.util.Log;
public class Eula {
private static final String ASSET_EULA = "EULA";
private static final String PREFERENCE_EULA_ACCEPTED = "eula.accepted";
private static final String PREFERENCES_EULA = "eula";
/**
* 回调 让activity知道用户何时接受
* @author davidhuang
*
*/
static interface OnEulaAgreedTo{
void onEulaAgreedTo();
}
public static boolean show(final Activity activity)
{
final SharedPreferences preferences = activity.getSharedPreferences(PREFERENCES_EULA,Activity.MODE_PRIVATE);
if (!preferences.getBoolean(PREFERENCE_EULA_ACCEPTED, false)) {//是否已有该设定
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(R.string.eula_title);
builder.setPositiveButton(R.string.eula_accept, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
accept(preferences);
if (activity instanceof OnEulaAgreedTo) {
((OnEulaAgreedTo)activity).onEulaAgreedTo();
}
}
});
builder.setNegativeButton(R.string.eula_reject, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
refuse(activity);
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
refuse(activity);
}
});
builder.setMessage(readEula(activity));
builder.create().show();
return false;
}
return true;
}
/**
* 读写到本地文档
* @param activity
* @return
*/
private static CharSequence readEula(Activity activity) {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(activity.getAssets().open(ASSET_EULA)));//读取assets资源
String lineString;
StringBuilder buffer = new StringBuilder();
while ((lineString = in.readLine()) != null) {
buffer.append(lineString).append("\n");//读写内容并换行
}
return buffer;
} catch (Exception e) {
return "";
}finally{
closeStream(in);
}
}
/**
* 关闭连接
* @param stream
*/
private static void closeStream(Closeable stream) {
if (stream != null) {
try {
stream.close();
} catch (IOException e) {
Log.e("TAG", e.toString());
}
}
}
private static void refuse(Activity activity) {
activity.finish();
}
private static void accept(SharedPreferences preferences) {
preferences.edit().putBoolean(PREFERENCE_EULA_ACCEPTED, true).commit();
}
}
11.1 自定义 button
package com.david;
import android.R.integer;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Button;
public class CustomButton extends Button {
private Paint mTextPaint, mPaint;
private String mTextString;
private int mAscent;
private Shader mShader;
private Matrix mMatrix = new Matrix();
private float mStart;
private float mSweep;
private float mRotate;
private static final float SWEEP_INC = 2;
private static final float START_INC = 5;
public CustomButton(Context context) {
super(context);
initLabelView();
}
public CustomButton(Context context, AttributeSet attrs) {
super(context, attrs);
initLabelView();
}
/**
* 初始化文本样式和投影
*/
private final void initLabelView() {
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(16);
mTextPaint.setColor(0xFF0000);
setPadding(15, 15, 15, 15);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStrokeWidth(4);
mPaint.setStyle(Paint.Style.STROKE);
mShader = new SweepGradient(this.getMeasuredWidth() / 2,
this.getMeasuredHeight() / 2, new int[] { Color.GREEN,
Color.RED, Color.CYAN, Color.DKGRAY }, null);
mPaint.setShader(mShader);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measuredWidth(widthMeasureSpec),
measuredHeight(heightMeasureSpec));
}
private int measuredHeight(int heightMeasureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
mAscent = (int) mTextPaint.ascent();
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop()
+ getPaddingBottom();
if (specMode == MeasureSpec.AT_MOST) {
Log.v("Measure Height", "At most height:" + specSize);
result = Math.min(result, specSize);
}
}
return result;
}
private int measuredWidth(int widthMeasureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = (int) mTextPaint.measureText(mTextString)
+ getPaddingLeft() + getPaddingRight();
if (specMode == MeasureSpec.AT_MOST) {
Log.v("Measure Height", "At most height:" + specSize);
result = Math.min(result, specSize);
}
}
return result;
}
public void setText(String text) {
mTextString = text;
requestLayout();// 重新布局
invalidate();// 失效
}
public void setTextSize(int size) {
mTextPaint.setTextSize(size);
requestLayout();
invalidate();
}
public void setTextColor(int color) {
mTextPaint.setColor(color);
requestLayout();
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
mMatrix.setRotate(mRotate, this.getMeasuredWidth() / 2,
this.getMeasuredHeight() / 2);
mShader.setLocalMatrix(mMatrix);
mRotate += 3;
if (mRotate >= 360) {
mRotate = 0;
}
RectF drawRectF = new RectF();
drawRectF.set(this.getWidth() - mTextPaint.measureText(mTextString),
(this.getHeight() - mTextPaint.getTextSize()) / 2,
mTextPaint.measureText(mTextString),
this.getHeight()
- (this.getHeight() - mTextPaint.getTextSize()) / 2);
drawArcs(canvas,drawRectF,false,mPaint);
mSweep += SWEEP_INC;
if (mSweep > 360) {
mSweep -= 360;
mStart += START_INC;
if (mStart >= 360) {
mStart -= 360;
}
}
if (mSweep > 180) {
canvas.drawText(mTextString, getPaddingLeft(), getPaddingTop()-mAscent, mTextPaint);
}
invalidate();
}
/**
* 绘制
* @param canvas
* @param drawRectF
* @param b
* @param mPaint2
*/
private void drawArcs(Canvas canvas, RectF drawRectF, boolean userCenter,
Paint paint) {
canvas.drawArc(drawRectF, mStart, mSweep, userCenter, paint);
}
}
11.2 AIDL
RpcActivity.java
package com.david;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class RpcActivity extends Activity {
IAdditionalService service;
MyServiceConnection connection;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initService();
Button calcButton = (Button) findViewById(R.id.calc);
calcButton.setOnClickListener(new View.OnClickListener() {
TextView result = (TextView) findViewById(R.id.result);
EditText value1 = (EditText) findViewById(R.id.value1);
@Override
public void onClick(View v) {
int v1,res = -1;
try {
v1 = Integer.parseInt(value1.getText().toString());//获取输入的值
res = service.factorial(v1);//调用service
} catch (Exception e) {
e.printStackTrace();
}
result.setText(new Integer(res).toString());
}
});
}
class MyServiceConnection implements ServiceConnection
{
@Override
public void onServiceConnected(ComponentName name, IBinder boundService) {
service = IAdditionalService.Stub.asInterface((IBinder) boundService);
Toast.makeText(RpcActivity.this, "Service connected", Toast.LENGTH_SHORT).show();
}
@Override
public void onServiceDisconnected(ComponentName name) {
service = null;
Toast.makeText(RpcActivity.this, "service disconnected", Toast.LENGTH_SHORT).show();
}
}
private void initService(){
connection = new MyServiceConnection();
Intent intent = new Intent();
intent.setClassName("com.cookbook.advance.rpc", RPCService.class.getName());
if (!bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
Toast.makeText(RpcActivity.this, "Bind service failed", Toast.LENGTH_SHORT).show();
}
}
private void releaseService()
{
unbindService(connection);
connection = null;
}
@Override
protected void onDestroy() {
releaseService();
}
}
RPCService.java
package com.david;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class RPCService extends Service {
IAdditionalService.Stub mBinderStub;
@Override
public IBinder onBind(Intent intent) {
return mBinderStub;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
mBinderStub = new IAdditionalService.Stub() {
@Override
public int factorial(int value) throws RemoteException {
int result = 1;
for (int i = 1; i < value; i++) {
result += i;
}
return result;
}
};
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}
IAdditionalService.aidl
package com.david;
interface IAdditionalService {
int factorial(in int value);
}