点击事件 1屏幕点击事件  4数据存储    4手机内存的文件输入输出 5手机存储空间的划分   7SD卡的文件输入输出  8文件读写权限  9SharedPreferences的使用    10xml文件的序列化器XmlSerializer 12xml文件的解析器XmlPullParser  14Json数据解析    16SQLite数据库操作 17数据显示    26ListView显示数据    26常见对话框合集 31网络编程    36流的工具方法  36子线程更新UI的步骤  37Handler使用示例代码:  38简单的子线程更新UI的步骤(在Activity中)   40HTTP请求  411.URL面向过程的请求方式  412.HttpClient面向对象的请求方式   443.开源框架的Http请求   46菜单  47文件上传开源框架    49自定义控件SmartImageView网络图片加载器  50综合案例-新闻客户端  56示例代码    57断点下载    70断点下载开源框架 afinal-master  78Activity    79意图Intent    79显式意图    80隐式意图    80页面间的数据传递    81设置intent的数据 81获取数据    82隐式意图的应用 82浏览器示例代码:    82请求码和结果码 84横竖屏切换的生命周期(ctrl+F11)    90启动模式和任务栈    91广播接收者   92接收广播    92代码注册广播接收者   94发送广播    97自定义无序广播 97自定义有序广播 97Service服务   98本地服务    98startService(intent)方式开启服务  99案例-电话窃听器    99进程的优先级  104bind方式开启服务  105混合调用服务的生命周期处理   109远程服务    109远程服务案例  109利用通知栏提醒提升服务优先级  114综合案例-音乐播放器  116内容提供者   122内容提供者编写的步骤  122内容观察者   131多媒体编程   132加载大图片   132图片处理    134图片画画板   141图片调色器   144视频播放器   147SoundPool   152拍照  153录像  154传感器 154光传感器    154方向传感器   156动画  157帧动画 157补间动画    159补间动画XML配置   162属性动画    168Fragment    171

点击事件

  1. 内部类

    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bt = (Button) findViewById(R.id.click);bt.setOnClickListener(new MyListener());
    }
    private class MyListener implements OnClickListener{@Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this, "我被點擊了", 0).show();}
    }
    
  2. 匿名内部类

    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bt = (Button) findViewById(R.id.click);bt.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(MainActivity.this, "我被點擊了", 0).show();}});
    }
    
  3. 让activity实现onclickListener接口

    public class MainActivity extends Activity implements OnClickListener{private Button bt1;private Button bt2;private Button bt3;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bt1 = (Button) findViewById(R.id.click1);bt2 = (Button) findViewById(R.id.click2);bt3 = (Button) findViewById(R.id.click3);bt1.setOnClickListener(this);bt2.setOnClickListener(this);bt3.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.click1:Toast.makeText(this, "按钮1", 0).show();break;case R.id.click2:Toast.makeText(this, "按钮2", 0).show();break;case R.id.click3:Toast.makeText(this, "按钮3", 0).show();break;  }}
    }
    
  4. 在布局xml文件里面绑定点击事件

    <Buttonandroid:onClick="click"android:layout_centerInParent="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="点我" />public void click(View v){Toast.makeText(this, "我被点击了", 0).show();
    }
    

屏幕点击事件

        @Overridepublic boolean onTouchEvent(MotionEvent event) {if(event.getAction()==MotionEvent.ACTION_DOWN){System.out.println("-------");seekBar1.setVisibility(View.VISIBLE);new Thread(){public void run() {SystemClock.sleep(3000);runOnUiThread(new Runnable() {@Overridepublic void run() {seekBar1.setVisibility(View.INVISIBLE);}});};}.start();}return super.onTouchEvent(event);}

数据存储

手机内存的文件输入输出

  getFileDir(); 获取自己的文件夹 /data/data/包名/filesgetCacheDir();               /data/data/包名/cache
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//寻找这些控件et_qqnumber = (EditText) findViewById(R.id.et_qqnumber);et_password = (EditText) findViewById(R.id.et_password);cb_remember = (CheckBox) findViewById(R.id.cb_remember);restoreInfo();
}
/*** 登陆按钮的点击事件* @param view*/
public void login(View view){String qq = et_qqnumber.getText().toString().trim();String password = et_password.getText().toString().trim();if(TextUtils.isEmpty(qq)||TextUtils.isEmpty(password)){Toast.makeText(this, "用户名和密码不能为空", 0).show();return;}else{//判断是否需要记录用户名和密码if(cb_remember.isChecked()){//被选中状态,需要记录用户名和密码try {File file = new File(this.getFilesDir(),"info.txt");FileOutputStream fos = new FileOutputStream(file);//10000##123456String info = qq +"##"+password;fos.write(info.getBytes());fos.close();} catch (Exception e) {e.printStackTrace();}}//登陆操作的. 模拟登陆,数据应该提交给服务器 由服务器比较是否正确if("10000".equals(qq)&&"123456".equals(password)){Toast.makeText(this, "登陆成功", 0).show();}else{Toast.makeText(this, "登陆失败", 0).show();}}
}
/*** 根据原来保存的文件信息,把qq号码和密码信息回显到界面* getFilesDir()//获取应用程序files目录  /data/data/包名/files/   文件夹*/
public  void restoreInfo(){File file = new File(this.getFilesDir(),"info.txt");if(file.exists()&&file.length()>0){try {FileInputStream fis = new FileInputStream(file);BufferedReader br = new BufferedReader(new InputStreamReader(fis));//10000##123456String info = br.readLine();String qq = info.split("##")[0];String pwd = info.split("##")[1];et_qqnumber.setText(qq);et_password.setText(pwd);} catch (Exception e) {e.printStackTrace();}}
}

手机存储空间的划分

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);File dataFile = Environment.getDataDirectory(); // 数据内部存储空间File sdFile = Environment.getExternalStorageDirectory();// 外部存储空间long datasize = dataFile.getTotalSpace();long sdsize = sdFile.getTotalSpace();TextView tv = (TextView) findViewById(R.id.tv);tv.setText("内部存储:" + Formatter.formatFileSize(this, datasize) + "\n"+ "外部sd卡:" + Formatter.formatFileSize(this, sdsize));// 三星  小米  魅族 // /mnt/sdcard// /mnt/storage01// /mnt/stoarge02// /mnt/mount/stoarge01
}

SD卡的文件输入输出

/*** 模拟向sd卡写一个视频文件. * @param view*/
public void click(View view) {// 检查的sd卡的状态if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {File sdFile = Environment.getExternalStorageDirectory();// 外部存储空间long sdsize = sdFile.getFreeSpace();if (sdsize >5* 1024 * 1024) {File file = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+"hlw.3gp");try {FileOutputStream fos = new FileOutputStream(file);byte[] buffer = new byte[1024];for (int i = 0; i < 5*1024; i++) {fos.write(buffer);}fos.close();} catch (Exception e) {e.printStackTrace();}}else{Toast.makeText(this, "sd卡空间不足", 0).show();}} else {Toast.makeText(this, "sd卡被拔出或者是不可用", 0).show();}
}

文件读写权限

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);try {/*得到一个文件的输出流,文件的位置/data/data/包名/files/haha.txt*File file = new File(getFilesDir(),"haha.txt");*FileOutputStream fos = new FileOutputStream(file);*/FileOutputStream fos = openFileOutput("readable.txt", MODE_WORLD_READABLE);fos.write("dafa".getBytes());fos.close();fos = openFileOutput("writeable.txt", MODE_WORLD_WRITEABLE);fos.write("dafa".getBytes());fos.close();fos = openFileOutput("public.txt", MODE_WORLD_WRITEABLE+MODE_WORLD_READABLE);fos.write("dafa".getBytes());fos.close();fos = openFileOutput("private.txt", MODE_PRIVATE);fos.write("dafa".getBytes());fos.close();} catch (Exception e) {e.printStackTrace();}
}

SharedPreferences的使用

//1. 声明一个共享参数(存储数据方便的api)
private SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//2. 通过上下文得到一个共享参数的实例对象//类似 File f = new File("config");sp = this.getSharedPreferences("config", MODE_PRIVATE);//寻找这些控件et_qqnumber = (EditText) findViewById(R.id.et_qqnumber);et_password = (EditText) findViewById(R.id.et_password);cb_remember = (CheckBox) findViewById(R.id.cb_remember);restoreInfo();
}
/*** 登陆按钮的点击事件* @param view*/
public void login(View view){String qq = et_qqnumber.getText().toString().trim();String password = et_password.getText().toString().trim();if(TextUtils.isEmpty(qq)||TextUtils.isEmpty(password)){Toast.makeText(this, "用户名和密码不能为空", 0).show();return;}else{//判断是否需要记录用户名和密码if(cb_remember.isChecked()){//被选中状态,需要记录用户名和密码//TODO:记录密码Editor editor = sp.edit();editor.putString("qq", qq);editor.putString("password", password);editor.commit();//提交数据. 类似关闭流,事务}//登陆操作的. 模拟登陆,数据应该提交给服务器 由服务器比较是否正确if("10000".equals(qq)&&"123456".equals(password)){Toast.makeText(this, "登陆成功", 0).show();}else{Toast.makeText(this, "登陆失败", 0).show();}}
}
/*** 根据原来保存的文件信息,把qq号码和密码信息回显到界面*/
public  void restoreInfo(){//TODO:读取密码String qq = sp.getString("qq", "");String password = sp.getString("password", "");et_qqnumber.setText(qq);et_password.setText(password);
}

xml文件的序列化器XmlSerializer

//  <头>
//  <info>
//      <student id='800001'>
//          <name>张三</name>
//          <age>18</age>
//      </student>
//  </info>
//保存学生的信息
public void save(View view){String name = et_name.getText().toString().trim();String age = et_age.getText().toString().trim();String id = et_id.getText().toString().trim();if(TextUtils.isEmpty(name)||TextUtils.isEmpty(age)||TextUtils.isEmpty(id)){Toast.makeText(this, "信息不能为空", 0).show();return;}else{//打算把数据存成xml文件.跨平台.try {//1.创建一个xml文件的序列化器XmlSerializer serializer = Xml.newSerializer();//2.设置文件的输出和编码方式File file = new File(Environment.getExternalStorageDirectory(),"info.xml");FileOutputStream os = new FileOutputStream(file);serializer.setOutput(os, "utf-8");//3.写xml文件的头serializer.startDocument("utf-8", true);//4.写info节点serializer.startTag(null, "info");//5.写student节点serializer.startTag(null, "student");//6.写属性serializer.attribute(null, "id", id);//7.写nameserializer.startTag(null, "name");serializer.text(name);serializer.endTag(null, "name");//8.写ageserializer.startTag(null, "age");serializer.text(age);serializer.endTag(null, "age");serializer.endTag(null, "student");serializer.endTag(null, "info");serializer.endDocument();//写文件的末尾os.close();Toast.makeText(this, "保存学生信息成功", 0).show();} catch (Exception e) {e.printStackTrace();Toast.makeText(this, "保存学生信息失败", 0).show();}}
}

xml文件的解析器XmlPullParser

private void readXmlInfo(File file){try {//1.初始化解析器XmlPullParser parser = Xml.newPullParser();//2.设置解析器的参数InputStream inputStream = new FileInputStream(file);parser.setInput(inputStream, "utf-8");int type = parser.getEventType();StringBuilder sb = new StringBuilder();while(type!=XmlPullParser.END_DOCUMENT){switch (type) {case XmlPullParser.START_TAG:if("name".equals(parser.getName())){//这是name节点String name = parser.nextText();sb.append("--name:"+name);}else if("num".equals(parser.getName())){//这是name节点String num = parser.nextText();sb.append("--num:"+num);}else if("sex".equals(parser.getName())){//这是name节点String sex = parser.nextText();sb.append("--sex:"+sex);}break;}type =  parser.next();//让解析器解析下一个元素}inputStream.close();String text = sb.toString();} catch (Exception e) {e.printStackTrace();}
}

Json数据解析

JSONObject

            json数据__GetZoneResult_ = {mts:'1351234',province:'重庆',catName:'中国移动',telString:'13512345678',areaVid:'29404',ispVid:'3236139',carrier:'重庆移动'}String json = StreamTools.readStream(is).replace("__GetZoneResult_ = ", "");JSONObject jsonObject = new JSONObject(json);final String catName = jsonObject.getString("catName");final String province = jsonObject.getString("province");showToastInAnyThread( "运营商:"+catName+"\n归属地:"+province);

JSONARRY

            //jsonData的数据格式:String jsonData = "[{ "id": "27JpL~jd99w9nM01c000qc", "version": "abc" },{ "id": "27JpL~j6UGE0LX00s001AH", "version": "bbc" },{ "id": "27JpL~j7YkM0LX01c000gt", "version": "Wa_" }]";JSONArray arr = new JSONArray(jsonData);  for (int i = 0; i < arr.length(); i++) { JSONObject temp = (JSONObject) arr.get(i);  String id = temp.getString("id");  String version = temp.getString("version");}

SQLite数据库操作

  1. MyDBOpenHelper创建数据库

    MyDBOpenHelper.java

    /*** 数据库创建的帮助类 类似File类* @author Administrator*/
    public class MyDBOpenHelper extends SQLiteOpenHelper {/*** @param context 上下文* @param version*/public MyDBOpenHelper(Context context) {//第二个参数数据库的名称//第三个参数null代表的是默认的游标工厂//第四个参数 是数据库的版本号  数据库只能升级,不能降级,版本号只能变大不能变小super(context, "itheima.db", null, 2); }//Called when the database is created for the first time.//当数据库第一次被创建的时候调用的方法,适合在这个方法里面把数据库的表结构定义出来.@Overridepublic void onCreate(SQLiteDatabase db) {System.out.println("oncreate 数据库被创建了. 哈哈哈哈,嘎嘎嘎------------");//执行sql语句db.execSQL("create table contactinfo (id integer primary key autoincrement, name varchar(20), phone varchar(20))");}//Called when the database needs to be upgraded.//当数据库更新的时候调用的方法@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {System.out.println("onUpgrade 数据库被更新了. oldVersion:"+oldVersion+"--------newVersion:"+newVersion+"----");db.execSQL("alter table contactinfo add account varchar(20)");}
    }
    
  2. ContactInfoDao数据库的DAO

    ContactInfoDao.java

    /**
    * 联系人数据库表的访问类
    */
    public class ContactInfoDao {/*** 数据库打开的帮助类*/private MyDBOpenHelper helper;/*** 在构造方法里面完成 必须要用的类的初始化* @param context*/public ContactInfoDao(Context context) {helper = new MyDBOpenHelper(context);}/*** 添加一条记录* @param name 联系人姓名* @param phone 联系人电话* @return 返回的是添加后在数据库的行号  -1代表添加失败*/public long add(String name, String phone){SQLiteDatabase db = helper.getWritableDatabase();//db.execSQL("insert into contactinfo (name,phone) values (?,?)", new Object[]{name,phone});ContentValues values = new ContentValues();values.put("name", name);values.put("phone", phone);//内部是组拼sql语句实现的.long rowid = db.insert("contactinfo", null, values);//记得释放数据库资源db.close();return rowid;}/*** 根据姓名删除一条记录* @param name 要删除的联系人的姓名* @return 返回0代表的是没有删除任何的记录 返回整数int值代表删除了几条数据*/public int delete(String name){//判断这个数据是否存在.SQLiteDatabase db = helper.getWritableDatabase();//db.execSQL("delete from contactinfo where name=?", new Object[]{name});int rowcount = db.delete("contactinfo", "name=?", new String[]{name});db.close();//再从数据库里面查询一遍,看name是否还在return rowcount;}/*** 修改联系人电话号码* @param newphone 新的电话号码* @param name 要修改的联系人姓名* @return 0代表一行也没有更新成功, >0 整数代表的是更新了多少行记录*/public int update(String newphone , String name){SQLiteDatabase db = helper.getWritableDatabase();//db.execSQL("update contactinfo set phone =? where name=?", new Object[]{newphone,name});ContentValues values = new ContentValues();values.put("phone", newphone);int rowcount =  db.update("contactinfo", values, "name=?", new String[]{name});db.close();return rowcount;}/*** 查询联系人的电话号码* @param name 要查询的联系人* @return 电话号码*/public String getPhoneNumber(String name){String phone = null;SQLiteDatabase db = helper.getReadableDatabase();//Cursor  cursor = db.rawQuery("select phone from contactinfo where name=?", new String[]{name});Cursor  cursor =  db.query("contactinfo", new String[]{"phone"}, "name=?", new String[]{name}, null, null, null);if(cursor.moveToNext()){//如果光标可以移动到下一位,代表就是查询到了数据phone = cursor.getString(0);}cursor.close();//关闭掉游标,释放资源db.close();//关闭数据库,释放资源return phone;}
    }
    

    数据库的事务操作

    // 数据库的事务, 保证一组sql语句 要么同时执行成功 ,要么同时执行失败
    public void deteleAll() {// 删除数据库全部的记录.SQLiteDatabase db = helper.getWritableDatabase();db.beginTransaction();// 开启事务try {Cursor cursor = db.query("info", new String[] { "studentid" },null, null, null, null, null);while (cursor.moveToNext()) {String studentid = cursor.getString(0);db.delete("info", "studentid=?", new String[] { studentid });//throw new RuntimeException("--");}cursor.close();db.setTransactionSuccessful();//设置事务执行成功.必须要这一行代码执行,数据才会被提交} finally {db.endTransaction();//根据db设置的事务标记 来去确定事务是否被提交db.close();}
    }
    
  3. MainActivity数据库的应用类

    MainActivity.java

    public class MainActivity extends Activity {private EditText et_name;private EditText et_phone;private ContactInfoDao dao;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_name = (EditText) findViewById(R.id.et_name);et_phone = (EditText) findViewById(R.id.et_phone);dao = new ContactInfoDao(this);}/*** 添加一条联系人的信息* @param view*/public void add(View view) {String name = et_name.getText().toString().trim();String phone = et_phone.getText().toString().trim();if (TextUtils.isEmpty(name) || TextUtils.isEmpty(phone)) {Toast.makeText(this, "不能为空", 0).show();return;} else {long id = dao.add(name, phone);if (id == -1) {Toast.makeText(this, "添加失败", 0).show();} else {Toast.makeText(this, "添加成功,在数据库的第:"+id+"行", 0).show();}}}/*** 删除一条记录* @param view*/public void delete(View view) {String name = et_name.getText().toString().trim();if (TextUtils.isEmpty(name)) {Toast.makeText(this, "姓名不能为空", 0).show();return;} else {int count = dao.delete(name);if(count==0){Toast.makeText(this, "删除失败,没有记录", 0).show();}else{Toast.makeText(this, "删除成功,删除了"+count+"条记录", 0).show();}}}/*** 修改联系人的号码* @param view*/public void update(View view) {String name = et_name.getText().toString().trim();String phone = et_phone.getText().toString().trim();if (TextUtils.isEmpty(name) || TextUtils.isEmpty(phone)) {Toast.makeText(this, "不能为空", 0).show();return;} else {int count = dao.update(phone, name);if(count==0){Toast.makeText(this, "更新失败,没有记录", 0).show();}else{Toast.makeText(this, "更新成功,更新了"+count+"条记录", 0).show();}}}/*** 查询* @param view*/public void query(View view) {String name = et_name.getText().toString().trim();if (TextUtils.isEmpty(name)) {Toast.makeText(this, "姓名不能为空", 0).show();return;} else {String result = dao.getPhoneNumber(name);Toast.makeText(this, "号码:" + result, 0).show();}}
    }
    

数据显示

ListView显示数据

  1. 在布局文件里面声明listview

    <ListViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/lv" />
    
  2. 自定义item.xml布局
  3. 设置listview的数据适配器(controller)

    public class MainActivity extends Activity {private EditText et_name;private EditText et_phone;private ListView lv;/*** 学生信息的dao*/private StudentDao dao;/*** 所有的学生信息*/private List<StudentInfo> infos;/*** 全局的数据适配器*/private StudentAdapter adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);et_name = (EditText) findViewById(R.id.et_name);et_phone = (EditText) findViewById(R.id.et_phone);lv = (ListView) findViewById(R.id.lv);dao = new StudentDao(this);infos = dao.findAll();// controll 控制器// 设置listview的数据适配器控制器adapter = new StudentAdapter();lv.setAdapter(adapter);}/*** 添加一个信息到数据库* @param view*/public void add(View view){String name = et_name.getText().toString().trim();String phone = et_phone.getText().toString().trim();if(TextUtils.isEmpty(name)||TextUtils.isEmpty(phone)){Toast.makeText(this, "数据不能为空", 0).show();return ;}long result = dao.add(name, phone);if(result>0){Toast.makeText(this, "添加成功", 0).show();infos = dao.findAll();adapter.notifyDataSetChanged();//-->从新调用getcount 调用getview}else{Toast.makeText(this, "添加失败", 0).show();}}private class StudentAdapter extends BaseAdapter{@Overridepublic int getCount() {return infos.size();}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {System.out.println("position"+position);//布局填充器View view = View.inflate(MainActivity.this, R.layout.item, null);TextView tv_id = (TextView) view.findViewById(R.id.tv_id);TextView tv_name = (TextView) view.findViewById(R.id.tv_name);TextView tv_phone = (TextView) view.findViewById(R.id.tv_phone);ImageView iv_delete = (ImageView) view.findViewById(R.id.iv_delete);iv_delete.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {AlertDialog.Builder builder = new Builder(MainActivity.this);builder.setTitle("提醒");builder.setMessage("是否确定删除?");builder.setPositiveButton("确定删除", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {// 获取该位置组件id,并删除int result = dao.delete(infos.get(position).getId());Toast.makeText(MainActivity.this, "删除了"+result+"个记录", 0).show();// 重新查询infos = dao.findAll();adapter.notifyDataSetChanged();}});builder.setNegativeButton("取消", null);builder.create().show();}});// 修改对应值tv_id.setText(infos.get(position).getId());tv_name.setText(infos.get(position).getName());tv_phone.setText(infos.get(position).getPhone());return view;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}}
    }
    

常见对话框合集

/*** 弹出确定取消对话框* @param view*/
public void click01(View view) {// 工厂设计模式. 得到创建对话框的工厂AlertDialog.Builder builder = new Builder(this);// 设置标题builder.setTitle("警告,请三思:");// 设置描述信息builder.setMessage("若练此功,必先自宫,是否继续?");// 设置确定和取消按钮builder.setPositiveButton("是", new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Toast.makeText(getApplicationContext(), "啊....,即便自宫,也不一定成功", 0).show();}});builder.setNegativeButton("否", new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Toast.makeText(getApplicationContext(), "如果不自宫,一定不成功", 0).show();}});// AlertDialog dialog = builder.create();// dialog.show();builder.show();
}
/*** 单选对话框* @param view*/
public void click02(View view) {// 工厂设计模式. 得到创建对话框的工厂AlertDialog.Builder builder = new Builder(this);//设置标题builder.setTitle("请选择您的性别");//设置选项final String[] items = {"男","女","中间"};builder.setSingleChoiceItems(items, -1, new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {Toast.makeText(getApplicationContext(), "您的性别为:"+items[which], 0).show();dialog.dismiss();}});builder.show();
}
/*** 多选对话框* @param view*/
public void click03(View view) {// 工厂设计模式. 得到创建对话框的工厂AlertDialog.Builder builder = new Builder(this);//设置标题builder.setTitle("请选择您爱吃的水果");//设置选项final String[] items = {"苹果","梨","香蕉","菠萝","煎饼果子"};final boolean[] checked={true,false,true,false,true};builder.setMultiChoiceItems(items, checked,  new OnMultiChoiceClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which, boolean isChecked) {Toast.makeText(getApplicationContext(), items[which]+isChecked, 0).show();checked[which] = isChecked;}});builder.setPositiveButton("提交", new OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {StringBuffer sb = new StringBuffer();for(int i=0;i<checked.length;i++){if(checked[i]){sb.append(items[i]+" ");}}Toast.makeText(getApplicationContext(), "您喜欢的水果有:"+sb.toString(), 0).show();}});builder.show();
}
/*** 进度对话框* @param view*/
public void click04(View view){final ProgressDialog pd = new ProgressDialog(this);pd.setTitle("请稍后:");pd.setMessage("正在拼命加载中....");pd.show();new Thread(){public void run() {try {Thread.sleep(30000);} catch (InterruptedException e) {e.printStackTrace();}pd.dismiss();};}.start();
}
/*** 带具体进度的对话框* @param view*/
public void click05(View view){final ProgressDialog pd = new ProgressDialog(this);pd.setTitle("请稍后:");//设置进度样式pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);pd.setMessage("正在拼命加载中....");//设置进度条的最大值pd.setMax(100);pd.show();new Thread(){public void run() {try {for(int i=0;i<=100;i++){Thread.sleep(300);pd.setProgress(i);}} catch (InterruptedException e) {e.printStackTrace();}pd.dismiss();};}.start();
}

网络编程

流的工具方法

    /*** 流的一个工具类* @author Administrator**/public class StreamUtils {/*** 读取流的数据返回一个字符串* @param is 获取的流* @return 字符串 解析失败返回null;*/public static String readStread(InputStream is){try {ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len = 0;while(( len = is.read(buffer))!=-1){baos.write(buffer, 0, len);}is.close();String result = baos.toString();//智能识别网页编码if(result.contains("gb2312")){return baos.toString("gb2312");}else{return result;}} catch (Exception e) {e.printStackTrace();return null;}}

子线程更新UI的步骤

runOnUiThread(new Runnable() {});

  1. 创建一个消息处理器Handler(一定要在主线程new出来)

    private Handler handler = new Handler() {};
    
  2. 在子线程利用handler发送消息给主线程的消息队列

    handler.sendMessage(msg);
    
  3. 在主线程的消息处理器里面,处理这个消息

    public void handleMessage(Message msg) {}
    
  4. 特殊情况 传递数据

    Message.obj 携带数据
    

Handler使用示例代码:

public class MainActivity extends Activity {private TextView tv;/*** 1.创建一个消息处理器,类似工厂里面的老板,运行在主线程里面.*/private Handler handler = new Handler() {// 3.loop调用的用来处理消息的方法,运行在主线程public void handleMessage(Message msg) {//区分消息类型switch(msg.what){case ?:break;}int i = (Integer) msg.obj;tv.setText("当前进度:"+i+"%");};};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv = (TextView) findViewById(R.id.tv);}public void click(View view) {new Thread() {public void run() {// tv.setText("hahahah"); 子线程不可以直接更新ui// 2.通过消息处理器 把一个消息发送到 消息队列for (int i = 0; i < 100; i++) {Message msg = new Message();//Message msg = Message.obtain(); 消息池//消息携带的数据msg.obj = i;//msg.what = ? 消息类型handler.sendMessage(msg);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}};}.start();}
}

简单的子线程更新UI的步骤(在Activity中)

/*** 显示土司* @param text*/
public void showToastInAnyThread(final String text){runOnUiThread(new Runnable() {@Overridepublic void run() {//运行在主线程,内部做了处理Toast.makeText(MainActivity.this, text, 0).show();}});
}

HTTP请求

1.URL面向过程的请求方式

GET请求

    // 采用http的get请求,提交数据到服务器new Thread() {public void run() {try {Thread.sleep(5000);//统一码表String path = "http://192.168.1.109:8080/web/LoginServlet?username="+ URLEncoder.encode(qq) + "&password=" + URLEncoder.encode(password); // 1.得到服务器资源的路径URL url = new URL(path);// 2.通过这个路径打开浏览器的连接.HttpURLConnection conn = (HttpURLConnection) url.openConnection();// ftp || http || https || rtsp// 3.设置请求方式为get请求conn.setRequestMethod("GET");// 注意get只能用大写 不支持小写conn.setConnectTimeout(5000);conn.setReadTimeout(10000);// 为了有一个更好的用户ui提醒,获取服务器的返回状态码int code = conn.getResponseCode();// 200 ok 404资源没有找到 503if(code == 200){// 4.获取服务器的返回的流InputStream is = conn.getInputStream();String result = StreamUtils.readStread(is);Message msg = Message.obtain();msg.what = GET_SERVER_RESOPONSE;msg.obj = result;handler.sendMessage(msg);}else {Message msg = Message.obtain();msg.what = ERROR;handler.sendMessage(msg);}} catch (Exception e) {e.printStackTrace();Message msg = Message.obtain();msg.what = ERROR;handler.sendMessage(msg);}};}.start();

POST请求

    // POST请求数据应该提交给服务器 由服务器比较是否正确new Thread() {public void run() {try {// 1.指定提交数据的路径,post的方式不需要组拼任何的参数String path = "http://192.168.1.109:8080/web/LoginServlet";URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();//2.指定请求方式为postconn.setRequestMethod("POST");//3.设置http协议的请求头conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");//设置发送的数据为表单类型//username=abc&password=123//统一码表String data = "username="+URLEncoder.encode(qq, "utf-8")+"&password="+URLEncoder.encode(password);conn.setRequestProperty("Content-Length", String.valueOf(data.length()));//告诉服务器发送的数据的长度//post的请求是把数据以流的方式写给了服务器//指定请求的输出模式conn.setDoOutput(true);//运行当前的应用程序给服务器写数据conn.getOutputStream().write(data.getBytes());int code = conn.getResponseCode();if(code == 200){InputStream is = conn.getInputStream();final String result = StreamTools.readStream(is);showToastInAnyThread(result);}else{showToastInAnyThread("请求失败");}} catch (Exception e) {e.printStackTrace();showToastInAnyThread("请求失败");}};}.start();

2.HttpClient面向对象的请求方式

GET请求

        // 提交数据到服务器,采用http的get请求new Thread() {public void run() {try {Thread.sleep(2000);String path = "http://192.168.1.109:8080/web/LoginServlet?username="+ URLEncoder.encode(qq) + "&password=" + URLEncoder.encode(password);//1.打开浏览器HttpClient client = new DefaultHttpClient();//2.输入数据HttpGet httpGet = new HttpGet(path);//3.敲回车HttpResponse  httpResponse = client.execute(httpGet);int code = httpResponse.getStatusLine().getStatusCode();if(code == 200){InputStream is = httpResponse.getEntity().getContent();String result = StreamUtils.readStread(is);Message msg = Message.obtain();msg.what = GET_SERVER_RESOPONSE;msg.obj = result;handler.sendMessage(msg);}else {Message msg = Message.obtain();msg.what = ERROR;handler.sendMessage(msg);}} catch (Exception e) {e.printStackTrace();Message msg = Message.obtain();msg.what = ERROR;handler.sendMessage(msg);}};}.start();

POST请求

        // 数据应该提交给服务器 由服务器比较是否正确new Thread() {public void run() {try {String path = "http://192.168.1.109:8080/web/LoginServlet";//1.打开浏览器HttpClient client = new DefaultHttpClient();//2.设置数据HttpPost httpPost = new HttpPost(path);//ctrl+shift+oList<NameValuePair> parameters = new ArrayList<NameValuePair>();// SimpleXXX DefaultXXX BaseXXX BasicXXXparameters.add(new BasicNameValuePair("username", qq));parameters.add(new BasicNameValuePair("password", password));httpPost.setEntity(new UrlEncodedFormEntity(parameters,"utf-8"));//3.发送请求HttpResponse response = client.execute(httpPost);int code = response.getStatusLine().getStatusCode();if(code == 200){InputStream is = response.getEntity().getContent();final String result = StreamTools.readStream(is);showToastInAnyThread(result);}else{showToastInAnyThread("请求失败");}} catch (Exception e) {e.printStackTrace();showToastInAnyThread("请求失败");}};}.start();

3.开源框架的Http请求

开源框架 android-async-http-master

POST请求

        // 1.打开浏览器. 支持异步的浏览器 自动在后台开启线程 发送网络请求AsyncHttpClient client = new AsyncHttpClient();String url = "http://192.168.1.109:8080/web/LoginServlet";//2.设置请求参数RequestParams params = new RequestParams();params.put("username", qq);params.put("password", password);//3.发送请求client.post(url, params, new AsyncHttpResponseHandler() {@Overridepublic void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {Toast.makeText(getApplicationContext(), new String(responseBody), 0).show();}@Overridepublic void onFailure(int statusCode, Header[] headers,byte[] responseBody, Throwable error) {Toast.makeText(getApplicationContext(), "请求失败", 0).show();}});

菜单

/*** 创建菜单*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.activity_main, menu);return true;
}
/*** 当选项的菜单被点击的时候调用的方法*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.item_deteleall:dao.deteleAll();Toast.makeText(this, "删除全部成功", 0).show();lv.setAdapter(new MyAdapter());break;case R.id.item_save:Toast.makeText(this, "上传到云服务器", 0).show();//data/data/包名/databases/student.dbuploadDBToServer();break;case R.id.item_aaa:Toast.makeText(this, "aaa", 0).show();break;case R.id.item_bbb:Toast.makeText(this, "bbb", 0).show();break;}return super.onOptionsItemSelected(item);
}

文件上传开源框架

开源框架 android-async-http-master

/*** 上传数据到服务器*/
private void uploadDBToServer() {try {AsyncHttpClient client = new AsyncHttpClient();String url = "http://192.168.1.109:8080/web/UploadServlet";RequestParams params = new RequestParams();params.put("file", new File("/data/data/"+getPackageName()+"/databases/student.db")); // Upload a Fileclient.post(url, params, new AsyncHttpResponseHandler() {@Overridepublic void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {Toast.makeText(getApplicationContext(), "上传成功", 0).show();}@Overridepublic void onFailure(int statusCode, Header[] headers,byte[] responseBody, Throwable error) {Toast.makeText(getApplicationContext(), "上传失败", 0).show();}@Overridepublic void onProgress(int bytesWritten, int totalSize) {System.out.println(bytesWritten+"/"+totalSize);super.onProgress(bytesWritten, totalSize);}});} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}

自定义控件SmartImageView网络图片加载器

开源框架 android-smart-image-view-master

  1. 自定义SmartImageView类继承ImageView

    SmartImageView.java

    public class SmartImageView extends ImageView {protected static final int SUCCESS = 1;protected static final int ERROR = 2;private Handler handler = new Handler(){public void handleMessage(android.os.Message msg) {switch (msg.what) {case SUCCESS:Bitmap bitmap = (Bitmap) msg.obj;setImageBitmap(bitmap);break;case ERROR:int resId = (Integer) msg.obj;setImageResource(resId);break;}};};public SmartImageView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public SmartImageView(Context context, AttributeSet attrs) {super(context, attrs);}public SmartImageView(Context context) {super(context);}/*** 设置一个网络图片 * @param path 图片的网址*/public void setImageUrl(final String path){//加载网络图片new Thread(){public void run() {try {URL url = new URL(path);Thread.sleep(5000);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");InputStream is = conn.getInputStream();Bitmap bitmap = BitmapFactory.decodeStream(is);Message msg = Message.obtain();msg.obj = bitmap;handler.sendMessage(msg);} catch (Exception e) {e.printStackTrace();}};}.start();}/*** 设置一个网络图片 * @param path 图片的网址* @param errorimage 如果加载失败显示什么图片,在r文件中的id*/public void setImageUrl(final String path,final int errorimage){//加载网络图片new Thread(){public void run() {try {URL url = new URL(path);Thread.sleep(5000);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");if(conn.getResponseCode()==200){InputStream is = conn.getInputStream();Bitmap bitmap = BitmapFactory.decodeStream(is);Message msg = Message.obtain();msg.obj = bitmap;msg.what = SUCCESS;handler.sendMessage(msg);}else{Message msg = Message.obtain();msg.what = ERROR;msg.obj = errorimage;handler.sendMessage(msg);}} catch (Exception e) {Message msg = Message.obtain();msg.what = ERROR;msg.obj = errorimage;handler.sendMessage(msg);e.printStackTrace();}};}.start();}/*** 设置一个网络图片 * @param path 图片的网址* @param loadingimg 加载中的图片* @param errorimage 如果加载失败显示什么图片,在r文件中的id*/public void setImageUrl(final String path,final int loadingimg, final int errorimage){setImageResource(loadingimg);//加载网络图片new Thread(){public void run() {try {URL url = new URL(path);Thread.sleep(5000);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");if(conn.getResponseCode()==200){InputStream is = conn.getInputStream();Bitmap bitmap = BitmapFactory.decodeStream(is);Message msg = Message.obtain();msg.obj = bitmap;msg.what = SUCCESS;handler.sendMessage(msg);}else{Message msg = Message.obtain();msg.what = ERROR;msg.obj = errorimage;handler.sendMessage(msg);}} catch (Exception e) {Message msg = Message.obtain();msg.what = ERROR;msg.obj = errorimage;handler.sendMessage(msg);e.printStackTrace();}};}.start();}
    }
    
  2. 编写布局,使用自定义控件

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" ><com.itheima.myimageview.SmartImageViewandroid:id="@+id/siv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_centerVertical="true"/>
    </RelativeLayout>
    
  3. 在MainActivity中找到自定义控件,调用SmartImageView中的方法

    public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);SmartImageView siv = (SmartImageView) findViewById(R.id.siv);siv.setImageUrl("http://192.168.1.109:8080/img/a.jpg", R.drawable.loading, R.drawable.error);}
    }
    

综合案例-新闻客户端

示例代码

  1. 编辑布局

    activity_main.xml

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" ><ListViewandroid:id="@+id/lv_news"android:layout_width="match_parent"android:layout_height="match_parent" /><LinearLayoutandroid:visibility="invisible"android:id="@+id/ll_loading"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical" ><ProgressBarandroid:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="正在拼命加载中..." /></LinearLayout>
    
  2. 获取数据,展示数据

    MainActivity.java

        public class MainActivity extends Activity {protected static final int LOAD_ERROR = 2;protected static final int SHOW_NEWS = 1;private ListView lv_news;private LinearLayout ll_loading;//如何内部的代码都可以访问private List<NewsItem> newsItems;private Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {//把正在加载的界面隐藏起来ll_loading.setVisibility(View.INVISIBLE);switch (msg.what) {case LOAD_ERROR:Toast.makeText(getApplicationContext(), "获取数据失败", 0).show();break;case SHOW_NEWS:Toast.makeText(getApplicationContext(), "加载数据成功,显示listview", 0).show();lv_news.setAdapter(new MyNewsAdapter());break;}};};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ll_loading = (LinearLayout) findViewById(R.id.ll_loading);lv_news = (ListView) findViewById(R.id.lv_news);// 设置新闻的数据.// 连接服务器 获取服务器上的最新的新闻信息loadNewsInfo();}/*** 获取新闻信息*/private void loadNewsInfo() {//把正在加载界面给显示出来ll_loading.setVisibility(View.VISIBLE);// 联网,子线程new Thread() {public void run() {try {Thread.sleep(5000);URL url = new URL("http://192.168.1.109:8080/news.xml");HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");// 设置连接超时时间conn.setConnectTimeout(5000);// 设置一个读取超时时间conn.setReadTimeout(20000);int code = conn.getResponseCode();if (code == 200) {// 请求成功InputStream is = conn.getInputStream();// 代表的是服务器返回的流// 里面是xml数据newsItems = NewsInfoParser.getAllNewsInfos(is);// 更新界面,把新闻显示到ui上.Message msg = Message.obtain();msg.what = SHOW_NEWS;handler.sendMessage(msg);} else {// 请求失败Message msg = Message.obtain();msg.what = LOAD_ERROR;handler.sendMessage(msg);}} catch (Exception e) {e.printStackTrace();// 请求失败Message msg = Message.obtain();msg.what = LOAD_ERROR;handler.sendMessage(msg);}};}.start();}private class MyNewsAdapter extends BaseAdapter{@Overridepublic int getCount() {return newsItems.size();}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {//LayoutInflater 布局打气筒, 把xml资源文件转成viewView view = View.inflate(getApplicationContext(), R.layout.news_item, null);SmartImageView iv = (SmartImageView) view.findViewById(R.id.iv_img);TextView tv_title = (TextView) view.findViewById(R.id.tv_title);TextView tv_desc = (TextView) view.findViewById(R.id.tv_desc);TextView tv_type = (TextView) view.findViewById(R.id.tv_type);NewsItem newsItem = newsItems.get(position);iv.setImageUrl(newsItem.getImagePath());tv_title.setText(newsItem.getTitle());tv_desc.setText(newsItem.getDesc());String type = newsItem.getType();// 1.新闻 2专题 3直播if("1".equals(type)){tv_type.setText("评论:"+newsItem.getCommentCount());tv_type.setBackgroundColor(Color.TRANSPARENT);tv_type.setTextColor(Color.BLACK);}else if("2".equals(type)){tv_type.setText("专题");tv_type.setBackgroundColor(Color.RED);tv_type.setTextColor(Color.WHITE);}else if("3".equals(type)){tv_type.setText("直播");tv_type.setBackgroundColor(Color.BLUE);tv_type.setTextColor(Color.WHITE);}return view;}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}}}
    
  3. 业务bean

    NewsItem.java

    /*** 新闻信息*/
    public class NewsItem {//新闻标题private String title;//新闻描述private String desc;//图片路径private String imagePath;//新闻类型private String type;//新闻的评论个数private int commentCount;public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}public String getImagePath() {return imagePath;}public void setImagePath(String imagePath) {this.imagePath = imagePath;}public String getType() {return type;}public void setType(String type) {this.type = type;}public int getCommentCount() {return commentCount;}public void setCommentCount(int commentCount) {this.commentCount = commentCount;}
    }
    
  4. 业务类,解析XML NewsInfoParser

    XML数据格式

    news.xml

        <?xml version="1.0" encoding="UTF-8" ?> <channel><item><title>国家</title> <description>国家</description><image>http://192.168.1.109:8080/img/a.jpg</image><type>1</type><comment>163</comment></item> <item><title>国家2</title> <description>国家2</description><image>http://192.168.1.109:8080/img/b.jpg</image><type>2</type></item><item><title>国家3</title> <description>国家3</description><image>http://192.168.1.109:8080/img/c.jpg</image><type>3</type></item><item><title>国家4</title> <description>国家3</description><image>http://192.168.1.109:8080/img/d.jpg</image><type>1</type><comment>763</comment></item></channel>
    

    NewsInfoParser

        /*** 业务类, 用来解析新闻的信息* @author Administrator*/public class NewsInfoParser {/*** 解析xml文件的流 获取全部的新闻信息* @param is 从服务器获取的xml文件的输入流* @return*/public static List<NewsItem> getAllNewsInfos(InputStream is) throws Exception {List<NewsItem> newsItems = null;// 新闻对象的集合NewsItem newsItem = null;// 某一个新闻对象// 1.获取xml文件的解析器XmlPullParser parser = Xml.newPullParser();// 2.初始化xml文件的解析器parser.setInput(is, "utf-8");// 3.解析xml文件int type = parser.getEventType();while (type != XmlPullParser.END_DOCUMENT) {switch (type) {case XmlPullParser.START_TAG:if ("channel".equals(parser.getName())) {// 说明解析到了 最根部的标签节点newsItems = new ArrayList<NewsItem>();} else if ("item".equals(parser.getName())) {newsItem = new NewsItem();} else if ("title".equals(parser.getName())) {newsItem.setTitle(parser.nextText());} else if ("description".equals(parser.getName())) {newsItem.setDesc(parser.nextText());} else if ("image".equals(parser.getName())) {newsItem.setImagePath(parser.nextText());} else if ("type".equals(parser.getName())) {newsItem.setType(parser.nextText());} else if ("comment".equals(parser.getName())) {String countstr = parser.nextText();if (TextUtils.isDigitsOnly(countstr)) {newsItem.setCommentCount(Integer.parseInt(countstr));}}break;case XmlPullParser.END_TAG://判断如果是走到了一个item的结束标签.说明一个item的数据已经准备好了.添加到集合if("item".equals(parser.getName())){newsItems.add(newsItem);//把当前的新闻对象加入到集合里面}break;}type = parser.next();}return newsItems;}
    }
    
  5. 条目布局 news_item

    news_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content" ><com.itheima.newsclient.SmartImageViewandroid:id="@+id/iv_img"android:layout_width="72dip"android:layout_height="53dip"android:layout_marginLeft="3dip"android:layout_centerVertical="true"android:src="@drawable/b" /><TextViewandroid:id="@+id/tv_title"android:singleLine="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="3dip"android:layout_marginTop="5dip"android:layout_toRightOf="@id/iv_img"android:text="我是新闻的标题"android:textColor="#000000"android:textSize="18sp" /><TextViewandroid:id="@+id/tv_desc"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/tv_title"android:layout_marginLeft="3dip"android:layout_marginTop="2dip"android:layout_toRightOf="@id/iv_img"android:lines="2"android:text="我是新闻的描述,不拉不拉不不拉不拉不不拉不拉不不拉不拉不不拉不拉不不拉不拉不不拉不拉不不拉不拉不不拉不拉不不拉不拉不"android:textColor="#99000000"android:textSize="12sp" /><TextViewandroid:id="@+id/tv_type"android:text="专题"android:background="#ff0000"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/tv_desc"android:layout_alignParentRight="true"android:textColor="#99000000"android:textSize="10sp" /></RelativeLayout>
    

断点下载

        public class MainActivity extends Activity {private EditText et_path;private EditText et_thread_count;private String path;// 总的线程的个数private int totalThreadCount;/*** 正在运行的线程的数量*/private int runningThreadCount;private LinearLayout ll_container;private List<ProgressBar> pbs;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_path = (EditText) findViewById(R.id.et_path);et_thread_count = (EditText) findViewById(R.id.et_threadcount);ll_container = (LinearLayout) findViewById(R.id.ll_container);}public void download(View view) {path = et_path.getText().toString().trim();String str_count = et_thread_count.getText().toString().trim();totalThreadCount = Integer.parseInt(str_count);ll_container.removeAllViews();//删除旧的pbs = new ArrayList<ProgressBar>();for(int i= 0;i<totalThreadCount;i++){//有几个线程 就创建几个进度条ProgressBar pb = (ProgressBar) View.inflate(this, R.layout.pb, null);ll_container.addView(pb);pbs.add(pb);}new Thread() {public void run() {try {// 推荐大家使用exe文件作为下载测试的文件URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");int code = conn.getResponseCode();if (code == 200) {int length = conn.getContentLength();System.out.println("服务器文件的长度为:" + length);RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+getDownLoadFileName(path), "rw");// 在本地创建一个空文件大小和服务器的文件大小保持一致raf.setLength(length);raf.close();int blocksize = length / totalThreadCount;// 把服务器的资源等分成3份// 每一份的大小System.out.println("每一份:" + blocksize);runningThreadCount = totalThreadCount;for (int threadid = 0; threadid < totalThreadCount; threadid++) {int startPosition = threadid * blocksize;int endPosition = (threadid + 1) * blocksize - 1;if (threadid == (totalThreadCount - 1)) {endPosition = length - 1;}System.out.println("线程理论:" + threadid + "下载的范围:"+ startPosition + "~~" + endPosition);// 开启子线程,让每个子线程下载对应位置的数据..new DownloadThread(threadid, startPosition, endPosition).start();}}} catch (Exception e) {e.printStackTrace();}};}.start();}public class DownloadThread extends Thread {/*** 线程id*/private int threadid;/*** 当前线程下载的开始位置*/private int startPosition;/*** 当前线程下载的结束位置*/private int endPosition;/*** 当前线程下载的进度的总大小*/private int threadTotal;/*** 上一次下载的总大小*/private int lastdownloadTotalSize;public DownloadThread(int threadid, int startPosition, int endPosition) {this.threadid = threadid;this.startPosition = startPosition;this.endPosition = endPosition;threadTotal = endPosition - startPosition;pbs.get(threadid).setMax(threadTotal);//设置当前线程的进度条的总大小}@Overridepublic void run() {System.out.println("线程:" + threadid + "开始工作了");// 让当前线程下载自己对应范围的数据try {// 判断是否已经下载过一部分的数据.File finfo = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+totalThreadCount+ getDownLoadFileName(path) + threadid + ".txt");if (finfo.exists() && finfo.length() > 0) {FileInputStream fis = new FileInputStream(finfo);BufferedReader br = new BufferedReader(new InputStreamReader(fis));String lastposition = br.readLine();// 这个线程上一次下载的大小int intlastposition = Integer.parseInt(lastposition);lastdownloadTotalSize = intlastposition - startPosition;startPosition = intlastposition;fis.close();}URL url = new URL(path);HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET");System.out.println("线程真实下载开始和结束:" + threadid + "下载的范围:"+ startPosition + "~~" + endPosition);conn.setRequestProperty("Range", "bytes=" + startPosition + "-"+ endPosition);// 从服务器下载资源.int code = conn.getResponseCode(); // 206 请求部分数据成功if (code == 206) {InputStream is = conn.getInputStream();RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+getDownLoadFileName(path), "rw");// ★ 非常重要指定文件写的开始位置raf.seek(startPosition);byte[] buffer = new byte[1024];int len = -1;int total = 0;// 当前线程这一次下载了多少的数据while ((len = is.read(buffer)) != -1) {raf.write(buffer, 0, len);// 把当前下载的位置记录下来.total += len;RandomAccessFile inforaf = new RandomAccessFile(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+totalThreadCount + getDownLoadFileName(path)+ threadid + ".txt", "rwd");// 每一次更新// 数据都被同步到底层硬盘// 存当前线程已经下载到了哪个位置inforaf.write(String.valueOf(startPosition + total).getBytes());inforaf.close();pbs.get(threadid).setProgress(total+lastdownloadTotalSize);}is.close();raf.close();System.out.println("线程:" + threadid + "下载完毕了...");}} catch (Exception e) {e.printStackTrace();} finally {synchronized (MainActivity.this) {runningThreadCount--;if (runningThreadCount <= 0) {System.out.println("多线程下载完毕.");for (int i = 0; i < totalThreadCount; i++) {File f = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/"+totalThreadCount+ getDownLoadFileName(path) + i + ".txt");System.out.println(f.delete());}}}}}}/*** 根据路径获取文件名* * @param path* @return*/public String getDownLoadFileName(String path) {return path.substring(path.lastIndexOf("/") + 1);}}

断点下载开源框架 afinal-master

afinal_0.5.1_bin

            public void download(View view) {path = et_path.getText().toString().trim();if (TextUtils.isEmpty(path) && !path.startsWith("http://")) {Toast.makeText(this, "下载路径不合法", 0).show();return;}FinalHttp fh = new FinalHttp();  fh.download(path, "/mnt/sdcard/haha.exe", true, new AjaxCallBack<File>() {@Overridepublic void onLoading(long count, long current) {pb.setMax((int) count);pb.setProgress((int) current);super.onLoading(count, current);}@Overridepublic void onSuccess(File t) {Toast.makeText(MainActivity.this, "下载成功", 0).show();super.onSuccess(t);}@Overridepublic void onFailure(Throwable t, int errorNo, String strMsg) {System.out.println(strMsg);super.onFailure(t, errorNo, strMsg);}});}

Activity

意图Intent

AndroidManifest.xml

    <activityandroid:name="com.itheima.intent.SecondActivity"android:label="@string/title_activity_second" ><intent-filter ><action android:name="com.itheima.intent.open02"/>//1. 设置数据的类型<data android:mimeType="text/plain"></data>//2. 设置数据的格式<data android:scheme="http"android:host="www.itheima.com"android:port="8080"android:path="/java"></data><category android:name="android.intent.category.DEFAULT"/></intent-filter></activity>
</application>

显式意图

方式一:

        /*** 显式意图点击按钮开启第二个界面* 激活自己应用程序的里面的界面* @param view*/public void click01(View view) {Intent intent = new Intent(this,SecondActivity.class);startActivity(intent);}

方式二:

        Intent intent = new Intent();intent.setClassName("com.itheima.intent","com.itheima.intent.SecondActivity");//类名必须是全路径startActivity(intent);

隐式意图

        /*** 隐式意图点击按钮开启第二个界面* 开启更加灵活,精准,并且可以携带匹配的数据* @param view*/public void click02(View view) {Intent intent = new Intent();intent.setAction("com.itheima.intent.open02");//1. 设置数据的类型intent.setType("text/plain");//2. 设置数据的格式intent.setData(Uri.parse("http://www.itheima.com:8080/java"));intent.addCategory("android.intent.category.DEFAULT");startActivity(intent);}

页面间的数据传递

设置intent的数据

MainActivity.java

    //声明一个意图对象Intent intent = new Intent();//Serializable  序列化到硬盘 自己实现的序列化的类//Parcelable 序列化到内存 bitmapintent.putExtra("name", name);//传递是 字符串intent.putExtra("key",value);//传递是int类型的数据//使用Bundle传递一个map集合Bundle extras = new Bundle();extras.putChar(key, value)intent.putExtras(extras);

获取数据

SecondActivity.java

    Intent intent = getIntent();//获取激活当前页面的意图对象intent.getStringExtra();intent.getIntExtra();intent.getDoubleExtra();...intent.getExtras();

隐式意图的应用

浏览器示例代码:

activity_main.xml

    <WebViewandroid:layout_below="@id/et_path"android:id="@+id/wv"android:layout_width="fill_parent"android:layout_height="fill_parent" />

MainActivity.java

    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);et_path = (EditText) findViewById(R.id.et_path);iv_go = (ImageView) findViewById(R.id.iv_go);wv = (WebView) findViewById(R.id.wv);Intent intent = getIntent();if (intent != null) {if (intent.getData() != null) {//获取其他应用传递的数据//intent.setData(Uri.parse("http://xxxx.com"));String path = intent.getData().toString();wv.loadUrl(path);et_path.setText(path);}}iv_go.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {String path = et_path.getText().toString().trim();wv.loadUrl(path);}});}

AndroidManifest.xml

        <activityandroid:name="com.itheima.superbrowser.MainActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><!-- 分拣系统,匹配当前的Activity可以用来打开网页 --><intent-filter><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><data android:scheme="http" /><data android:scheme="https" /><data android:scheme="about" /><data android:scheme="javascript" /></intent-filter></activity>

请求码和结果码

AndroidManifest.xml

        <applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name="com.itheima.request_result_code.MainActivity"android:label="@string/app_name" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><activityandroid:name="com.itheima.request_result_code.ChooseSexActivity"android:label="请选择性别"android:theme="@android:style/Theme.Dialog" ></activity><activityandroid:name="com.itheima.request_result_code.ChooseHeadActivity"android:label="请选择头像"android:theme="@android:style/Theme.Dialog" ></activity></application>

MainActivity.java

        public class MainActivity extends Activity {public static final int CHOOSE_SEX = 1;public static final int CHOOSE_IMAGE = 2;private TextView tv_sex;private ImageView iv_head;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv_sex = (TextView) findViewById(R.id.tv_sex);iv_head = (ImageView) findViewById(R.id.iv_head);}/*** 选择性别* @param view*/public void openSexChooseActivity(View view) {// 显式意图Intent intent = new Intent(this, ChooseSexActivity.class);startActivityForResult(intent, CHOOSE_SEX);}/*** 选择头像* @param view*/public void openHeadImageChooseActivity(View view) {// 显式意图Intent intent = new Intent(this, ChooseHeadActivity.class);startActivityForResult(intent, CHOOSE_IMAGE);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (data != null) {if(resultCode==CHOOSE_SEX){String sex = data.getStringExtra("sex");tv_sex.setText("您选择的性别为:" + sex);}else if(resultCode==CHOOSE_IMAGE){//返回图片资源Bitmap bitmap = data.getParcelableExtra("headbitmap");iv_head.setImageBitmap(bitmap);}}super.onActivityResult(requestCode, resultCode, data);}}

ChooseHeadActivity.java

        @Overridepublic void onClick(View v) {Intent data = new Intent();switch (v.getId()) {case R.id.iv_e0:data.putExtra("headbitmap", BitmapFactory.decodeResource(getResources(), R.drawable.e0));break;case R.id.iv_e1:data.putExtra("headbitmap", BitmapFactory.decodeResource(getResources(), R.drawable.e1));break;case R.id.iv_e2:data.putExtra("headbitmap", BitmapFactory.decodeResource(getResources(), R.drawable.e2));break;case R.id.iv_e3:data.putExtra("headbitmap", BitmapFactory.decodeResource(getResources(), R.drawable.e3));break;}setResult(MainActivity.CHOOSE_IMAGE, data);finish();}

ChooseSexActivity.java

        /***lv.setAdapter(new ArrayAdapter<T>(context, resource, objects));*/public class ChooseSexActivity extends Activity {private ListView lv;String[] objects = {"男","女","未知"};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_choose);lv = (ListView) findViewById(R.id.lv);  //使用ArrayAdapterlv.setAdapter(new ArrayAdapter<String>(this, R.layout.item_textview, objects));lv.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {String sex = objects[position];Intent data = new Intent();data.putExtra("sex", sex);//把数据设置到意图对象里面setResult(MainActivity.CHOOSE_SEX, data);finish();//关闭当前的界面  ★一定记得关闭界面,数据才会被返回}});}}/***lv.setAdapter(new SimpleAdapter(context, data, resource, from, to));*/public class ContactListActivity extends Activity {private ListView lv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_listcontact);lv = (ListView) findViewById(R.id.lv);List<Map<String, String>> data = new ArrayList<Map<String,String>>();for(int i=0;i<10;i++){Map<String, String> map = new HashMap<String, String>();map.put("name", "张三"+i);map.put("phone", "1000"+i);data.add(map);}lv.setAdapter(new SimpleAdapter(this, data, R.layout.item_contact, new String[]{"name","phone"}, new int[]{R.id.tv_name,R.id.tv_phone}));lv.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {String number = "1000"+position;Intent data = new Intent();data.putExtra("number", number);setResult(MainActivity.GET_PHONE, data);finish();}});}}

横竖屏切换的生命周期(ctrl+F11)

AndroidManifest.xml

  • 屏幕朝向
  • android:screenOrientation=”landscape” 横屏
    android:screenOrientation=”portrait” 竖屏
  • 忽略屏幕切换

    android:configChanges="orientation|keyboardHidden|screenSize" 方向/键盘/屏幕大小
    

启动模式和任务栈

AndroidManifest.xml

    android:launchMode="standard|singletop|singleTask|singleInstance"

* standard 默认的启动模式,标准模式(01,02)

01,01,02,02,01,02

  • singletop 单一顶部模式(02顶部不启动)

    01,01,02,01,02

    • 案例: 浏览器的书签
    • 目的: 避免奇怪的用户体验(避免被恶意程序开启多次)
  • singleTask 单一任务栈(一个任务栈02唯一)

    01,02,01,01,01,01

    01,02

    • 案例: 浏览器的BrowserActivity,应用程序的主界面
    • 目的: Activity非常笨重(内存开销非常大)
  • singleInstance 单一实例(独占任务栈02唯一)

    01,01,01,01,01

    02

    • 案例: 有道词典的快速取词,电话呼叫InCallScreen
    • 目的: 操作系统中唯一存在

广播接收者

广播接收者的代码是运行在主线程

    System.out.println(Thread.currentThread().getName());//当前线程名称

接收广播

MyBroadcastReceiver.java

        /*** 1.买个收音机,继承BroadcastReceiver,* 从写onReceive方法,用来接收消息的.*/public class MyBroadcastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context arg0, Intent arg1) {//打电话广播  System.out.println("有新的电话别打出来了....");String number = getResultData();// 获取当前的结果数据, 数据就是外拨的电话号码SharedPreferences sp = context.getSharedPreferences("config",Context.MODE_PRIVATE);//有序广播//abortBroadcast();//无效的.//setResultData(null);//使外拨电话为nullif (number.startsWith("0")) {setResultData(sp.getString("ipnumber", "") + number);}//收短信广播Object[] objs  = (Object[]) intent.getExtras().get("pdus");//pdu 短信二进制数据报文for(Object obj:objs){SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) obj);String sender = smsMessage.getOriginatingAddress();String body = smsMessage.getMessageBody();System.out.println("sender:"+sender);System.out.println("body:"+body);abortBroadcast();//拦截广播跟清单文件的android:priority="1000"参数配合使用}}}

AndroidManifest.xml

    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/><!-- 2.装配电池 --><receiver android:name="com.itheima.receiverdemo.MyBroadcastReceiver" ><!-- 3.调频道 fm934,监听的是新的外拨电话 --><intent-filter android:priority="1000">//优先级<!-- 打电话的广播接收者,有序广播--><action android:name="android.intent.action.NEW_OUTGOING_CALL"/><!-- SD卡的广播接收者--><action android:name="android.intent.action.MEDIA_UNMOUNTED"/><action android:name="android.intent.action.MEDIA_MOUNTED"/><data android:scheme="file"/><!-- 短信的广播接收者,有序广播--><action android:name="android.provider.Telephony.SMS_RECEIVED"/>//卸载<action android:name="android.intent.action.PACKAGE_REMOVED"/>//安装<action android:name="android.intent.action.PACKAGE_ADDED"/><data android:scheme="package"/></intent-filter></receiver>

代码注册广播接收者

  • 广播事件产生的很频繁,屏幕锁屏, 屏幕解锁, 电量变化,这些广播事件在清单文件中注册就不可用

MainActivity.java

        public class MainActivity extends Activity {private ScreenStatusReceiver receiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);receiver = new ScreenStatusReceiver();IntentFilter filter = new IntentFilter();filter.addAction("android.intent.action.SCREEN_OFF");filter.addAction("android.intent.action.SCREEN_ON");getApplicationContext().registerReceiver(receiver, filter);//      Intent intent = new Intent(this,TestService.class);//      startService(intent);}@Overrideprotected void onDestroy() {//this.unregisterReceiver(receiver);super.onDestroy();}}

ScreenStatusReceiver.java

        public class ScreenStatusReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if("android.intent.action.SCREEN_ON".equals(action)){Toast.makeText(context, "屏幕解锁了", 0).show();System.out.println("屏幕解锁了");}else if("android.intent.action.SCREEN_OFF".equals(action)){Toast.makeText(context, "屏幕被锁定了", 0).show();System.out.println("屏幕被锁定了");} }}

TestService.java

        public class TestService extends Service {private ScreenStatusReceiver receiver;@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {receiver = new ScreenStatusReceiver();IntentFilter filter = new IntentFilter();filter.addAction("android.intent.action.SCREEN_OFF");filter.addAction("android.intent.action.SCREEN_ON");this.registerReceiver(receiver, filter);super.onCreate();}@Overridepublic void onStart(Intent intent, int startId) {super.onStart(intent, startId);}@Overridepublic void onDestroy() {unregisterReceiver(receiver);super.onDestroy();}}

发送广播

自定义无序广播

MainActivity.java

        /*** 对外发送无序广播*/public void click(View view){Intent intent = new Intent();intent.setAction("com.itheima.cctv.XXMLZY");intent.putExtra("money", "5毛");sendBroadcast(intent);}

自定义有序广播

MainActivity.java (com.itheima.sendredheaddoc)

        /*** 中央发送一个红头文件,文件是一级一级向下传达的.* * @param view*/public void click(View view) {Intent intent = new Intent();intent.setAction("com.itheima.redheaddoc.BTNM");//intent 意图. 自定义广播的意图//receiverPermission//resultReceiver 内线,作为最后一个接受广播消息的人//scheduler 写null//initialCode 初始化的编码 1号文件NeiXianReceiver receiver = new NeiXianReceiver();sendOrderedBroadcast(intent, null, receiver,null, 1, "给每个农民补贴10000块钱", null);}

NeiXianReceiver.java (com.itheima.sendredheaddoc)

        public class NeiXianReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {System.out.println("我是卧底:我在村里面获取到了消息:"+getResultData());}}

Service服务

本地服务

startService(intent)方式开启服务

案例-电话窃听器

PhoneStatusService.java

    /*** 服务和Activity都拥有相同的父类, context上下文* 长期后台运行,没有界面的组件,监视用户电话的通话状态.**/public class PhoneStatusService extends Service {/*** 电话管理器 系统底层提供给我们的一个服务*/private TelephonyManager  tm;/*** 声明一个录音机*/private MediaRecorder mediaRecorder;@Overridepublic IBinder onBind(Intent intent) {return null;}//服务被创建@Overridepublic void onCreate() {System.out.println("服务被创建了");//获取android系统里面内置的服务,长期后台运行,没有界面tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);//监听系统电话呼叫的状态,第一个参数是一个监听器对象tm.listen(new MyPhoneListener(), PhoneStateListener.LISTEN_CALL_STATE);super.onCreate();}//服务被销毁@Overridepublic void onDestroy() {System.out.println("服务被销毁了.");super.onDestroy();}private class MyPhoneListener extends PhoneStateListener{//当呼叫状态变化调用的方法//state 电话的状态//incomingNumber 来电号码@Overridepublic void onCallStateChanged(int state, String incomingNumber) {super.onCallStateChanged(state, incomingNumber);switch (state) {case TelephonyManager.CALL_STATE_IDLE://当前手机处于空闲状态,没有接打电话System.out.println("手机处于空闲状态");if(mediaRecorder!=null){mediaRecorder.stop();mediaRecorder.release();mediaRecorder = null;System.out.println("窃听完毕,上传音频文件到服务器");}break;case TelephonyManager.CALL_STATE_RINGING://响铃状态,有人给手机打电话System.out.println("手机处于零响状态,准备一个录音机");break;case TelephonyManager.CALL_STATE_OFFHOOK://接通电话System.out.println("手机处于通话状态,开启录音机录音");startMediaRecorder(incomingNumber);break;}}}/*** 开启一个录音机 获取用户的声音* @param incomingNumber 来电电话号码*/public void startMediaRecorder(String incomingNumber) {try {//1.实例化录音机mediaRecorder = new MediaRecorder();//2.设置声音采集的音源mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//模拟器只支持mic//3.设置输出文件的格式mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);//模拟器 写默认的格式//4.设置输出的文件名称mediaRecorder.setOutputFile("mnt/sdcard/temp.3gp");//5.指定音频的编码方式mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//6.准备开始录音mediaRecorder.prepare();//7.开始录音mediaRecorder.start();} catch (Exception e) {e.printStackTrace();}}}

AndroidManifest.xml

    <applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid:name="com.itheima.phonelistener.MainActivity"android:label="@string/app_name"android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" ><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><service android:name="com.itheima.phonelistener.PhoneStatusService" ></service><receiver android:name="com.itheima.phonelistener.BootCompleteReceiver" ><intent-filter ><action android:name="android.intent.action.BOOT_COMPLETED"/></intent-filter></receiver></application>

BootCompleteReceiver.java开机启动的广播接收者

    public class BootCompleteReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {System.out.println("手机启动完毕了....");Intent i = new Intent(context,PhoneStatusService.class);context.startService(i);}}

进程的优先级

  • Android系统会尽量的长期保持每一个进程不被回收.
    The Android system tries to maintain an application process for as long as possible

    importance hierarchy 进程的优先级

    1. Foreground process 前台进程

      用户在操作的应用程序所在的进程就是前台进程

    2. Visible process 可见进程

      用户仍然可以看到界面,但是里面的按钮点击不了了.

    3. Service process 服务进程

      进程里面有一个服务正处于运行状态

    4. Background process 后台进程

      如果一个应用程序没有服务处于运行状态,界面最小化. onstop();

    5. Empty process

      应用程序没有任何活动的组件.没有服务,Activity也ondestroy了

bind方式开启服务

MainActivity.java

        public class MainActivity extends Activity {IService myBinder;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}/*** 绑定服务,获取服务里面的小蜜,间接的调用服务里面的方法。* @param view*/public void bind(View view){Intent intent = new Intent(this,DemoService.class);//intent 意图//conn 服务的通讯频道//1 服务如果在绑定的时候不存在,会自动创建System.out.println("1.采用bind的方式开启服务");bindService(intent, new MyConn(), BIND_AUTO_CREATE);}/*** 服务连接成功的通讯频道*/private class MyConn implements ServiceConnection{//当服务被成功连接的时候调用的方法@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {System.out.println("3. 得到了服务的一个连接,通讯频道,获取到服务内部的小蜜");myBinder = (IService) service;System.out.println("4.把ibinder强制类型转化成小蜜 MyBinder");}//当服务失去连接的时候调用的方法@Overridepublic void onServiceDisconnected(ComponentName name) {}}/*** 调用服务里面的方法。* @param view*/public void call(View view){System.out.println("5.利用mybinder间接的调用服务的方法");myBinder.callMethodInService(600);}}

DemoService.java

        public class DemoService extends Service {/*** 在服务被绑定的时候调用的方法* IBinder 服务内部的小蜜 */@Overridepublic IBinder onBind(Intent intent) {System.out.println("2. 服务如果成功绑定会执行onbind,返回服务内部的小蜜 mybinder");return new MyBinder();}/*** 服务内部的小蜜,可以调用服务的方法*/private class MyBinder extends Binder implements IService{/*** 调用服务的方法。* @param money 钱*/public void callMethodInService(int money){if(money>500){methodInService();}else{Toast.makeText(DemoService.this, "这点钱还想办事呀?", 0).show();}}public void 打麻将(){Toast.makeText(DemoService.this, "一起打麻将", 0).show();}public void 洗桑拿(){Toast.makeText(DemoService.this, "一起洗桑拿", 0).show();}}/*** 服务里面的方法*/public void methodInService(){Toast.makeText(this, "哈哈,我是服务的方法,被你调用了。", 0).show();}@Overridepublic void onCreate() {System.out.println("服务被创建了");super.onCreate();}@Overridepublic void onDestroy() {System.out.println("服务被销毁了。");super.onDestroy();}}

IService.java

        /*** 定义的接口,暴露一个给钱办事的方法。*/public interface IService {public void callMethodInService(int money);}

混合调用服务的生命周期处理

  • 为了保证服务长期的运行,又想调用服务的方法.
  • 一般步骤

    startService() 保证服务长期后台运行

bindService() 绑定服务 ,调用服务的方法

unbindservice() 解绑服务,不需要再去调用方法了

stopService() 停止服务

远程服务

  • IPC

    inter process communication 进程间通讯

  • AIDL
    android interface definition language 安卓接口定义语言,绑定远程服务的写法

远程服务案例

  • 支付宝APP

    AndroidManifest.xml

    <service android:name="com.itheima.alipay.AlipayService" ><intent-filter ><action android:name="com.itheima.alipay"/></intent-filter>
    </service>
    

    AlipayService.java

    public class AlipayService extends Service {private class MyBinder extends IService.Stub{@Overridepublic int callSafePay(String username, String password, float money,long timestamp) {return safePay(username, password, money, timestamp);}}@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}@Overridepublic void onCreate() {System.out.println("支付宝服务被创建了");super.onCreate();}@Overridepublic void onDestroy() {System.out.println("支付宝服务被销毁了");super.onDestroy();}/*** 安全支付的服务* @param username 用户名* @param password 密码* @param money 钱* @param timestamp 时间戳* @return 200 支付成功 404银行卡余额不足 505支付超过限额  408支付超时服务器无响应 300用户名密码错误*/public int safePay(String username,String password,float money,long timestamp){System.out.println("加密username");System.out.println("加密password");System.out.println("提交数据到支付宝的服务器");if(money>5000){return 505;//支付超过了限额}if("zhangsan".equals(username)&&"123".equals(password)){return 200;}else{return 300;}}
    }
    

    IService.java → IService.aidl (com.itheima.alipay)

    interface IService {int callSafePay(String username,String password,float money,long timestamp);
    }
    
  • 捕鱼达人APP

    IService.java → IService.aidl (com.itheima.alipay)

    interface IService {int callSafePay(String username,String password,float money,long timestamp);
    }
    

    MainActivity.java

    public class MainActivity extends Activity {private MyConn conn;private IService  iService;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Intent intent = new Intent();//采用隐式意图intent.setAction("com.itheima.alipay");conn = new MyConn();bindService(intent, conn, BIND_AUTO_CREATE);}private class MyConn implements ServiceConnection{@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {System.out.println("成功绑定到远程alipay服务上");iService = IService.Stub.asInterface(service);}@Overridepublic void onServiceDisconnected(ComponentName name) {}}/*** 调用远程服务的方法,支付2块钱.* @param view*/public void click(View view){try {//200 支付成功 404银行卡余额不足 505支付超过限额  408支付超时服务器无响应 300用户名密码错误int resultcode = iService.callSafePay("zhangsan", "123", 2.00f, System.currentTimeMillis());switch (resultcode) {case 200:Toast.makeText(this, "支付成功", 0).show();break;case 404:Toast.makeText(this, "银行卡余额不足", 0).show();break;case 300:Toast.makeText(this, "用户名密码错误", 0).show();break;}} catch (Exception e) {e.printStackTrace();}}
    }
    

利用通知栏提醒提升服务优先级

MainActivity.java

        public class MainActivity extends Activity {private NotificationManager nm;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);}public void click(View view){//链式调用.//       Notification noti = new Notification.Builder(this)//         .setContentTitle("我是通知的标题栏")//         .setContentText("我是通知栏的内容")//         .setSmallIcon(R.drawable.ic_launcher)//         .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher))//         .build(); //      nm.notify(0, noti);//向下兼容的写法Notification noti = new  Notification(R.drawable.ic_launcher, "通知到来了", System.currentTimeMillis());noti.flags = Notification.FLAG_NO_CLEAR;//设置点击后开启的事件//PendingIntent 进程间通讯用的可以序列号的类,适合做进程间的通讯.行为是由另外的一个应用程序执行Intent intent = new Intent();intent.setAction(Intent.ACTION_CALL);intent.setData(Uri.parse("tel://110"));PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent,  Intent.FLAG_ACTIVITY_NEW_TASK);noti.setLatestEventInfo(this, "我是大标题", "我是描述的文本", contentIntent);nm.notify(0, noti);}}

TestService.java

    public class TestService extends Service {@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic void onCreate() {//变成了 前台 进程 优先级最高. 不会被系统回收.startForeground(0, notification);super.onCreate();}@Overridepublic void onDestroy() {// TODO Auto-generated method stubsuper.onDestroy();}}

综合案例-音乐播放器

MainActivity.java

    public class MainActivity extends Activity {private MyConn conn;private IMusicService iMusicService;private MusicService musicService;private EditText et_path;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);et_path = (EditText) findViewById(R.id.et_path);//保证服务长期后台运行。Intent intent = new Intent(this,MusicService.class);startService(intent);//调用服务的方法。conn = new MyConn();bindService(intent, conn, BIND_AUTO_CREATE);}private class MyConn implements ServiceConnection{@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {iMusicService = (IMusicService) service;musicService = iMusicService.callGetMusicService();}@Overridepublic void onServiceDisconnected(ComponentName name) {}}public void play(View view){String path = et_path.getText().toString().trim();if(TextUtils.isEmpty(path)){Toast.makeText(this, "路径不合法", 0).show();return;}musicService.setMusic(path);boolean result = musicService.play();if(!result){Toast.makeText(this, "播放失败,请检查路径,或者音乐文件是否合法", 0).show();}}public void pause(View view){musicService.pause();}public void resume(View view){musicService.resume();}public void stop(View view){musicService.stop();}@Overrideprotected void onDestroy() {unbindService(conn);super.onDestroy();}}

IMusicService.java接口返回服务的对象

    public interface IMusicService {/*** 调用获取服务的引用* @return*/public MusicService callGetMusicService();}

MusicService.java

    public class MusicService extends Service {/*** 要播放的音乐文件的路径*/private String path;private MediaPlayer mediaPlayer;/*** 音乐播放的状态*/private int PLAYING_STATUS;private int STOP = 0;private int PLAYING = 1;private int PAUSE = 2;@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}private class MyBinder extends Binder implements IMusicService {@Overridepublic MusicService callGetMusicService() {return getMusicService();}}/*** 返回服务的对象* @return*/public MusicService getMusicService() {return this;}@Overridepublic void onCreate() {System.out.println("服务被创建了。");super.onCreate();}@Overridepublic void onDestroy() {System.out.println("服务被销毁了。");super.onDestroy();}/*** 设置要播放的音乐* @param path*            音乐文件的路径*/public void setMusic(String path) {this.path = path;}/*** 播放音乐,播放之前请设置音乐的路径*/public boolean play() {if (mediaPlayer != null && mediaPlayer.isPlaying()) {mediaPlayer.stop();mediaPlayer.release();mediaPlayer = null;}try {if (path == null) {return false;}mediaPlayer = new MediaPlayer();mediaPlayer.reset();mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);mediaPlayer.setDataSource(path);mediaPlayer.prepare();mediaPlayer.start();PLAYING_STATUS = PLAYING;return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 暂停音乐*/public void pause() {if (mediaPlayer != null && mediaPlayer.isPlaying()) {mediaPlayer.pause();PLAYING_STATUS = PAUSE;}}/*** 继续开始*/public void resume() {if (mediaPlayer != null && PLAYING_STATUS == PAUSE) {mediaPlayer.start();PLAYING_STATUS = PLAYING;}}public void stop() {if (mediaPlayer != null && mediaPlayer.isPlaying()) {mediaPlayer.stop();mediaPlayer.release();mediaPlayer = null;PLAYING_STATUS = STOP;}}}

内容提供者

内容提供者编写的步骤

  • 数据库APP

    AndroidManifest.xml

    <provider android:name="com.itheima.db.MyDBContentProvider"android:authorities="com.itheima.db" >
    </provider>
    

    MyDBContentProvider.xml

    /*** 私有数据库的内容提供者,把自己数据库的内容提供给别的应用程序 在内容提供者的模板代码里面就默认定义了增删改查的方法.* 可以实现全部的方法,也可以实现部分的方法*/
    public class MyDBContentProvider extends ContentProvider {private MyDBOpenHelper helper;private static final int CONTACT_INFO_ALL = 1;private static final int CONTACT_INFO_SINGLE = 2;/*** 定义一个uri路径的匹配器, 检查uri是否合法.如果路径不合法匹配失败返回 -1,相当于保安*/private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);// 训练我们的保安,让他识别对应的路径static {// authority 主机名 路径的前缀mUriMatcher.addURI("com.itheima.db", "contactinfo", CONTACT_INFO_ALL);mUriMatcher.addURI("com.itheima.db", "contactinfo/#",CONTACT_INFO_SINGLE);// content://com.itheima.db/contactinfo -->1}/*** 当内容提供者开始创建的时候调用的方法*/@Overridepublic boolean onCreate() {helper = new MyDBOpenHelper(getContext());// activity.this// getApplicationContext()// getContext()//模拟的假的上下文return true;// 表示内容提供者成功加载}/*** @param uri*            查询的路径* @param projection*            查询数据库某个表那些列的内容* @param selection*            选择条件* @param selectionArgs*            选择条件的参数* @param sortOrder*            按什么方式排序 desc*/@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {// 判断请求是否合法.int code = mUriMatcher.match(uri);if (code == CONTACT_INFO_ALL) {// 得到一个可读的数据库SQLiteDatabase db = helper.getReadableDatabase();return db.query("contactinfo", projection, selection,selectionArgs, null, null, sortOrder);} else if (code == CONTACT_INFO_SINGLE) {content://com.itheima.db/contactinfo/3String path = uri.toString();SQLiteDatabase db = helper.getReadableDatabase();return db.query("contactinfo", projection, "id=?",new String[]{path.substring(path.lastIndexOf("/")+1)}, null, null, sortOrder);} else {// 匹配失败throw new IllegalArgumentException("暗号对错了,拖出去打一顿");}}/*** 告诉调用者数据的类型是一条 还是一组*/@Overridepublic String getType(Uri uri) {int code = mUriMatcher.match(uri);if (code == CONTACT_INFO_ALL) {return "vnd.android.cursor.dir/contanct";} else if (code == CONTACT_INFO_SINGLE) {return "vnd.android.cursor.item/contanct";} else {// 匹配失败throw new IllegalArgumentException("错误的数据类型");}}@Overridepublic Uri insert(Uri uri, ContentValues values) {// 判断请求是否合法.int code = mUriMatcher.match(uri);if (code == CONTACT_INFO_ALL) {// 得到一个可写的数据库SQLiteDatabase db = helper.getWritableDatabase();long row = db.insert("contactinfo", null, values);db.close();// content://com.itheima.db/contactinfo/103return Uri.parse("content://com.itheima.db/contactinfo/" + row);} else {// 匹配失败throw new IllegalArgumentException("暗号对错了,拖出去打一顿");}}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {// 判断请求是否合法.int code = mUriMatcher.match(uri);if (code == CONTACT_INFO_ALL) {// 得到一个可写的数据库SQLiteDatabase db = helper.getWritableDatabase();int count = db.delete("contactinfo", selection, selectionArgs);db.close();return count;} else {// 匹配失败throw new IllegalArgumentException("暗号对错了,拖出去打一顿");}}@Overridepublic int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {// 判断请求是否合法.int code = mUriMatcher.match(uri);if (code == CONTACT_INFO_ALL) {// 得到一个可写的数据库SQLiteDatabase db = helper.getWritableDatabase();int count = db.update("contactinfo", values, selection,selectionArgs);db.close();return count;} else {// 匹配失败throw new IllegalArgumentException("暗号对错了,拖出去打一顿");}}
    }
    
  • 通过后门读取数据APP

    public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}/*** 查询数据* @param view*/public void read(View view) {// 通过后门读取数据库应用私有的数据库信息// 1. 获取内容提供者的解析器ContentResolver resolver = getContentResolver();// 2.利用解析器获取私有的数据库Uri uri = Uri.parse("content://com.itheima.db/contactinfo/33");String type = resolver.getType(uri);// vnd.android.cursor.item 只有一条记录// vnd.android.cursor.dir/ 多条数据if (type.startsWith("vnd.android.cursor.dir")) {System.out.println("一组数据");Cursor cursor = resolver.query(uri, null, null, null, null);while (cursor.moveToNext()) {String id = cursor.getString(0);String name = cursor.getString(1);String phone = cursor.getString(2);System.out.println("id:" + id + "--name:" + name + "--phone:"+ phone);}cursor.close();}else if(type.startsWith("vnd.android.cursor.item")){System.out.println("一条数据");Cursor cursor = resolver.query(uri, null, null, null, null);cursor.moveToFirst();String id = cursor.getString(0);String name = cursor.getString(1);String phone = cursor.getString(2);System.out.println("id:" + id + "--name:" + name + "--phone:"+ phone);cursor.close();}}/*** 添加数据* @param view*/public void insert(View view) {// 1. 获取内容提供者的解析器ContentResolver resolver = getContentResolver();// 2.利用解析器获取私有的数据库Uri uri = Uri.parse("content://com.itheima.db/contactinfo");ContentValues values = new ContentValues();values.put("name", "李四");values.put("phone", "9999999");Uri result = resolver.insert(uri, values);Toast.makeText(this, result.toString(), 1).show();}/*** 删除数据* @param view*/public void delete(View view) {// 1. 获取内容提供者的解析器ContentResolver resolver = getContentResolver();// 2.利用解析器获取私有的数据库Uri uri = Uri.parse("content://com.itheima.db/contactinfo");int count = resolver.delete(uri, "name=?", new String[] { "李四" });Toast.makeText(this, "删除了" + count + "条记录", 0).show();}/*** 修改数据* @param view*/public void update(View view) {// 1. 获取内容提供者的解析器ContentResolver resolver = getContentResolver();// 2.利用解析器获取私有的数据库Uri uri = Uri.parse("content://com.itheima.db/contactinfo");ContentValues values = new ContentValues();values.put("phone", "66666");int count = resolver.update(uri, values, "name=?",new String[] { "李四" });Toast.makeText(this, "修改了" + count + "条记录", 0).show();}
    }
    

内容观察者

BankInfoProvider.java 在内容提供者里面设置数据变化的消息notifyChange

    getContext().getContentResolver().notifyChange(uri, null);

MainActivity.java 设置内容观察者

    public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, new MyObserver(new Handler()));}private class MyObserver extends ContentObserver{public MyObserver(Handler handler) {super(handler);}@Overridepublic void onChange(boolean selfChange) {super.onChange(selfChange);System.out.println("短信的数据库变化了。");//查询数据库。}}}

多媒体编程

加载大图片

    public class MainActivity extends Activity {private ImageView iv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);}public void click(View view) {// 这种方式把所有的像素点都加载内存,vm虚拟机扛不住.// Bitmap bitmap = BitmapFactory.decodeFile("mnt/sdcard/hh.jpg");// iv.setImageBitmap(bitmap);// 用户识别的出来的图形,受到设备的分辨率的限制.// 只要我们显示的图形比手机的分辨率高,或者跟手机分辨率一致,用户就看不出来图形的质量的缩放了.BitmapFactory.Options opts = new Options();// 解码图片的配置选项opts.inJustDecodeBounds = true;// 不去真实的解析bitmap,而是查询bitmap的宽高信息BitmapFactory.decodeFile("mnt/sdcard/hh.jpg", opts);int width = opts.outWidth;int height = opts.outHeight;System.out.println("图片宽度width:" + width);System.out.println("图片高度height:" + height);// 得到手机屏幕的宽高WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);int screenWidth = wm.getDefaultDisplay().getWidth();int screenHeight = wm.getDefaultDisplay().getHeight();System.out.println("屏幕宽度width:" + screenWidth);System.out.println("屏幕高度height:" + screenHeight);int dx = width / screenWidth;int dy = height / screenHeight;int scale = 1;if (dx > dy && dy > 1) {scale = dx;}if (dy > dx && dx > 1) {scale = dy;}System.out.println(scale);//缩放的方式把图片加载到手机内存opts.inSampleSize = scale;opts.inJustDecodeBounds = false;// 真实的解析bitmapBitmap bitmap = BitmapFactory.decodeFile("mnt/sdcard/hh.jpg", opts);iv.setImageBitmap(bitmap);}}

图片处理

    public class MainActivity extends Activity {private ImageView iv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);}public void turnBig(View view) {Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);Matrix matrix = new Matrix();matrix.setScale(2, 2);//1.买一张纸Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth()*2, bitmap.getHeight()*2, bitmap.getConfig());//2.买个画板Canvas canvas = new Canvas(newBitmap);//3.临摹作画Paint paint = new Paint();paint.setColor(Color.BLACK);canvas.drawBitmap(bitmap, matrix, paint);iv.setImageBitmap(newBitmap);}public void turnSmall(View view) {Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);Matrix matrix = new Matrix();matrix.setScale(0.5f, 0.5f);//1.买一张纸Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth()/2, bitmap.getHeight()/2, bitmap.getConfig());//2.买个画板Canvas canvas = new Canvas(newBitmap);//3.临摹作画Paint paint = new Paint();paint.setColor(Color.BLACK);canvas.drawBitmap(bitmap, matrix, paint);iv.setImageBitmap(newBitmap);}//左移public void turnleft(View view) {Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);Matrix matrix = new Matrix();dx --;matrix.setTranslate(dx, 0);//1.买一张纸Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());//2.买个画板Canvas canvas = new Canvas(newBitmap);//3.临摹作画Paint paint = new Paint();canvas.drawColor(Color.WHITE);paint.setColor(Color.BLACK);canvas.drawBitmap(bitmap, matrix, paint);iv.setImageBitmap(newBitmap);}//右移public void turnRight(View view) {Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);Matrix matrix = new Matrix();dx ++;matrix.setTranslate(dx, 0);//1.买一张纸Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());//2.买个画板Canvas canvas = new Canvas(newBitmap);//3.临摹作画Paint paint = new Paint();canvas.drawColor(Color.WHITE);paint.setColor(Color.BLACK);canvas.drawBitmap(bitmap, matrix, paint);iv.setImageBitmap(newBitmap);}//逆时针 倒转public void turnleft(View view) {Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);Matrix matrix = new Matrix();degrees--;matrix.setRotate(degrees, bitmap.getWidth(), bitmap.getHeight());matrix.postTranslate(100, 100);//1.买一张纸Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth()*2, bitmap.getHeight()*2, bitmap.getConfig());//2.买个画板Canvas canvas = new Canvas(newBitmap);//3.临摹作画Paint paint = new Paint();canvas.drawColor(Color.WHITE);paint.setColor(Color.WHITE);paint.setAntiAlias(true);//锯齿消除canvas.drawBitmap(bitmap, matrix, paint);iv.setImageBitmap(newBitmap);}//顺时针 正转public void turnRight(View view) {new Thread(){public void run() {while(true){Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);Matrix matrix = new Matrix();degrees++;matrix.setRotate(degrees, bitmap.getWidth(), bitmap.getHeight());matrix.postTranslate(30, 30);//1.买一张纸final Bitmap newBitmap = Bitmap.createBitmap((int)(bitmap.getWidth()*1.5), (int)(bitmap.getHeight()*1.5), bitmap.getConfig());//2.买个画板Canvas canvas = new Canvas(newBitmap);//3.临摹作画Paint paint = new Paint();canvas.drawColor(Color.WHITE);paint.setAntiAlias(true);//锯齿消除paint.setColor(Color.WHITE);canvas.drawBitmap(bitmap, matrix, paint);runOnUiThread(new Runnable() {@Overridepublic void run() {iv.setImageBitmap(newBitmap);}});try {Thread.sleep(20);} catch (InterruptedException e) {e.printStackTrace();}}};}.start();}//倒影public void click01(View view) {Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);Matrix matrix = new Matrix();matrix.setScale(1, -1);matrix.postTranslate(0, bitmap.getHeight());//1.买一张纸Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());//2.买个画板Canvas canvas = new Canvas(newBitmap);//3.临摹作画Paint paint = new Paint();canvas.drawColor(Color.WHITE);paint.setColor(Color.BLACK);canvas.drawBitmap(bitmap, matrix, paint);iv.setImageBitmap(newBitmap);}//镜面public void click02(View view) {Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.meinv);Matrix matrix = new Matrix();matrix.setScale(-1, 1);matrix.postTranslate(bitmap.getWidth(),0);//1.买一张纸Bitmap newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());//2.买个画板Canvas canvas = new Canvas(newBitmap);//3.临摹作画Paint paint = new Paint();canvas.drawColor(Color.WHITE);paint.setColor(Color.BLACK);canvas.drawBitmap(bitmap, matrix, paint);iv.setImageBitmap(newBitmap);}}

图片画画板

    public class MainActivity extends Activity implements OnClickListener {private ImageView iv;private Canvas canvas;private Paint paint;private Bitmap bitmap;private TextView tv_red;private TextView tv_green;private TextView tv_blue;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);tv_red = (TextView) findViewById(R.id.tv_red);tv_green = (TextView) findViewById(R.id.tv_green);tv_blue = (TextView) findViewById(R.id.tv_blue);tv_blue.setOnClickListener(this);tv_green.setOnClickListener(this);tv_red.setOnClickListener(this);int width = getWindowManager().getDefaultDisplay().getWidth();int height = getWindowManager().getDefaultDisplay().getHeight();// 1.创建一个纸bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); // 2.买个画板canvas = new Canvas(bitmap); // 3.作画canvas.drawColor(Color.WHITE);paint = new Paint();paint.setColor(Color.BLACK);paint.setStrokeWidth(20);iv.setOnTouchListener(new OnTouchListener() {int startX;int startY;@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 手指按下屏幕System.out.println("摸到");startX = (int) event.getRawX();startY = (int) event.getRawY();break;case MotionEvent.ACTION_MOVE:// 手指在屏幕上移动System.out.println("移动");int endX = (int) event.getRawX();int endY = (int) event.getRawY();canvas.drawLine(startX, startY, endX, endY, paint);// 重新初始化线的开始位置startX = (int) event.getRawX();startY = (int) event.getRawY();iv.setImageBitmap(bitmap);break;case MotionEvent.ACTION_UP:// 手指立刻屏幕之前调用的方法System.out.println("放手");break;}return true;}});}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.tv_blue:paint.setColor(Color.BLUE);Toast.makeText(this, "蓝色", 0).show();break;case R.id.tv_red:paint.setColor(Color.RED);Toast.makeText(this, "红色", 0).show();break;case R.id.tv_green:paint.setColor(Color.GREEN);Toast.makeText(this, "绿色", 0).show();break;}}public void saveImage(View view){try {File file = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");FileOutputStream stream = new FileOutputStream(file);bitmap.compress(CompressFormat.JPEG, 100, stream);stream.close();Toast.makeText(this, "保存成功", 0).show();//模拟一个sd卡被插入的事件Intent intent = new Intent();intent.setAction(Intent.ACTION_MEDIA_MOUNTED);intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()));sendBroadcast(intent);} catch (Exception e) {e.printStackTrace();Toast.makeText(this, "保存失败,请检查sd的状态", 0).show();}}}

图片调色器

activity_main.xml

     <LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center_vertical"android:orientation="horizontal" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="青" /><SeekBarandroid:max="255"android:id="@+id/sb_red"android:progress="128"android:layout_width="0dip"android:layout_height="wrap_content"android:layout_weight="1" /><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="红" /></LinearLayout>

MainActivity.java

    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);sb_red = (SeekBar) findViewById(R.id.sb_red);sb_green = (SeekBar) findViewById(R.id.sb_green);sb_blue = (SeekBar) findViewById(R.id.sb_blue);sb_alpha = (SeekBar) findViewById(R.id.sb_alpha);bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pre19);newBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());canvas = new Canvas(newBitmap);paint = new Paint();cm = new ColorMatrix();cm.set(new float[] {1, 0, 0, 0, 0,0, 1, 0, 0, 0,0, 0, 1, 0, 0,0, 0, 0, 1, 0});paint.setColorFilter(new ColorMatrixColorFilter(cm));canvas.drawBitmap(bitmap, new Matrix(), paint);sb_red.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {//拖动停止的时候调用的方法@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {int progress = seekBar.getProgress();float fred = progress/128.0f;cm.set(new float[] {//RGBαfred, 0, 0, 0, 0,0, 1, 0, 0, 0,0, 0, 1, 0, 0,0, 0, 0, 1, 0});paint.setColorFilter(new ColorMatrixColorFilter(cm));canvas.drawBitmap(bitmap, new Matrix(), paint);iv.setImageBitmap(newBitmap);}//当开始拖动的时候调用的方法@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {// TODO Auto-generated method stub}//当拖动过程中调用的方法@Overridepublic void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {}});

视频播放器

    public class MainActivity extends Activity {private SurfaceView sv;private MediaPlayer mediaplayer;private SharedPreferences sp;private SeekBar seekBar1;private Timer timer ;private TimerTask task;private ProgressBar pb;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);seekBar1 = (SeekBar) findViewById(R.id.seekBar1);pb = (ProgressBar) findViewById(R.id.pb);seekBar1.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {if(mediaplayer!=null&&mediaplayer.isPlaying()){mediaplayer.seekTo(seekBar.getProgress());}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {}});sv = (SurfaceView) findViewById(R.id.sv);sp = getSharedPreferences("config", 0);sv.getHolder().addCallback(new Callback() {@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {System.out.println("SurfaceView被销毁了");if(mediaplayer!=null&&mediaplayer.isPlaying()){int position = mediaplayer.getCurrentPosition();Editor editor = sp.edit();editor.putInt("position", position);editor.commit();mediaplayer.stop();mediaplayer.release();mediaplayer = null;timer.cancel();task.cancel();timer = null;task = null;}}@Overridepublic void surfaceCreated(SurfaceHolder holder) {System.out.println("SurfaceView被创建了");try {mediaplayer = new MediaPlayer();mediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);//设置缩放比例//mediaplayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT);mediaplayer.setDataSource("http://192.168.1.109:8080/cc.MP4");//播放视频必须设置播放的容器,通过sv得到他的holdermediaplayer.setDisplay(sv.getHolder());//mediaplayer.prepare(); // might take long! (for buffering, etc)mediaplayer.prepareAsync();//异步的准备,开子线程mediaplayer.setOnCompletionListener(new OnCompletionListener() {@Overridepublic void onCompletion(MediaPlayer mp) {Editor editor = sp.edit();editor.putInt("position", 0);editor.commit();}});mediaplayer.setOnPreparedListener(new OnPreparedListener() {//准备完毕了@Overridepublic void onPrepared(MediaPlayer mp) {pb.setVisibility(View.INVISIBLE);mediaplayer.start();int position = sp.getInt("position", 0);mediaplayer.seekTo(position);timer = new Timer();task = new TimerTask() {@Overridepublic void run() {int max = mediaplayer.getDuration();int progress = mediaplayer.getCurrentPosition();seekBar1.setMax(max);seekBar1.setProgress(progress);}};timer.schedule(task, 0, 500);}});} catch (Exception e) {e.printStackTrace();}}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {}});}@Overridepublic boolean onTouchEvent(MotionEvent event) {if(event.getAction()==MotionEvent.ACTION_DOWN){System.out.println("-------");seekBar1.setVisibility(View.VISIBLE);new Thread(){public void run() {SystemClock.sleep(3000);runOnUiThread(new Runnable() {@Overridepublic void run() {seekBar1.setVisibility(View.INVISIBLE);}});};}.start();}return super.onTouchEvent(event);}}

SoundPool

    public class MainActivity extends Activity {private SoundPool soundPool;//声音池int soundid ;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);soundid = soundPool.load(this, R.raw.alarm, 1);}public void click(View view){soundPool.play(soundid, 1.0f, 1.0f, 0, 0, 1.0f);}}

拍照

    public void click(View view) {Intent intent = new Intent();intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);file= new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); // set the image file// start the image capture IntentstartActivityForResult(intent, 0);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {Toast.makeText(this, "照片存储在:"+file.getAbsolutePath(), 0).show();super.onActivityResult(requestCode, resultCode, data);System.out.println(file.getAbsolutePath());}

录像

    public void click(View view) {Intent intent = new Intent();intent.setAction(MediaStore.ACTION_VIDEO_CAPTURE);file= new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".3gp");intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); // set the image file// start the image capture IntentstartActivityForResult(intent, 0);}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {Toast.makeText(this, "视频存储在:"+file.getAbsolutePath(), 0).show();super.onActivityResult(requestCode, resultCode, data);System.out.println(file.getAbsolutePath());}

传感器

光传感器

    public class MainActivity extends Activity {private SensorManager mSensorManager;private MyListener listener;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listener = new MyListener();//获取传感器的服务mSensorManager =  (SensorManager) getSystemService(SENSOR_SERVICE);//得到光传感器Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);mSensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);}   private class MyListener implements SensorEventListener{//当精确度变化的时候调用的方法@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}//当传感器发现数据变化的时候调用的方法@Overridepublic void onSensorChanged(SensorEvent event) {float light = event.values[0];System.out.println("当前光线强度:"+light);}}@Overrideprotected void onDestroy() {mSensorManager.unregisterListener(listener);listener = null;super.onDestroy();}}

方向传感器

    public class MainActivity extends Activity {private SensorManager mSensorManager;private MyListener listener;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listener = new MyListener();//获取传感器的服务mSensorManager =  (SensorManager) getSystemService(SENSOR_SERVICE);//得到方向传感器Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);mSensorManager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_NORMAL);}   private class MyListener implements SensorEventListener{//当精确度变化的时候调用的方法@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}//当传感器发现数据变化的时候调用的方法@Overridepublic void onSensorChanged(SensorEvent event) {//0=North, 90=East, 180=South, 270=West float angle = event.values[0];System.out.println("angle:"+angle);}}@Overrideprotected void onDestroy() {mSensorManager.unregisterListener(listener);listener = null;super.onDestroy();}}

动画

帧动画

res->drawable

  • 1.gif
  • 2.gif
  • 3.gif
  • animation-list.xml

    <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true"><itemandroid:drawable="@drawable/1"android:duration="100"/><itemandroid:drawable="@drawable/2"android:duration="100"/><itemandroid:drawable="@drawable/3"android:duration="100"/>
    </animation-list>
    
  • activity_main.xml

    <ImageViewandroid:id="@+id/iv"android:layout_width="wrap_content"android:layout_height="wrap_content"/>
    
  • MainActivity.java

    public class MainActivity extends Activity {private ImageView iv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);iv.setBackgroundResource(R.drawable.girl_ainm);AnimationDrawable anim = (AnimationDrawable) iv.getBackground();anim.start();}
    }
    

补间动画

    public class MainActivity extends Activity {private ImageView iv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);}/*** 透明度变化的动画* @param view*/public void alpha(View view) {// 完全透明0.0f->完全不透明1.0fAlphaAnimation aa = new AlphaAnimation(0.0f, 1.0f);// 动画播放2秒aa.setDuration(2000);aa.setRepeatCount(2);aa.setRepeatMode(Animation.REVERSE);iv.startAnimation(aa);}/*** 缩放动画* @param view*/public void scale(View view) {ScaleAnimation sa = new ScaleAnimation(0.0f, 2.0f, 0.0f, 2.0f,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);sa.setDuration(2000);sa.setRepeatCount(2);sa.setRepeatMode(Animation.REVERSE);iv.startAnimation(sa);}/*** 位移动画* @param view*/public void Trans(View view) {TranslateAnimation ta = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 0.5f);ta.setDuration(2000);ta.setRepeatCount(2);ta.setRepeatMode(Animation.REVERSE);iv.startAnimation(ta);}/*** 旋转动画* @param view*/public void rotate(View view) {RotateAnimation ra = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF, 0.5f);ra.setDuration(2000);ra.setRepeatCount(2);ra.setRepeatMode(Animation.REVERSE);iv.startAnimation(ra);}public void set(View view){AnimationSet set = new AnimationSet(false);TranslateAnimation ta = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 0.5f,Animation.RELATIVE_TO_SELF, -0.5f, Animation.RELATIVE_TO_SELF, 0.5f);ta.setDuration(2000);ta.setRepeatCount(2);ta.setRepeatMode(Animation.REVERSE);RotateAnimation ra = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF, 0.5f);ra.setDuration(2000);ra.setRepeatCount(2);ra.setRepeatMode(Animation.REVERSE);ScaleAnimation sa = new ScaleAnimation(0.0f, 2.0f, 0.0f, 2.0f,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);sa.setDuration(2000);sa.setRepeatCount(2);sa.setRepeatMode(Animation.REVERSE);set.addAnimation(sa);set.addAnimation(ta);set.addAnimation(ra);iv.startAnimation(set);}}

补间动画XML配置

res->anim

  • alpha.xml

        <alpha xmlns:android="http://schemas.android.com/apk/res/android"android:fromAlpha="0"android:toAlpha="1.0"android:duration="2000"android:repeatCount="2"android:repeatMode="reverse" ></alpha>
    
  • rotate.xml

        <rotate xmlns:android="http://schemas.android.com/apk/res/android"android:fromDegrees="0"android:toDegrees="360"android:duration="2000"android:repeatCount="2"android:repeatMode="reverse"android:pivotX="50%p"android:pivotY="50%p" ></rotate>
    
  • scale.xml

        <scale xmlns:android="http://schemas.android.com/apk/res/android"android:duration="2000"android:fromXScale="0.0"android:fromYScale="0.0"android:pivotX="50%"android:pivotY="50%"android:repeatCount="2"android:repeatMode="reverse"android:toXScale="2.0"android:toYScale="2.0" ></scale>
    
  • trans.xml

        <translate xmlns:android="http://schemas.android.com/apk/res/android"android:duration="2000"android:fromXDelta="-50%p"android:fromYDelta="-50%p"android:repeatCount="2"android:repeatMode="reverse"android:toXDelta="50%p"android:fillAfter="true"android:toYDelta="50%p" ></translate>
    
  • set.xml

        <set><rotatexmlns:android="http://schemas.android.com/apk/res/android"android:duration="2000"android:fromDegrees="0"android:pivotX="50%"android:pivotY="50%"android:repeatCount="2"android:repeatMode="reverse"android:toDegrees="360" ></rotate><scalexmlns:android="http://schemas.android.com/apk/res/android"android:duration="2000"android:fromXScale="0.0"android:fromYScale="0.0"android:pivotX="50%"android:pivotY="50%"android:repeatCount="2"android:repeatMode="reverse"android:toXScale="2.0"android:toYScale="2.0" ></scale><translatexmlns:android="http://schemas.android.com/apk/res/android"android:duration="2000"android:fromXDelta="-50%"android:fromYDelta="-50%"android:repeatCount="2"android:repeatMode="reverse"android:toXDelta="50%"android:toYDelta="50%" ></translate></set>
    
  • MainActivity.java

        public class MainActivity extends Activity {private ImageView iv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);}/*** 透明度变化的动画* @param view*/public void alpha(View view) {Animation aa = AnimationUtils.loadAnimation(this, R.anim.alpha);iv.startAnimation(aa);}/*** 缩放动画* @param view*/public void scale(View view) {Animation sa = AnimationUtils.loadAnimation(this, R.anim.scale);iv.startAnimation(sa);}/*** 位移动画* @param view*/public void Trans(View view) {Animation ta = AnimationUtils.loadAnimation(this, R.anim.trans);iv.startAnimation(ta);}/*** 旋转动画* @param view*/public void rotate(View view) {Animation ra = AnimationUtils.loadAnimation(this, R.anim.rotate);iv.startAnimation(ra);}public void set(View view){Animation set = AnimationUtils.loadAnimation(this, R.anim.set);iv.startAnimation(set);}}
    

属性动画

    public class MainActivity extends Activity {private ImageView iv;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = (ImageView) findViewById(R.id.iv);}/*** 透明度* @param view*/public void alpha(View view){//      iv.setAlpha(alpha);//      iv.getAlpha()ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "alpha", 0.0f,0.2f,0.4f,0.6f,0.8f,1.0f);oa.setDuration(4000);oa.setRepeatMode(ObjectAnimator.REVERSE);oa.setRepeatCount(ObjectAnimator.INFINITE);oa.start();}/*** 旋转动画* @param view*/public void rotate(View view){//iv.setRotationY(rotationY)ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "rotationX", 0.0f,30f,60.0f,90f);oa.setDuration(2000);oa.setRepeatMode(ObjectAnimator.REVERSE);oa.setRepeatCount(ObjectAnimator.INFINITE);oa.start();}/*** 缩放* @param view*/public void scale(View view){//iv.setScaleX()ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "scaleY", 0.0f,0.2f,0.5f,2.0f);oa.setDuration(2000);oa.setRepeatMode(ObjectAnimator.REVERSE);oa.setRepeatCount(ObjectAnimator.INFINITE);oa.start();}/*** 位移* @param view*/public void trans(View view){//iv.setScaleX()//iv.setTranslationX()ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "translationX", 0.0f,30f,60f,200f);oa.setDuration(2000);oa.setRepeatMode(ObjectAnimator.REVERSE);oa.setRepeatCount(ObjectAnimator.INFINITE);oa.start();}public void set(View view){System.out.println("---");//动画的集合AnimatorSet set = new AnimatorSet();ObjectAnimator oa = ObjectAnimator.ofFloat(iv, "rotation", 0.0f,30f,60.0f,90f);oa.setDuration(4000);ObjectAnimator oa2 = ObjectAnimator.ofFloat(iv, "translationX", 0.0f,10f,20,40f,60f,100f,200f,600f);oa2.setDuration(2000);//set.playSequentially(oa,oa2);set.playTogether(oa,oa2);set.start();}}

Fragment

res->layout

  • activity_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity" ><FrameLayoutandroid:id="@+id/fl_container"android:layout_width="fill_parent"android:layout_weight="1"android:layout_height="0dip" ></FrameLayout><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:background="#22000000"android:orientation="horizontal" ><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="setting01"android:text="蓝牙设置" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="setting02"android:text="声音设置" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="setting03"android:text="显示设置" /></LinearLayout>
    </LinearLayout>
    
  • blue_tooth_layout.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><TextViewandroid:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="我是蓝牙设置" />
    </LinearLayout>
    
  • show_layout.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><TextViewandroid:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="我是显示设置" />
    </LinearLayout>
    
  • sound_layout.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><TextViewandroid:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="我是声音设置" />
    </LinearLayout>
    

    src->fragement

  • MainActivity.java

    public class MainActivity extends Activity {private FragmentManager fm;BlueToothFragment f1;SoundFragment f2;ShowFragment f3;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);fm = getFragmentManager();initFragment();//事务的概念FragmentTransaction ft = fm.beginTransaction();ft.replace(R.id.fl_container, f1);ft.commit();//保证了 要么同时成功,要么同时失败}private void initFragment() {f1 = new BlueToothFragment();f2 = new SoundFragment();f3 = new ShowFragment();}//蓝牙public void setting01(View view) {//事务的概念FragmentTransaction ft = fm.beginTransaction();ft.replace(R.id.fl_container, f1);ft.commit();//保证了 要么同时成功,要么同时失败}//声音public void setting02(View view) {//事务的概念FragmentTransaction ft = fm.beginTransaction();ft.replace(R.id.fl_container, f2);ft.commit();//保证了 要么同时成功,要么同时失败}//显示public void setting03(View view) {//事务的概念FragmentTransaction ft = fm.beginTransaction();ft.replace(R.id.fl_container, f3);ft.commit();//保证了 要么同时成功,要么同时失败}
    }
    
  • BlueToothFragment.java

    public class BlueToothFragment extends Fragment {//显示Fragment的ui的@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.blue_tooth_layout, null);}
    }
    
  • ShowFragment.java

    public class ShowFragment extends Fragment {//显示Fragment的ui的@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.show_layout, null);}
    }
    
  • SoundFragment.java

    public class SoundFragment extends Fragment {//显示Fragment的ui的@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {return inflater.inflate(R.layout.sound_layout, null);}
    }
    

接口回调

  • 不同模块之间传值需要用接口回调

    ToolBarUtil.java

     public class ToolBarUtil {private List<TextView> mTextViews = new ArrayList<TextView>();public void createToolBar(LinearLayout container, String[] toolBarTitleArr, int[] iconArr) {for (int i = 0; i < toolBarTitleArr.length; i++) {TextView tv = (TextView) View.inflate(container.getContext(), R.layout.inflate_toolbar_btn, null);tv.setText(toolBarTitleArr[i]);// 动态修改textView里面的drawableTop属性tv.setCompoundDrawablesWithIntrinsicBounds(0, iconArr[i], 0, 0);int width = 0;int height = LinearLayout.LayoutParams.MATCH_PARENT;LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, height);//设置weight属性params.weight = 1;container.addView(tv, params);//保存textView到集合中mTextViews.add(tv);//设置点击事件final int finalI = i;tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//不同模块之间传值需要用接口回调//3.需要传值的地方.用接口对象调用接口方法,position = finalImOnToolBarClickListener.onToolBarClick(finalI);}});}}public void changeColor(int position) {//还原所有的颜色for (TextView tv : mTextViews) {tv.setSelected(false);}mTextViews.get(position).setSelected(true);//通过设置selected属性,控制为选中效果}//1.创建接口和接口方法public  interface  OnToolBarClickListener{void onToolBarClick(int position);}//2.定义接口变量OnToolBarClickListener mOnToolBarClickListener;//4.暴露一个公共的方法public void setOnToolBarClickListener(OnToolBarClickListener onToolBarClickListener) {mOnToolBarClickListener = onToolBarClickListener;}
    }
    

    MainActivity.java

    //为mToolBarUtil设置setOnToolBarClickListener监听
    mToolBarUtil.setOnToolBarClickListener(new ToolBarUtil.OnToolBarClickListener() {@Override//position = finalIpublic void onToolBarClick(int position) {mMainViewpager.setCurrentItem(position);}
    });
    

Android 基础相关推荐

  1. Android基础新手教程——1.5.2 Git之使用GitHub搭建远程仓库

    Android基础新手教程--1.5.2 Git之使用GitHub搭建远程仓库 标签(空格分隔): Android基础新手教程 本节引言: 在上一节中.我们学习了怎样使用Git.构建我们的本地仓库.轻 ...

  2. android intent 源码,Android 基础之 IntentService 源码

    Android 基础之 IntentService 源码 Android,IntentService,源码 IntentService 位于 android.app 包下面,是 Service 的一个 ...

  3. 【Android基础】动画

    Android里的动画分为两类,以3.0版本为分水岭. 3.0前已存在 帧动画 补间动画 3.0出现 属性动画 帧动画 顾名思义,快速切换几张图片来达到动画的效果. 建立帧动画xml Note:不要把 ...

  4. 基于Android移动终端的微型餐饮管理系统的设计与实现4——Android基础

    本章将介绍一些在开发中用到的一些常用且值得介绍的Android 基础知识和技术,包括Fragment.Slidingmenu.RecyelerView.HelloCharts框架和Ormlite框架. ...

  5. 关于android基础教程一书的初步解读后发现的一些问题

    我是一个比较固执的人..在进行android基础教程一书的初步学习之后,说实话,这本书虽然说为了照顾有需要的童鞋,提供了所有的源代码,就连我也在亲自打了好久的代码之后最后决定放弃,也偷偷懒,进行简单无 ...

  6. Android基础总结+SQlite数据库【申明:来源于网络】

    Android基础总结+SQlite数据库[申明:来源于网络] 基础总结篇之一:Activity生命周期:http://blog.csdn.net/liuhe688/article/details/6 ...

  7. Android基础教程pdf

    下载地址:网盘下载 内容简介  · · · · · · <Android基础教程>内容完整丰富,具有较强的通用性,读者都能通过<Android基础教程>快速学习Android开 ...

  8. Android基础_数据存储

    2019独角兽企业重金招聘Python工程师标准>>> Android基础_数据存储 Android数据存储的几种形式 继承SQLiteOpenHelper public class ...

  9. android各目录大小,Android 基础篇 — 放不同drawable文件夹中图片的大小

    我们接着上篇文章Android 基础篇 - 不同DPI取哪个本地文件夹中的资源 讲,文末尾提到一个问题,为什么不同drawable文件夹中的图片大小在终端设备会不一样? 1 准备 在drawable- ...

  10. Mono.Android 基础

    Mono.Android 基础 (地址) Mono.Android项目结构是 - Project+ Assets+ Resources+ drawable+ layout+ valuesResourc ...

最新文章

  1. 安卓学习-其他-文件读写
  2. NodeJS + PhantomJS 前端自动化资源监控
  3. 自定义注解实现业务分发
  4. 【转】强大的B树B+树
  5. mysql 回滚段_史上最牛分析MySQL索引机制的实现!不接受反驳
  6. c语言处理字符串函数的头文件,C语言字符处理函数 - 20131125的个人空间 - OSCHINA - 中文开源技术交流社区...
  7. vs怎么把textbox输入的实数放置变量里_方程的计算机处理96(3)_C++vs
  8. Jeecg 文件上传漏洞补丁说明
  9. 外网DNS系统外网访问及邮件系统外网域名访问问题
  10. 【网络流24题】No.4 魔术球问题 (二分+最小路径覆盖)
  11. hdu1599+floyd最小环
  12. 双边滤波及其matlab代码
  13. 客户端软件的结构思考(一)
  14. Ubuntu 16.04 升级到内核4.18 后 vmplayer 不能运行
  15. 权限控制框架 shiro
  16. 5月16日第壹简报,星期一,农历四月十六
  17. ps cs6重启计算机,Photoshop CS6 Extended软件打开电脑蓝屏该怎么办?
  18. ESP32-CAM拍照输出RGB565数据,wifi传输到stm32控制tft屏显示拍照图像
  19. 关于月亮双鱼,早已超越弱与强。
  20. esp8266设置sta失败_ESP8266 – ESP8266WiFiSTA库 – disconnect

热门文章

  1. 端午抗疫宣传公益小游戏-用Python为粽子宝宝戴口罩
  2. html如何将图片做成六边形,css画正六边形的两种方法
  3. 实时渲染:Tone Mapping 色调映射
  4. ChromeDriver/Selenium/Python浏览器自动化初体验
  5. 什么是微信防火墙_CentOS 7/8 预装的新型防火墙firewalld配置详解,你会用吗
  6. Field iMessageProvider in com.tao.springcloud.controller.SendMessageController
  7. 微信小程序多客服系统相关实现方式
  8. jupyter notebook 中的 markdown 语法
  9. MySQL 运维和第三方工具
  10. 【IPD】集成产品开发培训课程「3月4-5日」