Build Apps with Content Sharing

如何創(chuàng)建apps與設備之間共享數(shù)據(jù)的app.

Sharing Simple Data

使用IntentActionProvider在app之間收發(fā)簡單數(shù)據(jù)剃盾。

Send Simple Data to Other Apps

當你構造一個intent時腺占,你必須確認你想讓intent來trigger什么行為.

Android 定義了幾種行為淤袜,其中有一種ACTION_SEND,用來在activity之間傳遞數(shù)據(jù)衰伯,甚至在進程之間也可以铡羡。

Note 最佳實踐是使用ShareActionProvider(Lesson -- Adding an Easy Share Action)添加action到ActionBar中(> API 14).

Send Text Content

Talk is cheap, I will show you the code.

Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send");
sendIntent.setType("text/plain");
startActivity(sendIntent);

如果有多個App接收到該intent,系統(tǒng)會自動顯示一個可選的dialog嚎研,當然蓖墅,你可以調(diào)用Intent.createChooser(),在任何版本任何情況下都會顯示選擇框临扮。優(yōu)點:

  • 即使用戶之前選擇了默認的action论矾,選擇框還是會顯示

  • 如果沒有App match到,Android會提示系統(tǒng)消息

  • 你可以自定義選擇框的title

    startActivity(Intent.createChooser(sendIntent, getResources().getText(R.string.send_to));

作為可選項杆勇,你也可以為intent設置一些基本的extra信息:EXTRA_EMAIL, EXTRA_CC, EXTRA_BCC, EXTRA_SUBJECT.

Note 一些e-mail應用(例如Gmail),會期望添加String[]作為extra.

Send Binary Content

使用ACTION_SENDEXTRA_STREAM(URI)結(jié)合來發(fā)送二進制內(nèi)容贪壳。

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
shareIntent.setType("image/jpeg");
startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.send_to)));

Note

  • 可以使用*/* MIME類型,但只能match到處理普通數(shù)據(jù)流的receiver.

  • 接收方需要權限來訪問Uri指向的數(shù)據(jù)蚜退。這里有兩種比較推薦的解決辦法:

    • 創(chuàng)建app自身的ContentProvider闰靴,確保其他app可以訪問你的provider:使用per-URI permissions -- 短期將權限授予給接收方.創(chuàng)建一個ContentProvider的簡單方法是使用FileProvider的幫助類.
    • 使用系統(tǒng)MediaStore. 主要包含video, audio, image MIME 類型(在Android 3.0 以下還會包含一些非媒體類型). 文件可被插入到MediaStore中:使用scanFile(),然后將適合共享的Uri(content://)傳遞給onScanCompleted()回調(diào).

Send Multiple Pieces of Content

使用ACTION_SEND_MULTIPLE action來發(fā)送多塊數(shù)據(jù)(多條指向content的uri).
MIME 類型match你共享的所有文件.

ArrayList<Uri> imageUris = new ArrayList<Uri>();
imageUris.add(imageUri1);
imageUris.add(imageUri2);

Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
shareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris);
shareIntent.setType("image/*");
startActivity(Intent.createChooser(shareIntent, "Share images to.."));

Receiving Simple Data from Other Apps

Update Your Manifest

Intent filters告訴系統(tǒng)App可以接受怎樣的intent事件.

<activity android:name=".ui.MyActivity" >
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND_MULTIPLE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
</activity>

Handle the Incoming Content

void onCreate(Bundle savedInstanceState) {
    Intent intent = getIntent();
    String action = intent.getAction();
    String type = intent.getType();

    if (Intent.ACTION_SEND.equals(action) && type != null) {
        if ("text/plain".equals(type)) {
            handleSendText(intent);    
        } else if (type.startsWith("image/")) {
            handleSendImage(intent);    
        }
    } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
        if (type.startsWith("image/")) {
            handleSendMultipleImages(intent);    
        } else {
            //Handle other intents    
        }   
    }
}

void handleSendText(Intent intent) {
    String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
    if (sharedText != null) {
        //Update UI    
    }
}

void handleSendImage(Intent intent) {
    Uri imageUri = (Uri) intent.getParcelbleExtra(Intent.EXTRA_STREAM);
    if (imageUri != null) {
        //Update    
    }
}

void handleSendMultipleImages(Intent intent) {
    ArrayList<Uri> imageUris = intent.getParcelbleArrayList(Intent.EXTRA_STREAM);
    if (imageUris != null) {
        //Update    
    }
}

Adding an Easy Share Action

使用 ShareActionProvider 在ActionBar上添加share action(> Android 4.0).

Update Menu Declarations

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/menu_item_share"
        android:showAsAction="isRoom"
        android:title="Share"
        android:actionProviderClass="android.widget.ShareActionProvider" />
</menu>

Set the Share Intent

使用ShareActionProvider钻注,必須為其提供一個intent蚂且,需要先調(diào)用MenuItem.getActionProvider()來取回ShareActionProvider實例,再調(diào)用setShareIntent()為其指定intent.

private ShareActionProvider shareActionProvider;

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.share_menu, menu);

    MenuItem item = menu.findItem(R.id.menu_item_share);

    shareActionProvider = (ShareActionProvider) item.getActionProvider();
    return true;
}

private void setShareIntent(Intent shareIntent) {
    if (shareActionProvider != null) {
        shareActionProvider.setShareIntent(shareIntent);    
    }    
}

Sharing Files

共享文件:提供App文件的URI給接收方幅恋,并給予短暫的可讀/可寫權限.
FileProvider => getUriForFile() => 生成文件的URI

共享較小的text/numeric數(shù)據(jù):發(fā)送包含數(shù)據(jù)的Intent.

Setting Up File Sharing

FileProviderv4 Support Library 的一部分.

Specify the FileProvider

在配置文件中定義 FileProvider:

<application
    ...>
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.example.myapp.fileprovider"
        android:grantUriPermissions="true"
        android:exported="false">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/filepaths" />
    </provider>
    ...
</application>
  • android:authorities: FileProvider 生成的content URIs

Specify Sharable Directories

一旦在配置文件中添加了FileProvider杏死,就需要指定一個目錄來放置你想共享的文件:

在res/xml中創(chuàng)建filepaths.xml.

<paths>
    <files-path path="images/" name="myimages" />
</paths>
  • files-path
  • external-path: share directories in external storage
  • cache-path: share directories in internal storage

所有準備工作做完以后,FileProvider會生成固定格式的訪問URI:
content://com.example.myapp.fileprovider/myimages/<filename>

Sharing a File

從server app提供文件選擇接口捆交,以便讓其他app可以喚起.

Receive File Requests

如果收到文件訪問請求淑翼,你的app應該提供一個文件選擇Activity. 請求方通過調(diào)用 startActivityForResult() (包含ACTION_PICK的Intent)啟動該Activity.

Create a File Selection Activity

<intent-filter>

  • action: ACTION_PICK
  • category: CATEGORY_DEFAULT & CATEGORY_OPENABLE
  • data: mimeType

Define the file selection Activity in code

定義Activity來展示你的app中files/images的文件,并允許用戶點擊想要的文件.

public class MainActivity extends Activity {
    private File mPrivareRootDir;
    private File mImagesDir;
    File[] mImageFiles;
    String[] mImageFilenames;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mResultIntent = new Intent("com.example.myapp.ACTION_RETURN_FILE");
        mPrivateRootDir = getFilesDir();
        mImagesDir = new File(mPrivateRootDir, "images");
        mImageFiles = mImageDir.listFiles();
        setResult(Activity.RESULT_CANCELED, null);
    }
}

Respond to a File Selection

如果用戶選擇了文件品追,你的app必須考慮為選中的文件提供URI.

因為Android 6.0以上只支持運行時授予權限玄括,所以需要避免使用Uri.fromFile():

  • 不支持文件共享
  • 你的app需要獲得WRITE_EXTERNAL_STORAGE權限(ANDROID 4.4 及以下)
  • 接收文件的app需要有READ_EXTERNAL_STORAGE 權限

onItemClick() => File Object => call getUriFromFile().

    protected void onCreate(Bundle savedInstanceState) {
        mFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView,
                        View view,
                        int position,
                        long rowId) {
                File requestFile = new File(mImageFilename[position]);
                try {
                    fileUri = FileProvider.getUriForFile(
                            MainActivity.this,
                            "com.example.myapp.fileprovider",
                            requestFile);    
                } catch (IllegalArgumentException e) {
                    Log.e("File Selector", 
                            "The selected file can't be shared: " + 
                            clickedFileName);    
                }
            }
        });    
    }

Grant Permissions for the File

通過給 Intent 設置permission flags賦予讀取文件的權限.

protected void onCreate(Bundle savedInstanceState) {
    mFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView,
                View view,
                int position,
                long rowId) {
            ...
            if (fileUri != null) {
                mResultIntent.addFlags(
                    Intent.FLAG_GRANT_READ_URI_PERMISSION);    
            }    
        }
    });    
}

避免使用Context.grantUriPermission():只能使用Context.revokeUriPermission()收回權限

Share the File with the Requesting App

setResult

protected void onCreate(Bundle savedInstanceState) {
    ...
    mFileListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView,
                View view,
                int position,
                long rowId) {
            ...
            if (fileUri != null) {
                ...
                mResultIntent.setDataAndType(
                    fileUri,
                    getContentResolver().getType(fileUri));
                MainActivity.this.setResult(Activity.RESULT_OK,
                    mResultIntent);
            } else {
                mResultIntent.setDataAndType(null, "");
                MainActivity.this.setResult(Activity.RESULT_CANCELED,
                    mResultIntent);
            }
        }
    });
}

Requesting a Shared File

Send a Request for the File

從server app請求文件數(shù)據(jù)的方式一般為:startActivityForResult() + Intent(包含actionMIME type).

public class MainActivity extends Activity {
    private Intent mRequestFileIntent;
    private ParcelFileDescriptor mInputPFD;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRequestFileIntent = new Intent(Intent.ACTION_PICK);
        mRequestFileIntent.setType("image/jpg");
        ...
    }
    ...
    protected void requestFile() {
        /**
         * When the user requests a file, send an Intent to the server app files.
        **/    
        startActivityForResult(mRequestFileIntent, 0);
        ...
    }
    ...
}

Access the Requested File

override onActivityResult() 來處理接收文件肉瓦,一旦客戶端app有了文件的content URI遭京,可以通過獲取其FileDescriptor來處理文件。

只有在server app賦予了訪問權限泞莉,client app獲取到文件訪問入口洁墙,文件才可被處理。由于權限是臨時的戒财,所以一旦client app的任務棧結(jié)束,文件不再可被外部訪問捺弦。

@Override
public void onActivityResult(int requestCode, int resultCode, Intent returnIntent) {
    if (resultCode != RESULT_OK) {
        return;    
    } else {
        Uri returnUri = returnIntent.getData();
        try {
            mInputPFD = getContentResolver().openFileDescriptor(returnUri, "r");    
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.e("MainActivity", "File not found.");
            return;
        }

        FileDescriptor fd = mInputPFD.getFileDescriptor();
        ...
    }
}

Retrieving File Information

使用FileProvider來獲取文件的類型和大小饮寞。

Retrieve a File's MIME Type

調(diào)用ContentResolver.getType()獲取文件的數(shù)據(jù)類型(MIME)孝扛。一般地,FileProvider定義文件的MIME類型為其文件后綴幽崩。

Uri returnUri = returnIntent.getData();
String mimeType = getContentResolver().getType(returnUri);

Retrieve a File's Name and Size

FileProvider 有默認的query()實現(xiàn):返回一個Cursor對象苦始,用來查詢含有文件名稱和大小的content URI.

默認的實現(xiàn)中有兩列:

  • DISPLAY_NAME: 文件名稱,和File.getName()返回的數(shù)據(jù)一致

  • SIZE: 文件大小(long)慌申,和File.length()返回的數(shù)據(jù)一致

      Uri returnUri = returnIntent.getData();
      Cursor returnCursor = getContentResolver().query(returnUri, null, null, null, null);
      int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
      int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
      returnCursor.moveToFirst();
      TextView nameView = (TextView) findViewById(R.id.filename_Text);
      TextView sizeView = (TextView) findViewById(R.id.filesize_text);
      nameView.setText(returnCursor.getString(nameIndex));
      sizeView.setText(returnCursor.getString(sizeIndex));
    

Sharing Files with NFC

使用Android Beam(Android 自己的一個app陌选,僅支持Android 4.0以上) 文件傳輸功能傳輸較大的文件.

雖然Android Beam 傳輸API處理大量的數(shù)據(jù),但是Android 4.0中引入的Android Beam NDFF 傳輸API只能處理少量數(shù)據(jù).

Sending Files to Another Device

使用Android Beam傳輸大型文件. 完成功能之前蹄溉,需要申請使用NFC和外部存儲的權限咨油,測試你的設備是否支持NFC,提供URI給Android Beam文件傳輸.

Android Beam文件傳輸功能有以下需求:

  • Android 4.1 以上
  • 傳輸文件必須在外部存儲中
  • 所傳輸?shù)奈募仨毷侨挚勺x的. => 調(diào)用File.setReadable(true, false)來設置
  • 必須提供文件的URI. Android Beam 文件傳輸不能處理通過FileProvider.getUriForFile生成的URI

Declare Features in the Manifest

Request Permissions

  • NFC: <uses-permission android:name="android.permission.NFC" />
  • READ_EXTERNAL_STORAGE: <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Specify the NFC feature

<manifest>下添加<uses-feature>標簽柒爵,并設置android:required="true" => 聲明如果沒有NFC役电,app將無法工作.

<uses-feature
    android:name="android.hardware.nfc"
    android:required="true" />

Test for Android Beam File Transfer Support

如果沒有NFC,你的app也可以工作棉胀,則設置required="false".

測試是否支持Android Beam文件傳輸:PackageManager.hasSystemFeature(FEATURE_NFC)法瑟,然后檢查Android版本是否在4.1以上.

如果支持:獲取NFC控制器的實例(和NFC硬件進行交互).

public class MainActivity extends Activity {
    NfcAdapter mNfcAdapter;

    boolean mAndroidBeamAvailable = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if (!PackageManager.hasSystemFeature(PackageManager.FEATURE_NFC)) {
            //Disable NFC feature
        } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            mAndroidBeamAvailable = false;    
        } else {
            mNfcAdapter = NfcAdapter.getDefaultAdapter(this);    
        }
    }
}

Create a Callback Method that Provides Files

Android Beam文件傳輸檢測到用戶想要給其他的NFC設備傳輸文件時,系統(tǒng)調(diào)用自定義的callback. 在這個callback方法中唁奢,返回一個Uri對象數(shù)組. Android Beam文件傳輸將這些文件傳輸給接收方.

實現(xiàn)NfcAdapter.CreateBeamUrisCallback 接口以及其方法createBeamUris().

public class MainActivity extends Activity {
    private Uri[] mFileUris = new Uri[10];

    private class FileUriCallback implements NfcAdapter.CreateBeamUrisCallback {
        public FileUriCallback() {} 

        @Override
        public Uri[] createBeamUri(NfcEvent event) {
            return mFileUris;    
        }
    }
}

實現(xiàn)以后霎挟,通過setBeamPushUrisCallback()激活該callback.

public class MainActivity extends Activity {
    private FileUriCallback mFileUriCallback;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        mFileUriCallback = new FileUriCallback();
        mNfcAdapter.setBeamPushUrisCallback(mFileUriCallback, this);
    }
}

你也可以直接提供一組uri給NfcAdapter:NfcAdapter.setBeamPushUris()

Specify the Files to Send

private Uri[] mFileUris = new Uri[10];
String transferFile = "transferimage.jpg";
File extDir = getExternalFileDir(null);
File requestFile = new File(extDir, transferFile);
requestFile.setReadable(true, false);
fileUri = Uri.fromFile(requestFile);
if (fileUri != null) {
    mFileUris[0] = fileUri;    
} else {
    Log.e("My Activity", "No File URI available for file.");    
}

Receiving Files from Another Device

使用Android Media Scanner查看文件,使用MediaStoreprovider為媒體文件添加內(nèi)容.

Respond to a Request to Display Data

當Android Beam文件傳輸完畢麻掸,會發(fā)送一個包含ACTION_VIEW和MIME Type的Intent.
接收者需要定義<intent-filter>來接收對應的喚起事件:

  • <action android:name="android.intent.action.VIEW" />
  • <category android:name="android.intent.category.CATEGORY_DEFAULT" />
  • <data android:mimeType="mime-type" />

示例

<activity
    android:name="com.example.android.nfctransfer.ViewActivity"
    android:label="Android Beam Viewer" >
    ...
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        ...
    </intent-filter>
</activity>

Request File Permissions

權限申請:

  • 讀:<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  • 寫:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Get the Directory for Copied Files

Android Beam一次性傳輸多個文件酥夭,傳輸結(jié)束調(diào)用Intent的URI指向第一個文件. 然而,你的app可能也會接收到來自其他文件傳輸?shù)膇ntent(ACTION_VIEW). 為了處理接收時間论笔,你需要檢查其scheme和authority.

public class MainActivity extends Activity {
    private File mParentPath;
    private Intent mIntent;

    private void handleViewIntent() {
        mIntent = getIntent();
        String action = mIntent.getAction();

        if (TextUtils.equals(action, Intent.ACTION_VIEW)) {
            Uri beamUri = mIntent.getData();
            if (TextUtils.equals(beamUri.getScheme(), "file") {
                mParentPath = handleFileUri(beamUri);    
            } else if (TextUtils.equals(beamUri.getScheme(), "content")) {
                mParentPath = handleContentUri(beamUri);
            }
        }
    }
}

Get the directory from a file URI

如果接收到的intent包含文件的URI采郎,該URI包含文件的絕對路徑和文件名稱.

public String handleFileUri(Uri beamUri) {
    String fileName = beamUri.getPath();
    File copiedFile = new File(fileName);
    return copiedFile.getParent();
}

Get the directory from a content URI

如果接收到的intent包含內(nèi)容的URI,該URI指向存儲在MediaStore的內(nèi)容提供者(指向文件夾和文件名稱).你可以通過測試URI的認證值來檢測MediaStore的content URI.

你也可以通過接收ACTION_VIEWintent狂魔,包含content URI(除MediaStore之外的content provider).這種情況下蒜埋,content URI不包含MediaStore權限值,并且content URI通常不指向目錄最楷。

Determine the content provider

調(diào)用Uri.getAuthority()獲取URI的認證級別:

  • MediaStore.AUTHORITY: 該URI用于由MediaStore追蹤的一個或多個文件.從MediaStore檢索完整的文件名整份,并從文件名獲取目錄.
  • Any other authority value: 來自其他content provider的content URI. 只可以顯示該文件,不能獲取文件目錄.

為了獲取MediaStore的content URI籽孙,通過過濾條件:收到的content URI(Uri)和MediaColumns.DATA(projection)查找對應的目標.返回的Cursor對象包含所有的傳輸文件的完整路徑和文件名稱.

public String handleContentUri(Uri beamUri) {
    int filenameIndex;
    File copiedFile;
    String fileName;

    if (!TextUtils.equals(beamUri.getAuthority(), MediaStore.AUTHORITY) {
        //other content provider    
    } else {
        String[] projection = { MediaStore.MediaColumns.DATA };
        Cursor pathCursor = getContentResolver().query(beamUri, projection, null, null, null);
        if (pathCursor != null && pathCursor.moveToFirst()) {
            filenameIndex = pathCursor.getColumnIndex(MediaStore.MediaColumns.DATA);
            fileName = pathCursor.getString(filenameIndex);
            copiedFile = new File(fileName);
            return new File(copiedFile.getParent());
        }
    } else {
        return null;    
    }
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末烈评,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子犯建,更是在濱河造成了極大的恐慌讲冠,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件适瓦,死亡現(xiàn)場離奇詭異竿开,居然都是意外死亡谱仪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人末秃,你說我怎么就攤上這事【闯撸” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵贴浙,是天一觀的道長砂吞。 經(jīng)常有香客問我,道長悬而,這世上最難降的妖魔是什么呜舒? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮笨奠,結(jié)果婚禮上袭蝗,老公的妹妹穿的比我還像新娘。我一直安慰自己般婆,他們只是感情好到腥,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蔚袍,像睡著了一般乡范。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上啤咽,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天晋辆,我揣著相機與錄音,去河邊找鬼宇整。 笑死瓶佳,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的鳞青。 我是一名探鬼主播霸饲,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼臂拓!你這毒婦竟也來了厚脉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤胶惰,失蹤者是張志新(化名)和其女友劉穎傻工,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡中捆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年威鹿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片轨香。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖幼东,靈堂內(nèi)的尸體忽然破棺而出臂容,到底是詐尸還是另有隱情,我是刑警寧澤根蟹,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布脓杉,位于F島的核電站,受9級特大地震影響简逮,放射性物質(zhì)發(fā)生泄漏球散。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一散庶、第九天 我趴在偏房一處隱蔽的房頂上張望蕉堰。 院中可真熱鬧,春花似錦悲龟、人聲如沸屋讶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽皿渗。三九已至,卻和暖如春轻腺,著一層夾襖步出監(jiān)牢的瞬間乐疆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工贬养, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留挤土,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓煤蚌,卻偏偏與公主長得像耕挨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子尉桩,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,501評論 25 707
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程筒占,因...
    小菜c閱讀 6,358評論 0 17
  • Android7.0發(fā)布已經(jīng)有一個多月了,Android7.0在給用戶帶來一些新的特性的同時蜘犁,也給開發(fā)者帶來了新的...
    東經(jīng)315度閱讀 1,340評論 0 14
  • NFC 基礎 本文檔介紹了在Android上的基本的NFC任務翰苫。它說明了如何發(fā)送和接收的NDEF消息(NDEF m...
    張云飛Vir閱讀 3,205評論 0 52
  • 首先要清楚你到底想要過什么樣的生活,你要為之付出什么?你想過的生活需要多少錢奏窑,也就是你的工資要達到什么程...
    釋蓮花閱讀 378評論 0 1