在这里我们要使用Android ListView来实现显示股票行情,效果图如下,红色表示股票价格上涨,绿色表示股票价格下跌。
第一步、定义color.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="color_dark_grey">#808080</color>
<color name="color_black">#000000</color>
<color name="color_green">#00FF00</color>
<color name="color_red">#FF0000</color>
<color name="color_white">#FFFFFF</color>
</resources>
第二步、定义style.xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Define the list items style begin -->
<style name="list_item_seperator_layout">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">1dip</item>
<item name="android:background">@color/color_dark_grey</item>
</style>
<style name="list_item_cell_seperator_layout">
<item name="android:layout_width">1dip</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:background">@color/color_dark_grey</item>
</style>
<!-- Define the list items style end -->
</resources>
第三步、定义ListHeader的layout文件,stock_list_header.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="3">
<TableRow
android:id="@+id/stock_list_header_row">
<View
/>
<TextView
android:id="@+id/stock_list_header_code"
android:text="@string/stock_code"
android:layout_width="60dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="2dip"
/>
<View
/>
<TextView
android:id="@+id/stock_list_header_symbol"
android:text="@string/stock_symbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="2dip"
/>
<View
/>
<TextView
android:id="@+id/stock_list_header_last_price"
android:text="@string/stock_last_price"
android:layout_width="60dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="2dip"
/>
<View
/>
<TextView
android:id="@+id/stock_list_header_price_change"
android:text="@string/stock_price_change"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="2dip"
/>
<View
/>
<TextView
android:id="@+id/stock_list_header_price_change_percentage"
android:text="@string/stock_price_change_percent"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="2dip"
/>
<View
/>
</TableRow>
</TableLayout>
</LinearLayout>
<View />是用来在每个单元格之间显示出一条垂直的分割线,使单元格之间相互分割开来。
第四步、定义ListItem的布局文件,stock_list_item.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TableLayout
android:id="@+id/stock_list_item_table_layout"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="3">
<TableRow
android:id="@+id/stock_list_row">
<View
/>
<TextView
android:id="@+id/stock_code"
android:layout_width="60dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="2dip" />
<View
/>
<TextView
android:id="@+id/stock_symbol"
android:layout_width="1dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="2dip"
/>
<View
/>
<TextView android:id="@+id/stock_last_price"
android:layout_width="60dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="2dip"
/>
<View
/>
<TextView
android:id="@+id/stock_change_price"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="2dip"
/>
<View
/>
<TextView
android:id="@+id/stock_change_percentage"
android:layout_width="50dip"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="2dip"
/>
<View
/>
</TableRow>
</TableLayout>
</LinearLayout>
第五步、定义stock list activity的layout文件stock_list.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<View
/>
<include
layout="@layout/stock_list_header"
/>
<View
/>
<ListView
android:id="@+id/stock_list_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollingCache="true"
android:cacheColorHint="#00000000"
android:fastScrollEnabled="true"
android:focusable="true"
android:divider="@color/color_dark_grey"
android:dividerHeight="1dip"
/>
</LinearLayout>
<View />是为了在Header的上下方显示一条线来分割header和list.可能有人会问,为什么这里不直接用ListView控件的header呢?
这是因为我们为了使ListView在滚动过程中header始终固定在List的最上方,不会随着ListView的滚动而消失。
到此为止,layout布局文件基本上定义完了,下面就是如何在代码中实现了。
StockListActivity.java
package com.android.msoft.mfinance.ui;
import com.android.msoft.mfinance.R;
import com.android.msoft.mfinance.provider.Stock;
import com.android.msoft.mfinance.provider.StockMarket.StockMarketColumns;
import com.android.msoft.mfinance.ui.MFinancePreferenceActivity.BGColor;
import com.android.msoft.mfinance.ui.MFinancePreferenceActivity.TextSize;
import com.android.msoft.mfinance.ui.MFinancePreferenceActivity.UpDownColor;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.WindowManager;
import android.widget.ListView;
import android.widget.TableRow;
import android.widget.TextView;
public class StockListActivity extends Activity {
private static final String TAG = "com.android.msoft.mfinance.ui.StockListActivity";
private SharedPreferences mPreference;
private TextView mCodeTextView;
private TextView mSymbolTextView;
private TextView mLastPriceTextView;
private TextView mPriceChangeTextView;
private TextView mPriceChangePercentageTextView;
private ListView mStockListView;
private TableRow mStockListHeader;
private float mTextSize;
private int mBgColor;
private int mDownTextColor;
private int mUpTextColor;
private Cursor mStockListCursor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.stock_list);
mPreference = PreferenceManager.getDefaultSharedPreferences(this);
refreshDisplayPreference();
mStockListHeader = (TableRow) findViewById(R.id.stock_list_header_row);
mCodeTextView = (TextView) findViewById(R.id.stock_list_header_code);
mSymbolTextView = (TextView) findViewById(R.id.stock_list_header_symbol);
mLastPriceTextView = (TextView) findViewById(R.id.stock_list_header_last_price);
mPriceChangeTextView = (TextView) findViewById(R.id.stock_list_header_price_change);
mPriceChangePercentageTextView = (TextView) findViewById(R.id.stock_list_header_price_change_percentage);
mStockListView = (ListView) findViewById(R.id.stock_list_view);
refreshStockListHeader();
mStockListCursor = getContentResolver().query(
Stock.CONTENT_URI_STOCK_WITH_MARKET, null, null, null,
StockMarketColumns.CHANGE_PRICE_PERCENT + " DESC");
StockListAdapter listViewAdpater = new StockListAdapter(this,
mStockListCursor);
mStockListView.setAdapter(listViewAdpater);
}
@Override
protected void onDestroy() {
if (!mStockListCursor.isClosed()) {
mStockListCursor.close();
}
super.onDestroy();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.stock_list_option_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.stock_list_option_menu_settings:
Intent intent = new Intent(this, MFinancePreferenceActivity.class);
startActivity(intent);
break;
}
return super.onOptionsItemSelected(item);
}
private void refreshDisplayPreference() {
UpDownColor upAndDownColor = MFinancePreferenceActivity.UpDownColor
.valueOf(mPreference.getString("up_down_color", "RED_GREEN"));
if (0 == upAndDownColor.value) { // UP: RED DOWN: GREEN
mUpTextColor = getResources().getColor(R.color.color_red);
mDownTextColor = getResources().getColor(R.color.color_green);
} else { // DOWN: RED UP: GREEN
mUpTextColor = getResources().getColor(R.color.color_green);
mDownTextColor = getResources().getColor(R.color.color_red);
}
TextSize textSize = MFinancePreferenceActivity.TextSize
.valueOf(mPreference.getString("text_size", "NORMAL"));
mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
textSize.value, getResources().getDisplayMetrics());
int colorResId = R.color.color_black;
BGColor bgColor = MFinancePreferenceActivity.BGColor
.valueOf(mPreference.getString("bg_color", "BLACK"));
switch (bgColor.value) {
case 0:
colorResId = R.color.color_black;
break;
case 1:
colorResId = R.color.color_white;
break;
default:
Log.e(TAG, "invalid bg color");
}
mBgColor = getResources().getColor(colorResId);
}
public float getTextSize() {
return mTextSize;
}
public int getBgColor() {
return mBgColor;
}
public int getUpTextColor() {
return mUpTextColor;
}
public int getDownTextColor() {
return mDownTextColor;
}
private void refreshStockListHeader() {
mCodeTextView.setTextSize(mTextSize);
mSymbolTextView.setTextSize(mTextSize);
mLastPriceTextView.setTextSize(mTextSize);
mPriceChangeTextView.setTextSize(mTextSize);
mPriceChangePercentageTextView.setTextSize(mTextSize);
mStockListHeader.setBackgroundColor(mBgColor);
mStockListView.setBackgroundColor(mBgColor);
}
}
StockListAdapter.java
package com.android.msoft.mfinance.ui;
import com.android.msoft.mfinance.provider.Stock.StockColumns;
import com.android.msoft.mfinance.provider.StockMarket.StockMarketColumns;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public class StockListAdapter extends BaseAdapter {
private static final String TAG = "com.android.msoft.mfinance.ui.StockListAdapter";
private Cursor mStockListCursor;
private Context mContext;
private final int sCodeIndex;
private final int sSymbolIndex;
private final int sBoardIndex;
private final int sLastPriceIndex;
private final int sChangePriceIndex;
private final int sChangePricePercentIndex;
public StockListAdapter(Context context, Cursor cursor) {
mStockListCursor = cursor;
mContext = context;
sCodeIndex = mStockListCursor.getColumnIndex(StockColumns.CODE);
sSymbolIndex = mStockListCursor.getColumnIndex(StockColumns.SYMBOL);
sBoardIndex = mStockListCursor.getColumnIndex(StockColumns.BOARD);
sLastPriceIndex = mStockListCursor
.getColumnIndex(StockMarketColumns.LAST_PRICE);
sChangePriceIndex = mStockListCursor
.getColumnIndex(StockMarketColumns.CHANGE_PRICE);
sChangePricePercentIndex = mStockListCursor
.getColumnIndex(StockMarketColumns.CHANGE_PRICE_PERCENT);
}
@Override
public int getCount() {
Log.d(TAG, "Stock list count:" + mStockListCursor.getCount());
return mStockListCursor.getCount();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
StockListItem listItem;
mStockListCursor.moveToPosition(position);
if (null == convertView) {
String code = mStockListCursor.getString(sCodeIndex);
String symbol = mStockListCursor.getString(sSymbolIndex);
String board = mStockListCursor.getString(sBoardIndex);
float lastPrice = mStockListCursor.getFloat(sLastPriceIndex);
float changePrice = mStockListCursor.getFloat(sChangePriceIndex);
float changePercent = mStockListCursor
.getFloat(sChangePricePercentIndex);
listItem = new StockListItem(mContext, code, symbol, board,
lastPrice, changePrice, changePercent);
} else {
listItem = (StockListItem) convertView;
}
return listItem;
}
}
StockListItem.java
package com.android.msoft.mfinance.ui;
import com.android.msoft.mfinance.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;
public class StockListItem extends LinearLayout {
public StockListItem(Context context, String code, String symbol,
String board, float lastPrice, float changePrice,
float changePercent) {
super(context);
StockListActivity stockListActivity = (StockListActivity) context;
float textSize = stockListActivity.getTextSize();
LayoutInflater factory = LayoutInflater.from(context);
factory.inflate(R.layout.stock_list_item, this);
TextView codeTextView = (TextView) findViewById(R.id.stock_code);
codeTextView.setTextSize(textSize);
codeTextView.setText(code);
TextView symbolTextView = (TextView) findViewById(R.id.stock_symbol);
symbolTextView.setTextSize(textSize);
symbolTextView.setText(symbol);
TextView lastPriceTextView = (TextView) findViewById(R.id.stock_last_price);
lastPriceTextView.setTextSize(textSize);
lastPriceTextView.setText(Float.toString(lastPrice));
TextView changePriceTextView = (TextView) findViewById(R.id.stock_change_price);
changePriceTextView.setTextSize(textSize);
changePriceTextView.setText(Float.toString(changePrice));
TextView ChangePercentTextView = (TextView) findViewById(R.id.stock_change_percentage);
ChangePercentTextView.setTextSize(textSize);
ChangePercentTextView.setText(Float.toString(changePercent));
if (changePrice > 0) {
int textColor = stockListActivity.getUpTextColor();
// codeTextView.setTextColor(textColor);
// symbolTextView.setTextColor(textColor);
lastPriceTextView.setTextColor(textColor);
changePriceTextView.setTextColor(textColor);
ChangePercentTextView.setTextColor(textColor);
} else if (changePrice < 0) {
int textColor = stockListActivity.getDownTextColor();
// codeTextView.setTextColor(textColor);
// symbolTextView.setTextColor(textColor);
lastPriceTextView.setTextColor(textColor);
changePriceTextView.setTextColor(textColor);
ChangePercentTextView.setTextColor(textColor);
}
}
}
到此就大功告成了,这个例子我们是通过View来画线条分割各个单元格的,另外我们还可以通过定义不同的背景色,通过背景色来达到相似的效果,这个不难,就不写了。
从网上了解到ubi image不能像其他格式的文件系统image那样作为loop设备mount起来,所以需要找其它方法。具体做法就是安装nandsim模块来模拟一个nand flash,然后将ubi image写到mtd设备上,再将mtd设备attach起来,最后就可一mount ubi设备了。
2002 sudo modprobe ubi
(需要安装ubi模块,不然ubiattach会报错)
2003 sudo modprobe nandsim first_id_byte=0x20 second_id_byte=0xaa third_id_byte=0x00 fourth_id_byte=0x15
(安装nandsim来模拟nand设备,执行后可以看到/dev/mtd0。传入的四个id在执行“read ID”命令时返回)
2005 cat /proc/mtd
(mtd设备信息)
2008 sudo ubiformat -y /dev/mtd0 -s 512 -f ubi.img
(格式化mtd,并写入ubi image)
2009 sudo ubiattach -m 0
(将/dev/mtd0 attach到ubi设备。detach则用-d 0,表示detach /dev/ubi0)
2010 ls /dev/ubi0*
2012 sudo mount -t ubifs /dev/ubi0_0 ubi
(将ubi设备0的第一个分区mount到ubi目录)
2025 sudo mkfs.ubifs -r ubi -m 2048 -e 129024 -c 863 -o fs.img
(由ubi目录制作文件系统image。-m为最小io大小,-e为逻辑擦除块leb大小,-c为最大leb个数)
2027 sudo ubinize -o fs.img.ubinized -m 2048 -p 128KiB -s 512 -O 512 ubi.ini
(制作待烧录的ubi image。-m为最小io大小,-p为物理擦除块peb大小,-s为用作ubi头的page大小,-O为VID头的偏移量)
ubi.ini内容:
[ubifs]
mode=ubi
image=fs.img
vol_id=0
vol_type=dynamic
vol_alignment=1
vol_name=rootfs
vol_flags=autoresize
有关ubi可以参考:
http://www.linux-mtd.infradead.org/doc/ubi.html
UBI头:
每一个PEB开始处存由两个64byte的的头,分为EC头和VID头。EC头存放PEB的擦除次数。VID头存放所属volume,以及映射时对应的LEB号码。EC头位于0偏移量处,VID位置取决于是否由sub-page:如果没有,则位于第二个page处;如果由,则位于第二个sub-page处。由于PEB包含两个头,所以LEB比PEB小。
最小io单元:
NOR flash的大小为1byte,NAND的对应page大小,比如512或者2k等等。
转载:
http://www.cnblogs.com/lemonczy/archive/2011/11/17/2252245.html
public class MyCrashHandler implements UncaughtExceptionHandler {
@SuppressWarnings("unused")
private Context context;
private static MyCrashHandler crashHandler = new MyCrashHandler();
UncaughtExceptionHandler defaultExceptionHandler;
private MyCrashHandler() {
}
public static MyCrashHandler getInstanceMyCrashHandler() {
return crashHandler;
}
/**
* 初始化方法
* @param context 上下文对象
*/
public void init(Context context) {
this.context = context;
defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 异常处理方法
* @Params Thread对象
* @param Throwable对象
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(thread, ex) && defaultExceptionHandler != null) {
defaultExceptionHandler.uncaughtException(thread, ex);
}
}
// 程序异常处理方法
private boolean handleException(Thread thread, Throwable ex) {
StringBuilder sb = new StringBuilder();
long startTimer = System.currentTimeMillis();
SimpleDateFormat formatter = new SimpleDateFormat(
"yyyy年MM月dd日 HH:mm:ss ");
Date firstDate = new Date(System.currentTimeMillis()); // 第一次创建文件,也就是开始日期
String str = formatter.format(firstDate);
sb.append(startTimer);
//sb.append("\n");
sb.append(str); // 把当前的日期写入到字符串中
Writer writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
ex.printStackTrace(pw);
String errorresult = writer.toString();
sb.append(errorresult);
sb.append("\n");
try {
File fileDir = new File("/data/data/com.ebank/Ebank/");
//File fileDir = new File("/sdcard/com.ebank/EBank/");
if (!fileDir.exists()) {
fileDir.mkdirs();
}
File files = new File(fileDir, "ebank.log");
if (!files.exists()) {
files.createNewFile();
}
FileOutputStream fileOutputStream = new FileOutputStream(files,
true);
fileOutputStream.write(sb.toString().getBytes());
fileOutputStream.close();
// 文件大小限制在1M,超过1M自动删除
FileInputStream fileInputStream = new FileInputStream(files);
int sizeK = fileInputStream.available() / 1024; // 单位是KB
int totalSize = 1 * 1024;
if (sizeK > totalSize) {
boolean b = files.delete();
if (b) { // 删除成功,重新创建一个文件
@SuppressWarnings("unused")
File filesTwo = new File(fileDir, "ebank.log");
if (!files.exists()) {
files.createNewFile();
}
} else {
// 删除失败
FileOutputStream fileOutputStream2 = new FileOutputStream(
files);
fileOutputStream2.write(" ".getBytes()); // 写入一个空格进去
}
}
// 文件保存7天,过了7天自动删除
FileReader fileReader = new FileReader(files);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String firstLine = bufferedReader.readLine();
long startTimerFile = Long.valueOf(firstLine.trim()); // 类型转换
long endTimer = System.currentTimeMillis();
long totalDay = 24 * 60 * 60 * 1000 * 7;
final File f = files;
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
try {
boolean n = f.delete();
if(n){
File fileDirs = new File("/data/data/com.ebank/Ebank/");
if (!fileDirs.exists()) {
fileDirs.mkdirs();
}
File filess = new File(fileDirs, "ebank.log");
if (!filess.exists()) {
filess.createNewFile();
}
}else{
// 删除失败
FileOutputStream fileOutputStream2 = new FileOutputStream(f);
fileOutputStream2.write(" ".getBytes()); // 写入一个空格进去
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
//定时器类的对象
Timer timer = new Timer();
if ((endTimer - startTimerFile) >= totalDay) {
timer.schedule(timerTask, 1); // 7天后执行
}
} catch (Exception e) {
e.printStackTrace();
}
defaultExceptionHandler.uncaughtException(thread, ex);
return true;
}
}