在这里我们要使用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; } }