android學習筆記三

1、Android數據存儲,參考http://www.cnblogs.com/ITtangtang/p/3920916.htmlhtml

①最熟悉的是文件存儲的方式,分兩種:java

  一、保存在手機的文件目錄中(也能夠是緩存目錄中,使用了Context對象),mysql

  二、保存在sd卡上(使用了Environment對象獲取SD卡信息,參考:http://www.cnblogs.com/mengdd/p/3742623.html)。linux

保存文件時的選擇:不過重要的能夠存在緩存目錄中(能夠直接被刪除);較重要的存在通常目錄中;最重要的能夠存在SD卡上。android

②使用SharedPreferences保存數據一樣是保存文件形式,可是是xml格式的文件。web

Android解析xml文件的方式:Android提供了多種解析器,可是推薦使用pull解析器。參考:http://blog.csdn.net/liuhe688/article/details/6415593.sql

③使用SQlite數據庫存儲數據,和mysql等相比的特色是:在客戶端,不用安裝服務器。Android中經過兩個對象來進行操做:SQLiteOpenHelper,SQLiteDatabase數據庫

參考:http://www.cnblogs.com/Excellent/archive/2011/11/19/2254888.html編程

④使用內容提供者:這是應用之間傳遞數據的方式,一個應用做爲提供者,另外一個進行查詢(這也是使用SQLite數據庫,可是是對另外一個用的數據庫進行CURD操做)。緩存

  一、提供者將數據操做的類(dao類)繼承ContentProviders便可將其暴露,並經過UriMatcher對象設置訪問路徑且只有uri匹配時才進行相應操做。

    注意:此時的dao類須要實現ContentProviders的抽象方法來進行CURD操做;內容提供者能夠設置權限進行控制訪問。

  二、在配置文件中進行配置(包含其自己的聲明和權限的配置)

  1 import android.content.ContentProvider;
  2 import android.content.ContentUris;
  3 import android.content.ContentValues;
  4 import android.content.UriMatcher;
  5 import android.database.Cursor;
  6 import android.database.sqlite.SQLiteDatabase;
  7 import android.net.Uri;
  8 
  9 public class PersonContentProvider extends ContentProvider {
 10     
 11     private static final String AUTHORITY = "com.itheima28.sqlitedemo.providers.PersonContentProvider";
 12     private static final int PRESON_INSERT_CODE = 0;    // 操做person表添加的操做的uri匹配碼
 13     private static final int PERSON_DELETE_CODE = 1;
 14     private static final int PERSON_UPDATE_CODE = 2;
 15     private static final int PERSON_QUERY_ALL_CODE = 3;
 16     private static final int PERSON_QUERY_ITEM_CODE = 4;
 17     
 18     private static UriMatcher uriMatcher;
 19     private PersonSQLiteOpenHelper mOpenHelper;        // person表的數據庫幫助對象
 20     
 21     static {
 22         uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 23         // 添加一些uri(相似於分機號)
 24         
 25         // content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/insert
 26         uriMatcher.addURI(AUTHORITY, "person/insert", PRESON_INSERT_CODE);
 27         
 28         // content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/delete
 29         uriMatcher.addURI(AUTHORITY, "person/delete", PERSON_DELETE_CODE);
 30 
 31         // content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/update
 32         uriMatcher.addURI(AUTHORITY, "person/update", PERSON_UPDATE_CODE);
 33         
 34         // content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/queryAll
 35         uriMatcher.addURI(AUTHORITY, "person/queryAll", PERSON_QUERY_ALL_CODE);
 36         
 37         // content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/query/#
 38         uriMatcher.addURI(AUTHORITY, "person/query/#", PERSON_QUERY_ITEM_CODE);
 39     }
 40 
 41     //這裏能夠經過該方法進行初始化,而不用經過構造函數
 42     @Override
 43     public boolean onCreate() {
 44         mOpenHelper = new PersonSQLiteOpenHelper(getContext());
 45         return true;
 46     }
 47 
 48     //這個方法是由系統調用的,用於說明返回值的MIME類型
 49     @Override
 50     public String getType(Uri uri) {
 51         switch (uriMatcher.match(uri)) {
 52         case PERSON_QUERY_ALL_CODE: // 返回多條的MIME-type
 53             return "vnd.android.cursor.dir/person";
 54         case PERSON_QUERY_ITEM_CODE: // 返回單條的MIME-TYPE
 55             return "vnd.android.cursor.item/person";
 56         default:
 57             break;
 58         }
 59         return null;
 60     }
 61 
 62     @Override
 63     public Cursor query(Uri uri, String[] projection, String selection,
 64             String[] selectionArgs, String sortOrder) {
 65         SQLiteDatabase db = mOpenHelper.getReadableDatabase();
 66         switch (uriMatcher.match(uri)) {
 67         case PERSON_QUERY_ALL_CODE:  // 查詢全部人的uri
 68             if(db.isOpen()) {
 69                 Cursor cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
 70                 return cursor;
 71                 // db.close(); 返回cursor結果集時, 不能夠關閉數據庫
 72             }
 73             break;
 74         case PERSON_QUERY_ITEM_CODE:        // 查詢的是單條數據, uri末尾出有一個id
 75             if(db.isOpen()) {
 76                 
 77                 long id = ContentUris.parseId(uri);
 78                 
 79                 Cursor cursor = db.query("person", projection, "_id = ?", new String[]{id + ""}, null, null, sortOrder);
 80 
 81                 return cursor;
 82             }
 83             break;
 84         default:
 85             throw new IllegalArgumentException("uri不匹配: " + uri);
 86         }
 87         return null;
 88     }
 89 
 90     @Override
 91     public Uri insert(Uri uri, ContentValues values) {
 92         
 93         switch (uriMatcher.match(uri)) {
 94         case PRESON_INSERT_CODE:    // 添加人到person表中
 95             SQLiteDatabase db = mOpenHelper.getWritableDatabase();
 96             
 97             if(db.isOpen()) {
 98                 
 99                 long id = db.insert("person", null, values);
100                 
101                 db.close();
102                 
103                 return ContentUris.withAppendedId(uri, id);
104             }
105             break;
106         default:
107             throw new IllegalArgumentException("uri不匹配: " + uri);
108         }
109         return null;
110     }
111 
112     @Override
113     public int delete(Uri uri, String selection, String[] selectionArgs) {
114         switch (uriMatcher.match(uri)) {
115         case PERSON_DELETE_CODE:    // 在person表中刪除數據的操做
116             SQLiteDatabase db = mOpenHelper.getWritableDatabase();
117             if(db.isOpen()) {
118                 int count = db.delete("person", selection, selectionArgs);
119                 db.close();
120                 return count;
121             }
122             break;
123         default:
124             throw new IllegalArgumentException("uri不匹配: " + uri);
125         }
126         return 0;
127     }
128 
129     @Override
130     public int update(Uri uri, ContentValues values, String selection,
131             String[] selectionArgs) {
132         switch (uriMatcher.match(uri)) {
133         case PERSON_UPDATE_CODE: // 更新person表的操做
134             SQLiteDatabase db = mOpenHelper.getWritableDatabase();
135             if(db.isOpen()) {
136                 int count = db.update("person", values, selection, selectionArgs);
137                 db.close();
138                 return count;
139             }
140             break;
141         default:
142             throw new IllegalArgumentException("uri不匹配: " + uri);
143         }
144         return 0;
145     }
146 
147 }
內容提供者
 1 import android.content.ContentResolver;
 2 import android.content.ContentUris;
 3 import android.content.ContentValues;
 4 import android.database.Cursor;
 5 import android.net.Uri;
 6 import android.test.AndroidTestCase;
 7 import android.util.Log;
 8 
 9 public class TextCase extends AndroidTestCase {
10 
11     private static final String TAG = "TextCase";
12 
13     public void testInsert() {
14         Uri uri = Uri.parse("content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/insert");
15         
16         // 內容提供者訪問對象
17         ContentResolver resolver = getContext().getContentResolver();
18         
19         ContentValues values = new ContentValues();
20         values.put("name", "fengjie");
21         values.put("age", 90);
22         
23         uri = resolver.insert(uri, values);
24         Log.i(TAG, "uri: " + uri);
25         long id = ContentUris.parseId(uri);
26         Log.i(TAG, "添加到: " + id);
27     }
28     
29     public void testDelete() {
30         Uri uri = Uri.parse("content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/delete");
31         
32         // 內容提供者訪問對象
33         ContentResolver resolver = getContext().getContentResolver();
34         
35         String where = "_id = ?";
36         String[] selectionArgs = {"21"};
37         int count = resolver.delete(uri, where, selectionArgs);
38         Log.i(TAG, "刪除行: " + count);
39     }
40     
41     public void testUpdate() {
42         Uri uri = Uri.parse("content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/update");
43         
44         // 內容提供者訪問對象
45         ContentResolver resolver = getContext().getContentResolver();
46         
47         ContentValues values = new ContentValues();
48         values.put("name", "lisi");
49         
50         int count = resolver.update(uri, values, "_id = ?", new String[]{"20"});
51         Log.i(TAG, "更新行: " + count);
52     }
53     
54     public void testQueryAll() {
55         Uri uri = Uri.parse("content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/queryAll");
56         
57         // 內容提供者訪問對象
58         ContentResolver resolver = getContext().getContentResolver();
59         
60         Cursor cursor = resolver.query(uri, new String[]{"_id", "name", "age"}, null, null, "_id desc");
61         
62         if(cursor != null && cursor.getCount() > 0) {
63             
64             int id;
65             String name;
66             int age;
67             while(cursor.moveToNext()) {
68                 id = cursor.getInt(0);
69                 name = cursor.getString(1);
70                 age = cursor.getInt(2);
71                 Log.i(TAG, "id: " + id + ", name: " + name + ", age: " + age);
72             }
73             cursor.close();
74         }
75     }
76     
77     public void testQuerySingleItem() {
78         Uri uri = Uri.parse("content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/query/#");
79         
80         // 在uri的末尾添加一個id content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/query/20
81         uri = ContentUris.withAppendedId(uri, 20);
82         
83         // 內容提供者訪問對象
84         ContentResolver resolver = getContext().getContentResolver();
85         
86         Cursor cursor = resolver.query(uri, new String[]{"_id", "name", "age"}, null, null, null);
87         
88         if(cursor != null && cursor.moveToFirst()) {
89             int id = cursor.getInt(0);
90             String name = cursor.getString(1);
91             int age = cursor.getInt(2);
92             cursor.close();
93             Log.i(TAG, "id: " + id + ", name: " + name + ", age: " + age);
94         }
95     }
96 }
訪問內容提供者

內容提供者是Android四大組件之一,是系統數據向外提供的方式,例如短信,聯繫人信息等,參考:http://www.2cto.com/kf/201312/261478.html

和內容提供者相關的是內容觀察者,指的是監聽一個uri路徑上的數據庫變化並做出相應操做的類,參考:http://blog.csdn.net/qinjuning/article/details/7047607,注意這篇文章中的其餘連接也有些不錯的好文。

參考:http://www.it165.net/pro/html/201402/9053.html.

⑤網絡數據:Android是一個操做系統,裏面各類應用進行網絡操做,因此須要多種網絡訪問方式,而不像web中只有http便可,這就須要所謂的網絡編程。參考:http://www.jb51.net/article/44859.htm

可是移動端網絡性能對用戶體驗影響大,因此一般須要多線程處理網絡訪問或者其餘比較複雜的問題,這就涉及到多線程編程,而在多個線程之間進行消息的傳遞也是一個必須處理的問題,參考:http://blog.csdn.net/beiminglei/article/details/8474026

  1 import java.io.InputStream;
  2 import java.net.HttpURLConnection;
  3 import java.net.MalformedURLException;
  4 import java.net.URL;
  5 
  6 import javax.net.ssl.HttpsURLConnection;
  7 
  8 import android.os.Bundle;
  9 import android.os.Handler;
 10 import android.os.Message;
 11 import android.app.Activity;
 12 import android.graphics.Bitmap;
 13 import android.graphics.BitmapFactory;
 14 import android.util.Log;
 15 import android.view.Menu;
 16 import android.view.View;
 17 import android.view.View.OnClickListener;
 18 import android.widget.EditText;
 19 import android.widget.ImageView;
 20 import android.widget.Toast;
 21 
 22 public class MainActivity extends Activity implements OnClickListener {
 23 
 24     private static final String TAG = "MainActivity";
 25     protected static final int ERROR = 1;
 26     private EditText etUrl;
 27     private ImageView ivIcon;
 28     private final int SUCCESS = 0;
 29     
 30     private Handler handler = new Handler() {
 31 
 32         /**
 33          * 接收消息
 34          */
 35         @Override
 36         public void handleMessage(Message msg) {
 37             super.handleMessage(msg);
 38             
 39             Log.i(TAG, "what = " + msg.what);
 40             if(msg.what == SUCCESS) {    // 當前是訪問網絡, 去顯示圖片
 41                 ivIcon.setImageBitmap((Bitmap) msg.obj);        // 設置imageView顯示的圖片
 42             } else if(msg.what == ERROR) {
 43                 Toast.makeText(MainActivity.this, "抓去失敗", 0).show();
 44             }
 45         }
 46     };
 47 
 48     @Override
 49     protected void onCreate(Bundle savedInstanceState) {
 50         super.onCreate(savedInstanceState);
 51         setContentView(R.layout.activity_main);
 52         
 53         ivIcon = (ImageView) findViewById(R.id.iv_icon);
 54         etUrl = (EditText) findViewById(R.id.et_url);
 55         
 56         findViewById(R.id.btn_submit).setOnClickListener(this);
 57     }
 58 
 59     @Override
 60     public void onClick(View v) {
 61         final String url = etUrl.getText().toString();
 62         
 63         new Thread(new Runnable() {
 64 
 65             @Override
 66             public void run() {
 67                 Bitmap bitmap = getImageFromNet(url);
 68 
 69 //                ivIcon.setImageBitmap(bitmap);        // 設置imageView顯示的圖片
 70                 if(bitmap != null) {
 71                     Message msg = new Message();
 72                     msg.what = SUCCESS;
 73                     msg.obj = bitmap;
 74                     handler.sendMessage(msg);
 75                 } else {
 76                     Message msg = new Message();
 77                     msg.what = ERROR;
 78                     handler.sendMessage(msg);
 79                 }
 80             }}).start();
 81         
 82     }
 83 
 84     /**
 85      * 根據url鏈接取網絡抓去圖片返回
 86      * @param url
 87      * @return url對應的圖片
 88      */
 89     private Bitmap getImageFromNet(String url) {
 90         HttpURLConnection conn = null;
 91         try {
 92             URL mURL = new URL(url);    // 建立一個url對象
 93             
 94             // 獲得http的鏈接對象
 95             conn = (HttpURLConnection) mURL.openConnection();
 96             
 97             conn.setRequestMethod("GET");        // 設置請求方法爲Get
 98             conn.setConnectTimeout(10000);        // 設置鏈接服務器的超時時間, 若是超過10秒鐘, 沒有鏈接成功, 會拋異常
 99             conn.setReadTimeout(5000);        // 設置讀取數據時超時時間, 若是超過5秒, 拋異常
100             
101             conn.connect();        // 開始連接
102             
103             int responseCode = conn.getResponseCode(); // 獲得服務器的響應碼
104             if(responseCode == 200) {
105                 // 訪問成功
106                 InputStream is = conn.getInputStream();    // 得到服務器返回的流數據
107                 
108                 Bitmap bitmap = BitmapFactory.decodeStream(is); // 根據 流數據 建立一個bitmap位圖對象
109                 
110                 return bitmap;
111             } else {
112                 Log.i(TAG, "訪問失敗: responseCode = " + responseCode);
113             }
114         } catch (Exception e) {
115             e.printStackTrace();
116         } finally {
117             if(conn != null) {
118                 conn.disconnect();        // 斷開鏈接
119             }
120         }
121         return null;
122     }
123 }
網絡圖片查看

 Android下進行http鏈接可使用HttpClient類,可是在Android 6.0(即sdk23)以後移除了相關包,因此不推薦使用,可是好像有的框架依然在使用,能夠做爲了解,對於Android下使用參考http://liangruijun.blog.51cto.com/3061169/803097/:關於其餘的使用參考:http://www.ibm.com/developerworks/cn/opensource/os-httpclient/。注意其中引用的文章列表。

 

!!!網絡訪問在模擬器下測試時,訪問本機的路徑不是127.0.0.1,而是10.0.2.2,或者是局域網中的路徑。參考:http://www.cnblogs.com/csulennon/p/3709032.html.

 

2、android權限

①Android文件權限是linux風格的

 

②安卓的權限很是細,並且應用須要申請,而用戶能夠對其進行設定(在模擬器中直接賦予),

具體權限參考:http://www.cnblogs.com/classic/archive/2011/06/20/2085055.html

 

3、多線程下載:

 

上圖的要點是:

  ①RandomAccessFile類,這是一個很是適合用於多線程下載的類,由於它帶有一個文件指針,能夠方便的針對文件的指定位置進行操做。因此多個線程能夠分別在不一樣的位置操做同一個文件而不出線程問題。參考:http://www.2cto.com/kf/201208/149816.html。注意:rwd是直接將讀取的文件寫入到硬盤上,而rw是先寫到內存的緩衝區中,當達到必定量以後在寫入硬盤。二者各有優勢:一個防止特殊狀況丟失下載數據(尚未保存就斷網等狀況),一個減小io操做。可是下載時使用rwd更好

  ②上面提到了多線程常常應用在網絡等比較耗時的方面,對於網絡下載更是如此。可是在Android下的下載使用的依然是j2se中的API,也就是HttpURLConnection類中的方法。具體實現的原理就是HTTP協議中的HTTP頭 Range和Content-Range字段。參考:。

所謂的端點下載就是在用一個臨時文件同步存儲下載數據,只有在下載完成時才刪除,因此這個文件就用於判斷是否下載完成和記錄下載到了那裏,便於以後繼續下載。

 

  1 import java.io.BufferedReader;
  2 import java.io.File;
  3 import java.io.FileInputStream;
  4 import java.io.InputStream;
  5 import java.io.InputStreamReader;
  6 import java.io.RandomAccessFile;
  7 import java.net.HttpURLConnection;
  8 import java.net.URL;
  9 
 10 public class MutileThreadDownload {
 11     /**
 12      * 線程的數量
 13      */
 14     private static int threadCount = 3;
 15 
 16     /**
 17      * 每一個下載區塊的大小
 18      */
 19     private static long blocksize;
 20 
 21     /**
 22      * 正在運行的線程的數量
 23      */
 24     private static int runningThreadCount;
 25 
 26     /**
 27      * @param args
 28      * @throws Exception
 29      */
 30     public static void main(String[] args) throws Exception {
 31         // 服務器文件的路徑
 32         String path = "http://192.168.1.100:8080/ff.exe";
 33         URL url = new URL(path);
 34         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
 35         conn.setRequestMethod("GET");
 36         conn.setConnectTimeout(5000);
 37         int code = conn.getResponseCode();
 38         if (code == 200) {
 39             long size = conn.getContentLength();// 獲得服務端返回的文件的大小
 40             System.out.println("服務器文件的大小:" + size);
 41             blocksize = size / threadCount;
 42             // 1.首先在本地建立一個大小跟服務器如出一轍的空白文件。
 43             File file = new File("temp.exe");
 44             RandomAccessFile raf = new RandomAccessFile(file, "rw");
 45             raf.setLength(size);
 46             // 2.開啓若干個子線程分別去下載對應的資源。
 47             runningThreadCount = threadCount;
 48             for (int i = 1; i <= threadCount; i++) {
 49                 long startIndex = (i - 1) * blocksize;
 50                 long endIndex = i * blocksize - 1;
 51                 if (i == threadCount) {
 52                     // 最後一個線程
 53                     endIndex = size - 1;
 54                 }
 55                 System.out.println("開啓線程:" + i + "下載的位置:" + startIndex + "~"
 56                         + endIndex);
 57                 new DownloadThread(path, i, startIndex, endIndex).start();
 58             }
 59         }
 60         conn.disconnect();
 61     }
 62 
 63     private static class DownloadThread extends Thread {
 64         private int threadId;
 65         private long startIndex;
 66         private long endIndex;
 67         private String path;
 68 
 69         public DownloadThread(String path, int threadId, long startIndex,
 70                 long endIndex) {
 71             this.path = path;
 72             this.threadId = threadId;
 73             this.startIndex = startIndex;
 74             this.endIndex = endIndex;
 75         }
 76 
 77         @Override
 78         public void run() {
 79             try {
 80                 // 當前線程下載的總大小
 81                 int total = 0;
 82                 File positionFile = new File(threadId + ".txt");
 83                 URL url = new URL(path);
 84                 HttpURLConnection conn = (HttpURLConnection) url
 85                         .openConnection();
 86                 conn.setRequestMethod("GET");
 87                 // 接着從上一次的位置繼續下載數據
 88                 if (positionFile.exists() && positionFile.length() > 0) {// 判斷是否有記錄
 89                     FileInputStream fis = new FileInputStream(positionFile);
 90                     BufferedReader br = new BufferedReader(
 91                             new InputStreamReader(fis));
 92                     // 獲取當前線程上次下載的總大小是多少
 93                     String lasttotalstr = br.readLine();
 94                     int lastTotal = Integer.valueOf(lasttotalstr);
 95                     System.out.println("上次線程" + threadId + "下載的總大小:"
 96                             + lastTotal);
 97                     startIndex += lastTotal;
 98                     total += lastTotal;// 加上上次下載的總大小。
 99                     fis.close();
100                 }
101 
102                 conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
103                         + endIndex);
104                 conn.setConnectTimeout(5000);
105                 int code = conn.getResponseCode();
106                 System.out.println("code=" + code);
107                 InputStream is = conn.getInputStream();
108                 File file = new File("temp.exe");
109                 RandomAccessFile raf = new RandomAccessFile(file, "rw");
110                 // 指定文件開始寫的位置。
111                 raf.seek(startIndex);
112                 System.out.println("第" + threadId + "個線程:寫文件的開始位置:"
113                         + String.valueOf(startIndex));
114                 int len = 0;
115                 byte[] buffer = new byte[512];
116                 while ((len = is.read(buffer)) != -1) {
117                     RandomAccessFile rf = new RandomAccessFile(positionFile,
118                             "rwd");
119                     raf.write(buffer, 0, len);
120                     total += len;
121                     rf.write(String.valueOf(total).getBytes());
122                     rf.close();
123                 }
124                 is.close();
125                 raf.close();
126 
127             } catch (Exception e) {
128                 e.printStackTrace();
129             } finally {
130                 // 只有全部的線程都下載完畢後 才能夠刪除記錄文件。
131                 synchronized (MutileThreadDownload.class) {
132                     System.out.println("線程" + threadId + "下載完畢了");
133                     runningThreadCount--;
134                     if (runningThreadCount < 1) {
135                         System.out.println("全部的線程都工做完畢了。刪除臨時記錄的文件");
136                         for (int i = 1; i <= threadCount; i++) {
137                             File f = new File(i + ".txt");
138                             System.out.println(f.delete());
139                         }
140                     }
141                 }
142 
143             }
144         }
145     }
146 }
斷點下載實例

 

在Android上實現多線程下載的基本原理同樣,只是有一些問題須要注意,

  ①下載文件的保存位置,Android項目須要保存在指定的位置:sd卡/Android項目文件路徑

  ②多線程之間的信息傳遞

  ③對用戶的提示

相關文章
相關標籤/搜索