Android 个人理财工具四:添加账单页面 下

本文考虑把账单界面整理下,实现如下图中的功能。做之前感觉应该不难,但实际做时发现排列界面布局甚至比编写程序代码还要复杂。网上搜索发现,关于这种布局的资料能用的很少,Google Demo中用的最多的就是Listview了,但本实例的界面似乎要复杂一些。

spinner和cursor如何配合使用成了完成此实例过程中的难点,本来应该很简单,但却把我郁闷坏了。

先给大家贴上最终的效果图片:

界面的xml:

XML/HTML代码

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_height="fill_parent" android:layout_width="fill_parent">
<LinearLayout android:id="@+id/LinearLayout01" android:orientation="vertical" android:layout_height="fill_parent" android:layout_width="fill_parent">
 <LinearLayout android:id="@+id/LinearLayout02" android:layout_width="wrap_content" android:layout_height="wrap_content">
 <TextView android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="选择账目" android:minWidth="80dip" android:textAppearance="?android:attr/textAppearanceLarge"></TextView>
 <EditText android:id="@+id/edittext_acctitem" android:layout_width="wrap_content" android:layout_height="wrap_content" android:width="200dip" android:maxLines="1" android:editable="false" android:cursorVisible="false"></EditText>
 </LinearLayout>
 <View android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listDivider"/>
 <LinearLayout android:id="@+id/LinearLayout03" android:layout_width="wrap_content" android:layout_height="wrap_content">
 <TextView android:id="@+id/TextView03" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="填入费用" android:minWidth="80dip" android:textAppearance="?android:attr/textAppearanceLarge"></TextView>
 <EditText android:id="@+id/Fee" android:layout_width="wrap_content" android:layout_height="wrap_content" android:numeric="decimal" android:width="160dip"></EditText>
 <TextView android:id="@+id/TextView13" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="(元)" android:textAppearance="?android:attr/textAppearanceLarge"></TextView>
 </LinearLayout>
 <View android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listDivider"/>
 <LinearLayout android:id="@+id/LinearLayout04" android:layout_height="wrap_content" android:layout_width="fill_parent">
 <TextView android:id="@+id/TextView02" android:layout_height="wrap_content" android:text="选择时间" android:layout_width="fill_parent" android:fadingEdge="horizontal" android:height="24dip" android:drawablePadding="2dip"></TextView>
 </LinearLayout> 

 <LinearLayout android:id="@+id/LinearLayout05" android:layout_width="wrap_content" android:layout_height="wrap_content">
 <TextView android:id="@+id/vdate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:width="120dip"></TextView>
 <Button android:id="@+id/BtnDate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="+" android:textStyle="bold" android:textSize="24dip" android:height="30dip" android:width="30dip"></Button>
 <TextView android:id="@+id/vtime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:width="80dip" android:gravity="center_horizontal"></TextView>
 <Button android:id="@+id/BtnTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="+" android:textStyle="bold" android:textSize="24dip"></Button>
 </LinearLayout>
 <View android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listDivider"/>
 <LinearLayout android:id="@+id/LinearLayout06" android:layout_height="wrap_content" android:layout_width="fill_parent">
 <TextView android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="账目类型" android:minWidth="80dip" android:textAppearance="?android:attr/textAppearanceLarge"></TextView> 

 <Spinner android:id="@+id/Spinner01" android:layout_height="wrap_content" android:minWidth="200dip" android:layout_width="wrap_content"></Spinner>
 </LinearLayout>
 <View android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listDivider"/>
 <TextView android:id="@+id/TextView07" android:layout_height="wrap_content" android:text="填写备注" android:layout_width="fill_parent" android:height="24dip" ></TextView>
 <EditText android:id="@+id/EditTextDESC" android:layout_width="fill_parent" android:layout_height="wrap_content" android:lines="4" android:gravity="top"></EditText>
 <View android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listDivider"/>
 <LinearLayout android:id="@+id/LinearLayout08" android:layout_height="wrap_content" android:layout_width="fill_parent">
 <Button android:id="@+id/BtnSave" android:width="160dip" android:text="保 存" android:textStyle="bold" android:textSize="24dip" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
 <Button android:id="@+id/BtnCancel" android:width="160dip" android:text="取 消" android:textStyle="bold" android:textSize="24dip" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> 

</LinearLayout>
 <View android:layout_width="fill_parent" android:layout_height="1dip" android:background="?android:attr/listDivider"/>
</LinearLayout>
</ScrollView>

下面我们来看下spinner和cursor的用法。

主要就是一个SimpleCursorAdapter。

代码如下:

Java代码

s1=(Spinner) findViewById(R.id.Spinner01);
String[] from= new String[]{"caption"};//需要显示游标里面的字段
int[] to=new int[]{android.R.id.text1};
Cursor cur=billdb.getUserid();
SimpleCursorAdapter mAdapter=new SimpleCursorAdapter(this,android.R.layout.simple_spinner_item, cur,from, to);
mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s1.setAdapter(mAdapter);

我在这儿居然搞了2天,其实写法一直没错,可是每次报未知的行 _ID。这个错误我也知道就是使用SimpleCursorAdapter 该方法的游标里面必须包括一个_ID的字段,可是我的表里面肯定有的,在我重试了无数次后发现,区分大小写,我倒!

而事实上我建表的语句是:

Java代码

db.execSQL("Create table tusers (_id integer primary key autoincrement," +
 "caption text not null)");

而我在函数getUserid 里面cursor定义是:

Java代码

public Cursor getUserid(){
 Log.v("cola","run get users cursor");
 return db.query("tusers", new String[]{"_ID", "caption" }, null, null, null, null, null); 

}

你单独测试这个cursor是没有问题的。

这都没用问题,也就是在这儿是不区分大小写的。但是如果你用这个cursor 绑定到SimpleCursorAdapter 这个里面去,一定要和建表语句的一致,不然就出错。这儿把我郁闷坏了。

上面界面布局和这个spinner 搞定后,后面就是完善代码,完善界面的功能,没有新的地方了。

在用户选择完账目,填写费用,选择时间,账目类型后就保存进数据库bills表。

附最新的代码Frm_Addbills.java:

Java代码

package com.cola.ui;
import java.util.Calendar;
import java.util.TimeZone;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.TimePickerDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.SimpleCursorAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
public class Frm_Addbills extends Activity implements OnClickListener {
 EditText edittext_acctitem,EditTextDESC,Fee;
 TextView mDate;
 TextView mTime;
 static final int RG_REQUEST = 0; 

 private int mYear;
 private int mMonth;
 private int mDay;
 private int mHour;
 private int mMinute;
 Spinner s1;
 Button BtnDate,BtnTime;
 Button BtnCancel,BtnSave; 

 BilldbHelper billdb; 

 int acctitemid=-1;
 public void onCreate(Bundle icicle) {
 super.onCreate(icicle);
 setTitle("ColaBox-添加账单");
 setContentView(R.layout.frm_addbills); 

 edittext_acctitem = (EditText)findViewById(R.id.edittext_acctitem);
 edittext_acctitem.setOnClickListener(this); 

 EditTextDESC=(EditText)findViewById(R.id.EditTextDESC);
 Fee=(EditText)findViewById(R.id.Fee); 

 BtnDate=(Button)findViewById(R.id.BtnDate);
 BtnDate.setOnClickListener(this);
 BtnTime=(Button)findViewById(R.id.BtnTime);
 BtnTime.setOnClickListener(this); 

 BtnCancel=(Button)findViewById(R.id.BtnCancel);
 BtnCancel.setOnClickListener(this);
 BtnSave=(Button)findViewById(R.id.BtnSave);
 BtnSave.setOnClickListener(this); 

 mDate = (TextView) findViewById(R.id.vdate);
 mTime = (TextView) findViewById(R.id.vtime); 

 //Calendar c=Calendar.getInstance(Locale.CHINA);
 initTime(); 

 setDatetime();
 billdb = new BilldbHelper(this);
 s1=(Spinner) findViewById(R.id.Spinner01);
 String[] from= new String[]{"caption"};
 int[] to=new int[]{android.R.id.text1};
 Cursor cur=billdb.getUserid();
 SimpleCursorAdapter mAdapter=new SimpleCursorAdapter(this,android.R.layout.simple_spinner_item, cur,from, to);
 mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
 s1.setAdapter(mAdapter); 

 }
 public boolean onCreateOptionsMenu(Menu menu) {
 super.onCreateOptionsMenu(menu);
 menu.add(0, 1, 0, "账目明细").setIcon(R.drawable.editbills);
 menu.add(0, 2, 0, "账目统计").setIcon(R.drawable.editbills2);
 menu.add(0, 3, 0, "账目报表").setIcon(R.drawable.billsum1);
 menu.add(0, 4, 0, "退 出").setIcon(R.drawable.quit); 

 return true;
 }
 public void onClick(View v) {
 if (v.equals(edittext_acctitem)) {
 Log.v("ColaBox", "cmd=edittext_acctitem");
 Intent intent = new Intent();
 intent.setClass(Frm_Addbills.this, Frm_Editacctitem.class);
 startActivityForResult(intent, RG_REQUEST);
 } else if (v.equals(BtnTime)){
 showDialog(1);
 } else if (v.equals(BtnDate)){
 showDialog(2);
 } else if (v.equals(BtnCancel)){
 cancel();
 } else if (v.equals(BtnSave)){
 save();
 } 

 }
 public boolean onOptionsItemSelected(MenuItem item) {
 //Log.v("ColaBox", "getmenuitemid=" + item.getItemId());
 switch (item.getItemId()) {
 case 1:
 return true;
 case 2: 

 return true;
 case 3:
 return true;
 case 4:
 QuitApp();
 return true;
 }
 return false;
 }
 public void QuitApp() {
 new AlertDialog.Builder(Frm_Addbills.this).setTitle("提示").setMessage(
 "确定退出?").setIcon(R.drawable.quit).setPositiveButton("确定",
 new DialogInterface.OnClickListener() {
  public void onClick(DialogInterface dialog, int whichButton) {
  billdb.close();
  finish();
  }
 }).setNegativeButton("取消",
 new DialogInterface.OnClickListener() {
  public void onClick(DialogInterface dialog, int whichButton) {
  }
 }).show();
 }
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 if (requestCode == RG_REQUEST) {
 if (resultCode == RESULT_CANCELED) {
 // setTitle("Canceled...");
 } else if (resultCode == RESULT_OK) {
 // setTitle((String)data.getCharSequenceExtra("DataKey"));
 edittext_acctitem.setText((String) data.getCharSequenceExtra("name"));
 acctitemid=Integer.parseInt((String)data.getCharSequenceExtra("id"));
 Log.v("cola","get acctitemid="+acctitemid); 

 }
 }
 } 

 private void cancel(){
 Log.v("cola","u put cancel btn");
 edittext_acctitem.setText("");
 Fee.setText("");
 acctitemid=-1;
 initTime();setDatetime();
 EditTextDESC.setText("");
 }
 private void save(){
 Log.v("cola","u put save btn");
 if (acctitemid==-1){
 new AlertDialog.Builder(this)
 .setMessage("请首先选择账目.")
 .show();
 return;
 }
 int fee=0;
 String s=Fee.getText().toString();
 int pos=s.indexOf(".");
 //Log.v("cola","i="+(s.length()-pos));
 if (pos>0){
 if (s.length()-pos<3){
 s=s+"0";
 }
 fee=Integer.parseInt(s.substring(0,pos)+s.substring(pos+1,pos+3));
 }else{
 fee=Integer.parseInt(s)*100; 

 }
 Log.v("cola","u put save btn");
 if (billdb.Bills_save(acctitemid,fee,(int)s1.getSelectedItemId(), ((TextView)mDate).getText().toString(), ((TextView)mTime).getText().toString(),EditTextDESC.getText().toString())){
 Toast.makeText(this, "保存成功.", Toast.LENGTH_SHORT).show();
 cancel();
 }else{
 Toast.makeText(this, "保存失败,请检查数据.", Toast.LENGTH_SHORT).show();
 }
 } 

 public boolean onKeyDown(int keyCode, KeyEvent event) { 

 switch (keyCode) {
 case KeyEvent.KEYCODE_BACK:
 QuitApp();
 return true; 

 }
 return false;
 }
 private void initTime(){
 Calendar c = Calendar. getInstance(TimeZone.getTimeZone("GMT+08:00"));
 mYear = c.get(Calendar.YEAR);
 mMonth = c.get(Calendar.MONTH);
 mDay = c.get(Calendar.DAY_OF_MONTH);
 mHour = c.get(Calendar.HOUR_OF_DAY);
 mMinute = c.get(Calendar.MINUTE);
 } 

 private void setDatetime(){
 mDate.setText(mYear+"-"+mMonth+"-"+mDay);
 mTime.setText(pad(mHour)+":"+pad(mMinute));
 } 

 @Override
 protected Dialog onCreateDialog(int id) {
 switch (id) {
 case 1:
 return new TimePickerDialog(this,
  mTimeSetListener, mHour, mMinute, false);
 case 2:
 return new DatePickerDialog(this,
  mDateSetListener,
  mYear, mMonth, mDay);
 }
 return null;
 }
 @Override
 protected void onPrepareDialog(int id, Dialog dialog) {
 switch (id) {
 case 1:
 ((TimePickerDialog) dialog).updateTime(mHour, mMinute);
 break;
 case 2:
 ((DatePickerDialog) dialog).updateDate(mYear, mMonth, mDay);
 break;
 }
 } 

 private DatePickerDialog.OnDateSetListener mDateSetListener =
 new DatePickerDialog.OnDateSetListener() {
 public void onDateSet(DatePicker view, int year, int monthOfYear,
  int dayOfMonth) {
 mYear = year;
 mMonth = monthOfYear;
 mDay = dayOfMonth;
 setDatetime();
 }
 };
 private TimePickerDialog.OnTimeSetListener mTimeSetListener =
 new TimePickerDialog.OnTimeSetListener() {
 public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
 mHour = hourOfDay;
 mMinute = minute;
 setDatetime();
 }
 };
 private static String pad(int c) {
 if (c >= 10)
 return String.valueOf(c);
 else
 return "0" + String.valueOf(c);
 }
}

最新的billdbhelper.java :

Java代码

package com.cola.ui;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
/**
 * Provides access to a database of notes. Each note has a title, the note
 * itself, a creation date and a modified data.
 */
public class BilldbHelper {
 private static final String TAG = "Cola_BilldbHelper";
 private static final String DATABASE_NAME = "cola.db"; 

 SQLiteDatabase db;
 Context context; 

 BilldbHelper(Context _context) {
 context=_context;
 db=context.openOrCreateDatabase(DATABASE_NAME, 0, null);
 Log.v(TAG,"db path="+db.getPath());
 } 

 public void CreateTable_acctitem() {
 try{
 db.execSQL("CREATE TABLE acctitem ("
  + "_ID INTEGER PRIMARY KEY,"
  + "PID integer,"
  + "NAME TEXT"
  + ");");
 Log.v("cola","Create Table acctitem ok");
 }catch(Exception e){
 Log.v("cola","Create Table acctitem err,table exists.");
 }
 } 

 public void CreateTable_bills() {
 try{
 db.execSQL("CREATE TABLE bills ("
  + "_ID INTEGER primary key autoincrement,"
  +" acctitemid integer,"
  + "fee integer,"
  + "userid integer,"
  + "sdate TEXT,"
  + "stime TEXT,"
  + "desc TEXT"
  + ");"); 

 Log.v("cola","Create Table acctitem ok");
 }catch(Exception e){
 Log.v("cola","Create Table acctitem err,table exists.");
 }
 } 

 public boolean Bills_save(int acctid,int fee,int userid,String date,String time,String text){
 String sql="";
 try{
 sql="insert into bills values(null,"+acctid+","+fee+","+userid+",'"+date+"','"+time+"','"+text+"')";
 db.execSQL(sql); 

 Log.v("cola","insert Table bills ok");
 return true; 

 }catch(Exception e){
 Log.v("cola","insert Table bills err="+sql);
 return false;
 }
 } 

 public void CreateTable_colaconfig() {
 try{
 db.execSQL("CREATE TABLE colaconfig ("
  + "_ID INTEGER PRIMARY KEY,"
  + "NAME TEXT"
  + ");");
 Log.v("cola","Create Table colaconfig ok");
 }catch(Exception e){
 Log.v("cola","Create Table acctitem err,table exists.");
 }
 } 

 public void CreateTable_users() {
 try{
 db.execSQL("Create table tusers (_id integer primary key autoincrement," +
  "caption text not null)");
 Log.v("cola","Create Table users ok");
 db.execSQL("insert into tusers values (null,'个人')");
 db.execSQL("insert into tusers values (null,'公司')");
 }catch(Exception e){
 Log.v("cola","Create Table tusers err,table exists.");
 }
 } 

 public void InitAcctitem() {
 try{
 //s.getBytes(encoding);
 db.execSQL("insert into acctitem values (1,null,'收入')");
 db.execSQL("insert into acctitem values (2,1,'工资')");
 db.execSQL("insert into acctitem values (9998,1,'其他')");
 db.execSQL("insert into acctitem values (0,null,'支出')");
 db.execSQL("insert into acctitem values (3,0,'生活用品')");
 db.execSQL("insert into acctitem values (4,0,'水电煤气费')");
 db.execSQL("insert into acctitem values (5,0,'汽油费')");
 db.execSQL("insert into acctitem values (9999,0,'其他')"); 

 //db.execSQL("insert into bills values(100,135,10000,'','','备注')");
 Log.v("cola","insert into ok");
 }catch(Exception e)
 {
 Log.v("cola","init acctitem e="+e.getMessage());
 } 

 }
 public void Acctitem_newitem(String text,int type){ 

 Cursor c =db.query("acctitem", new String[]{"max(_id)+1"}, "_id is not null and _id<9998", null, null, null, null);
 c.moveToFirst();
 int maxid=c.getInt(0);
 String sql="insert into acctitem values ("+maxid+","+type+",'"+text+"')";
 db.execSQL(sql);
 Log.v("cola","newitem ok text="+text+" id="+type+" sql="+sql); 

 } 

 public void Acctitem_edititem(String text,int id){
 db.execSQL("update acctitem set name='"+text+"' where _id="+id);
 Log.v("cola","edititem ok text="+text+" id="+id);
 } 

 public void Acctitem_delitem(int id){ 

 db.execSQL("delete from acctitem where _id="+id);
 Log.v("cola","delitem ok id="+id);
 } 

 public void QueryTable_acctitem(){ 

 } 

 public void FirstStart(){
 try{
 String col[] = {"type", "name" };
 Cursor c =db.query("sqlite_master", col, "name='colaconfig'", null, null, null, null);
 int n=c.getCount();
 if (c.getCount()==0){
 CreateTable_acctitem();
 CreateTable_colaconfig();
 CreateTable_bills();
 CreateTable_users();
 InitAcctitem();
 }
 //test();
 Log.v("cola","c.getCount="+n+"");  

 }catch(Exception e){
 Log.v("cola","e="+e.getMessage());
 }
 } 

 public void close(){
 db.close();
 } 

 public Cursor getParentNode(){
 return db.query("acctitem", new String[]{"_id", "name" }, "pid is null", null, null, null, "pid,_id");
 } 

 public Cursor getChildenNode(String pid){
 Log.v("cola","run getchildenNode");
 return db.query("acctitem", new String[]{"_id", "name" }, "pid="+pid, null, null, null, "_id");
 } 

 public Cursor getUserid(){
 Log.v("cola","run get users cursor");
 return db.query("tusers", new String[]{"_id", "caption" }, null, null, null, null, null);
 } 

 public String test(){
 try{
 Cursor c2 =getUserid();
 String ss="";
 c2.moveToFirst();
 while(!c2.isAfterLast()){
 ss = c2.getString(0) +", "+ c2.getString(1);
 //byte b[]=c2.getString(1).getBytes(); 

 c2.moveToNext(); 

 Log.v("cola","ss="+ss+"");
 }
 return ss;
 }catch(Exception e){
 Log.v("cola","e="+e.getMessage());
 return "err";
 }
 }
}

系列文章:

Android 个人理财工具六:显示账单明细 下

Android 个人理财工具五:显示账单明细 上

Android 个人理财工具四:添加账单页面 下

Android 个人理财工具三:添加账单页面 上

Android 个人理财工具二:使用SQLite实现启动时初始化数据

Android 个人理财工具一:项目概述与启动界面的实现

以上就Android 理财工具详情页面的开发,后续继续补充,其他功能,谢谢大家对本站的支持!

(0)

相关推荐

  • Android 个人理财工具五:显示账单明细 上

    前面我们已经将每个月的收支明细存入到SQLite的数据表中,本文将实现从SQLite的数据表中取出这些数据显示为账单明细界面. 下图是最终的效果图: 在设计该界面时我考虑过好几个方案.本来准备使用一个gridview,因为觉得名字很像我需要的东西.可是后来查了一些资料,并且做了点实验,发现和我想象的有些差距.于是采用了目前这种方式.使用Listview. 这个界面布局实际上很简单,就是上面一个表头(Linearlayout),中间一个Listview,下面是一个脚注(Linearlayout).

  • Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

    在前面几篇文章中,我们详细介绍了Android系统进程间通信机制Binder的原理,并且深入分析了系统提供的Binder运行库和驱动程序的源代码.细心的读者会发现,这几篇文章分析的Binder接口都是基于C/C++语言来实现的,但是我们在编写应用程序都是基于Java语言的,那么,我们如何使用Java语言来使用系统的Binder机制来进行进程间通信呢?这就是本文要介绍的Android系统应用程序框架层的用Java语言来实现的Binder接口了. 熟悉Android系统的读者,应该能想到应用程序框架

  • Android 个人理财工具六:显示账单明细 下

    上一节的显示账单明细 上中,账单明细的显示已经基本实现,本文主要整理下代码,实现此窗口的查询和删除功能:按下Menu菜单时弹出选择月份的窗口,可选择明细的月份:在ListView上长按可弹出确认删除的对话框,以完成删除. 下面上图: 这里面有个OnItemLongClickListener 事件,这个事件的用法如下: 首先activity 里面implements OnItemLongClickListener,然后如下面的代码所写: Java代码 // 这里listview 添加侦听事件 lv

  • 最常见的猜拳小游戏Android代码实现

    本文实例为大家分享了Android猜拳小游戏,供大家参考,具体内容如下 简单的 页面跳转 和 点击事件 的实现... --> AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.drag

  • Android Handler 机制实现原理分析

    handler在安卓开发中是必须掌握的技术,但是很多人都是停留在使用阶段.使用起来很简单,就两个步骤,在主线程重写handler的handleMessage( )方法,在工作线程发送消息.但是,有没有人想过这种技术是怎么实现的呢?下面我们一起探讨下. 先上图,让大家好理解下handler机制: handler机制示例图 上面一共出现了几种类,ActivityThread,Handler,MessageQueue,Looper,msg(Message),对这些类作简要介绍: ActivityThr

  • Android 音乐播放器的开发实例详解

    本文将引导大家做一个音乐播放器,在做这个Android开发实例的过程中,能够帮助大家进一步熟悉和掌握学过的ListView和其他一些组件.为了有更好的学习效果,其中很多功能我们手动实现,例如音乐播放的快进快退等. 先欣赏下本实例完成后运行的界面效果: 首先我们建立项目,我使用的SDK是Android2.2的,然后在XML中进行布局. 上方是一个ListView用来显示我们的音乐列表,中间是一个SeekBar可以拖动当前音乐的播放进度,之所以用SeekBar而不用ProgressBar是因为我们需

  • Android:下拉刷新+加载更多+滑动删除实例讲解

    小伙伴们在逛淘宝或者是各种app上,都可以看到这样的功能,下拉刷新和加载更多以及滑动删除,刷新,指刷洗之后使之变新,比喻突破旧的而创造出新的,比如在手机上浏览新闻的时候,使用下拉刷新的功能,我们可以第一时间掌握最新消息,加载更多是什么nie,简单来说就是在网页上逛淘宝的时候,我们可以点击下一页来满足我们更多的需求,但是在手机端就不一样了,没有上下页,怎么办nie,方法总比困难多,细心的小伙伴可能会发现,在手机端中,有加载更多来满足我们的要求,其实加载更多也是分页的一种体现.小伙伴在使用手机版QQ

  • Android 应用中插入广告的实例

    想必大家都知道,国内的Android应用基本都是免费的,那么开发者如何获得收入呢?应用中插入广告是一个比较常用的盈利手段.本文就讲解如何在Android应用中插入广告. 国内的广告平台有很多,用户数量比较多的有万普,有米,多普.下面就不一一介绍了,免得说我打广告.本文以万普为例.   1.首先去万普官网下载sdk,把sdk里面的jar包导入到项目的lib目录下.        2.修改AndroidManifest.xml文件. 确保应用具有以下几项权限: XML/HTML代码 <uses-pe

  • Android WebP 图片压缩与传输

    1. 简介 直到4g时代,流量依然是宝贵的东西.而移动网络传输中,最占流量的一种载体:图片,成为了我们移动开发者不得不关注的一个问题. 我们关注的问题,无非是图片体积和质量如何达到一个比较和谐的平衡,希望得到质量不错的图片同时体积还不能太大. 走在时代前列的谷歌给出了一个不错的答案--WebP. WebP是一种图片文件格式,在相同的压缩指标下,webp的有损压缩能比jpg小 25-34%.而在我自己的测试里,有时候能小50%. 2. 大企业背书 WebP在2010年发布第一个版本,到现在已经6年

  • Android仿微信通讯录打造带悬停头部的分组列表(上)

    一 概述 本文是Android导航分组列表系列上,因时间和篇幅原因分上下,最终上下合璧,完整版效果如下: 上部残卷效果如下:两个ItemDecoration,一个实现悬停头部分组列表功能,一个实现分割线(官方demo) 网上关于实现带悬停分组头部的列表的方法有很多,像我看过有主席的自定义ExpandListView实现的,也看过有人用一个额外的父布局里面套 RecyclerView/ListView+一个头部View(位置固定在父布局上方)实现的. 对于以上解决方案,有以下几点个人觉得不好的地方

  • Android开发之ListView、GridView 详解及示例代码

    ListView与GridView是Android开发中的常用控件,它们和Adapter配合使用能够实现很多界面效果.下面分别以实例说明ListView.GridView的用法.        1.ListView的Android开发实例 ListView 是android开发中最常用的控件之一,一般构成列表包括三个元素,ListView:用来展示列表的视图.Adapter:数据与视图连接的桥梁.Data:具体的数据包括字符串 .图片或者控件. 适配器一般有以下几种类型: ArrayAdapte

随机推荐