① 如何解決android7.0及以上的許可權崩潰問題
1.檢查代碼和許可權申請流程:請確保您的代碼已針對Android 7.0及以上版本進行了兼容性處理,並且許可權申請的流程符合最新的安全規范。2.盡可能使用新API:Android 7.0引入了新的API,例如運行時許可權,應用鏈接和漏晌通知管道等,這些API可以逗祥幫助您正確處理許可權,提高應用程序的兼容性。3.升級庫版本:如果您正在使用第三方庫,請查看最新庫版本是否已針對Android 7.0及以上版本進行了兼容性處理,如果是,請盡快山搜搏升級庫版本。4.升級設備:盡管不是所有用戶都會立即升級到Android 7.0及以上版本,但是您可以建議用戶升級設備以避免許可權崩潰問題。5.避免使用不穩定的許可權:對於某些許可權(例如SYSTEM_ALERT_WINDOW),由於其過於敏感,系統會限制其使用。如果您在使用這些許可權,請確保其使用場景受到支持,並盡可能使用更穩定的替代方案。6.優化應用程序性能:如果您的應用程序在授予許可權時崩潰,則可能由於應用程序的性能不佳導致。因此,請確保您的應用程序已經進行了優化,以提高應用程序的穩定性和性能。② android開發開想要在一個方法中將子線程計算的數據返回怎麼做
先實例化一個Handler再重寫handleMessage(Messagemsg)方法msg.getData().getXXX()獲得Thread線程發送的數據
③ android 怎麼獲取相冊路徑
android手機4.2版本之前是一個方法,大於4.2版本又是一個方法。
注意:現在手機市場android版本2015面上半年平均4.4,現在是平均5.0了。
before
你網路一下,都能查到,很簡單.
after
private void startPickPhotoActivity() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.setType("image/*"); // Or 'image/ jpeg '
startActivityForResult(intent, RESULT_PICK_PHOTO_NORMAL);
}
// 獲得圖片返回的路徑
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == RESULT_PICK_PHOTO_NORMAL) {
if (resultCode == RESULT_OK && data != null) {
//選中圖片路徑
mFileName = MainActivity.getPath(getApplicationContext(),
data.getData());
if ("".equals(mFileName)) {
return;
}
Intent intent = new Intent(this, EditActivity.class);
intent.putExtra("pathName", mFileName);
startActivity(intent);
}
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (UriUtils.isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/"
+ split[1];
}
}
// DownloadsProvider
else if (UriUtils.isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"),
Long.valueOf(id));
return UriUtils.getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (UriUtils.isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = MediaColumns._ID + "=?";
final String[] selectionArgs = new String[] { split[1] };
return UriUtils.getDataColumn(context, contentUri, selection,
selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (UriUtils.isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return UriUtils.getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
④ 請android高手幫忙!
使用照相機的方法:
//在監聽事件中加入如下代碼
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(Environment.getExternalStorageDirectory()+"/","temp.jpg")));
startActivityForResult(intent, reqCode_CAMERA);// reqCode_CAMERA是一個一自己設定的值,用於在onActivityResult方法中判斷是哪一個activity返回的
再重寫onActivityResult方法:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == reqCode_CAMERA && resultCode== RESULT_OK){
////這里是直接隱式啟動系統圖片預覽程序
// Intent intent = new Intent();
// intent.setAction(Intent.ACTION_VIEW);
//// uri指向用戶選擇的那個圖片
// Uri uri = data.getData();
// intent.setData(uril);
// startActivity(intent);
// Uri uri = data.getData();
// Cursor cursor = getContentResolver().query(uri, null, null, null, null);
// if(cursor!=null&&cursor.moveToFirst()){
// String path = cursor.getString(1);
// Bitmap bm = BitmapFactory.decodeFile(path);
// iv.setImageBitmap(bm);
// }
// iv.setImageURI(uri);
//也可以用這里代碼打開圖片裁剪
Intent intent = new Intent();
intent.setAction("com.android.camera.action.CROP");
intent.setType("image/*");
intent.putExtra("data", data.getExtras().getParcelable("data"));
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);//默認圖片剪裁起始位置x值
intent.putExtra("aspectY", 1);//默認圖片剪裁起始位置y值
intent.putExtra("outputX", 128);//默認圖片剪裁終止位置x值
intent.putExtra("outputY", 128);//默認圖片剪裁終止位置x值
intent.putExtra("return-data", true);
startActivityForResult(intent, reqCode_Zoom);
}//這里是處理剪裁圖片返回後的處理,直接調用ImageView顯示了,你可以根據你的需要修改
else if(requestCode==reqCode_Zoom){
Bitmap bitmap = data.getExtras().getParcelable("data");
iv.setImageBitmap(bitmap);
}
上傳本地圖片方法:
按鈕名.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// 隱式啟動系統相冊程序
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setDataAndType(Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(intent, reqCode_PICK);// reqCode和上面一樣自己定義,但是不要重復了
}
});
再在onActivityResult方法添加一個"elseif(requestCode == reqCode_PICK && resultCode== RESULT_OK)"條件,方法體直接參考上面,就是在剪裁那裡把「intent.putExtra("data", data.getExtras().getParcelable("data"));」換為「intent.setDataAndType(data.getData(), "image/*");」就可以了。
⑤ android studio如何調用系統相冊
在Android Studio中,可以使用Intent調用含嘩握系統相冊。以下是具體步驟:
1. 在你的Android Studio項目中創建一個Button或ImageView,用於觸發打開相冊的事件。
2. 在Button或ImageView的OnClick事件中添加以下代碼:
Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, PICK_IMAGE_REQUEST);
其中,PICK_IMAGE_REQUEST是一個整數常量,用於在Activity返回結果時進行識別。
3. 在Activity中添加以下代碼,以處理從相冊返回的結果:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
Uri uri = data.getData();
// 使用uri載入圖片
}
}
在這個方法中,蘆衫我們檢查requestCode是否等於PICK_IMAGE_REQUEST,resultCode是否等於RESULT_OK,以及data和data.getData()是否不為null。如果這些條件都滿足,我們就可以使用data.getData()方法獲取從相冊中選擇的圖片的Uri,並使用這個Uri載入圖片。
注意:在使用打開談慶相冊的Intent時,需要在AndroidManifest.xml文件中添加以下許可權:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
這個許可權用於讀取存儲在設備上的圖片。
⑥ android如何獲取本地文件屬性信息
通過主動的方式通知系統我們需要文件列表,要向系統發送廣播
java">sendBroadcast(newIntent(Intent.ACTION_MEDIA_MOUNTED,Uri.parse(「file://」
+Environment.getExternalStorageDirectory())));
然後通過接收器獲取系統文列表
{
privatefinalstaticStringTAG=」MediaScannerReceiver」;
@Override
publicvoidonReceive(Contextcontext,Intentintent){
Stringaction=intent.getAction();
Uriuri=intent.getData();
StringexternalStoragePath=Environment.getExternalStorageDirectory().getPath();
if(action.equals(Intent.ACTION_BOOT_COMPLETED)){
//scaninternalstorage
scan(context,MediaProvider.INTERNAL_VOLUME);
}else{
if(uri.getScheme().equals(「file」)){
//
Stringpath=uri.getPath();
if(action.equals(Intent.ACTION_MEDIA_MOUNTED)&&
externalStoragePath.equals(path)){
scan(context,MediaProvider.EXTERNAL_VOLUME);
}elseif(action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)&&
path!=null&&path.startsWith(externalStoragePath+」/」)){
scanFile(context,path);
}
}
}
}
privatevoidscan(Contextcontext,Stringvolume){
Bundleargs=newBundle();
args.putString(「volume」,volume);
context.startService(
newIntent(context,MediaScannerService.class).putExtras(args));
}
privatevoidscanFile(Contextcontext,Stringpath){
Bundleargs=newBundle();
args.putString(「filepath」,path);
context.startService(
newIntent(context,MediaScannerService.class).putExtras(args));
}
}
⑦ Android-DataBinding原理分析
在MainActivity中,調用下面的方法:
appuildintermediatesdata_binding_layout_info_type_mergedebugout
可以看到,這里定義了多個Target標簽,這些Target的定義,其實就是定義對應的tag,將tag與activity_main.xml布局中的對應的View的id對應起來
經過DataBinding變化後的布局,會多出tag。
app/build/imtermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml
其實DataBindingUtil的setContentView()方法,主要就是調用activity的setContentView設置布局,並且綁定添加對應的View
這里的sMapper是一個DataBinderMapper對象,其實現類是DataBinderMapperImpl
DataBinderMapperImpl是通過apt註解處理器生成的。
這里的sMapper.getDataBinder()其實就是調用的MergedDataBinderMapper的getDataBinder()方法
而sMapper中的數據,其實就是DataBinderMapperImpl的構造器中調用其父類MergedDataBinderMapper 的addMapper()方法添加的對象
在DataBinding中有兩個DataBinderMapperImpl類,一個是上面這個在androidx.databinding包下,繼承了MergedDataBinderMapper的,另一個是在com.example.databindingdemo應用包下,直接繼承DataBinderMapper。其實MergedDataBinderMapper也是繼承自DataBinderMapper
這里要注意兩點,就是如果是布局的頂層View,比如tag為layout/activity_main_0,那麼就會new一個ActivityMainBindingImpl對象。這個tag,其實可以從前面看到的app/build/imtermediates/incremental/mergeDebugResources/stripped.dir/layout/activity_main.xml布局中的LinearLayout的tag知道
在new出ActivityMainBindingImpl對象後,則進行一些View的綁定操作,將通過tag取出的View與ActivityMainBindingImpl中對應的View屬性進行綁定。
在這里,會調用了一個mapBindings方法,第三個參數是一個3,這個3的意思,就是activity_main.xml布局文件中有3個節點
mapBindings就會返回一個Object[] bindings數組。
這里的主要工作,就是將布局中的View保存在對應的bindings數組中,然後取出這個數組中的數據賦值給ActivityMainBindingImpl中的View
ActivityMainBindingImpl的父類ActivityMainBinding是在Eappuildgenerateddata_binding_base_class_source_包下
BR的作用: 其實BR的作用,就用BR中的屬性值來標記不同的操作需要的監聽在mLocalFieldObservers數組中的位置
這里的localFieldId=0,這個id其實就BR文件中的id,就是BR文件中對應的靜態final屬性的值。而第二個就是觀察者對象,比如傳入的ViewModel對象。
這里通過WeakListener監聽器中的ObservableReference對象保存觀察者與被觀察者,當被觀察者發生改變的時候,就會找到對應的WeakListener監聽器,然後通知觀察者做修改。
而ObservableReference方法的實現,有多個,比如:WeakPropertyListener。
這里讓WeakListener.setTarget()其實就是通過WeakPropertyListener給被觀察者添加callback,然後當被觀察者數據發生改變的時候,被觀察者通過遍歷其內部的PropertyChangeRegistry中的OnPropertyChangedCallback回調(其實就是WeakPropertyListener),然後通過WeakPropertyListener監聽通知給ViewDataBinding以及其實現類ActivityMainBindingImpl具體進行數據的處理和設置。
// 這里的mTarget其實是一個泛型T對象,而這個泛型是在WeakPropertyListener初始化WeakListener的時候傳入的一個Observable,這個是databinding中的Observable,其子類實現就是BaseObservable
WeakPropertyListener中的addListener方法,就會給Observable添加一個callback回調,向Observable這個被觀察者中添加callback的目的,就是在Observable數據發生變化的時候,遍歷Observable中的mCallbacks這個callback集合,通知觀察者進行修改。
從這第三步可以知道:
而WeakPropertyListener和WeakListener是相互持有的對方的引用。
在完成監聽的相互綁定關系,並且給Observable添加了回調之後,就會回到ActivityMainBindingImpl的setUser()方法繼續執行notifyPropertyChanged()方法。
但是這里的例子有個問題,就是監聽是添加在User這個BaseObservable的子類中的,但是更新的時候,並不是通過這個User來進行通知,而是根據ActivityMainBindingImpl這個BaseObservable來通知,那麼這個時候並不會通過ActivityMainBindingImpl的調用notifyPropertyChanged()最終拿到User中的PropertyChangeRegistry對象mCallbacks,所以起作用的並不是這句話。而最終ActivityMainBindingImpl在設置User起刷新作用,是因為super.requestRebind()的調用也觸發了mRebindRunnable任務的執行,其實就是沒有通過PropertyChange來觸發requestRebind()
這里其實就是調用的BaseObservable的notifyPropertyChanged()方法,因為ActivityMainBindingImpl是ViewDataBinding的子類,而ViewDataBinding繼承了BaseObservable類
這里的mNotifier.notifyCallback其實就會調用到下面的PropertyChangeRegistry中定義的NOTIFIER_CALLBACK 屬性中的onNotifyCallback實現,而這里的callback其實就是WeakPropertyListener,因為WeakPropertyListener是OnPropertyChangedCallback的子類,這里其實會回調給mLocalFieldObservers數組中所有的WeakListener
從mListener中取出target,而這里的mListener其實就是,WeakListener,而每個被觀察者,其實都是有一個對應的LocalFieldId,這個id就是BR文件中定義的,剛才的流程中,我們傳入的是0,所以這里的 mLocalFieldId=0
這里的onFieldChange的方法的實現,就是在ActivityMainBindingImpl.java中
這里因為fieldId=0,所以會進入第一個if條件if (fieldId == BR._all),所以會返回true,所以就會返回到ViewDataBinding.java中的handleFieldChange方法中,繼續執行requestRebind()
這里最終都會執行mRebindRunnable的run()方法。只不過SDK版本大於等於16的時候,會採用Choreographer編舞者來處理,而之前的版本則是採用Handler來執行。
在這里最終就會執行到executeBindings()方法,而該方法的實現,又是在ActivityMainBindingImpl.java中
如果自定義類繼承了BaseObservable類,則會更新注冊監聽。即BaseObservable保存PropertyChangeRegistry對象,該對象中會保存WeakPropertyListener監聽,而WeakPropertyListener監聽會持有WeakListener,WeakListener也會持有WeakPropertyListener,並且持有一個BaseObservable的target,這個target就是自定義的BaseObservable子類實現對象,在設置target的時候就會將WeakPropertyListener監聽給保存在這個target中的PropertyChangeRegistry對象中,當使用自定義的BaseObservable進行更新的時候,就可以通過監聽回調的方式通知到ActivityMainBindingImpl這些ViewDataBinding中,然後向ActivityMainBindingImpl解析得到的View實體中設置對應的數據。
通過WeakListener監聽器中的ObservableReference對象保存觀察者與被觀察者,當被觀察者發生改變的時候,就會找到對應的WeakListener監聽器,然後通知觀察者做修改。
而ObservableReference方法的實現,有多個,比如:WeakPropertyListener。
這里讓WeakListener.setTarget()其實就是通過WeakPropertyListener給被觀察者添加callback,然後當被觀察者數據發生改變的時候,被觀察者通過遍歷其內部的PropertyChangeRegistry中的OnPropertyChangedCallback回調(其實就是WeakPropertyListener),然後通過WeakPropertyListener監聽通知給ViewDataBinding以及其實現類ActivityMainBindingImpl具體進行數據的處理和設置。
其實就是向ViewModel或者自定義的Observable(是databinding中的Observable)的子類實現中的mCallbacks中添加監聽WeakPropertyListener,用於數據變化回調。而在WeakPropertyListener中的WeakListener對象會保存這個Observable為target,用於在更新的時候取出。
比如在xml布局的data中直接使用Boolean、Integer、String等類型
如果ActivityMainBindingImpl中設置的是比如ViewModel,那麼就需要看是否使用了LiveData修飾的屬性,如果沒有使用LiveData的,則並不會去更新注冊監聽信息,而只是重新保存ViewDataBinding中保存的數據實體,並且直接調用ActivityMainBinding中保存的View實體進行設置新的數據
如果是使用了LiveData的話,則會在調用LiveDataListener(這是一個Observer子類與上面的WeakPropertyListener類似)的addListener的時候,就會給LiveData注冊觀察者LiveDataListener,然後在LiveDataListener中的onChanged實現中通過調用ViewDataBinding的handleFieldChange方法觸發數據變化修改,進而更新View顯示的數據