溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

IOS程序員必須知道的Android要點(diǎn)有哪些

發(fā)布時(shí)間:2021-12-18 16:31:11 來源:億速云 閱讀:167 作者:iii 欄目:移動(dòng)開發(fā)

本篇內(nèi)容介紹了“IOS程序員必須知道的Android要點(diǎn)有哪些”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

UI設(shè)計(jì)簡要說明

本文不 會深入研究關(guān)于IOS和Android兩個(gè)平臺之間的用戶體驗(yàn)或者設(shè)計(jì)模式之間的差異,不過如果能夠理解Android上的一些優(yōu)秀的UI范例也很有幫 助:ActionBar、Overflow menu、back button share action等等。假如你很想嘗試Android開發(fā),那么強(qiáng)烈推薦你去Google Play Store上購置一臺Nexus5,然后把它作為你日常使用的設(shè)備使用一周,然后嘗試仔細(xì)了解這個(gè)操作系統(tǒng)的各種功能和擴(kuò)展特性,如果開發(fā)者連操作系統(tǒng)的 各種使用規(guī)則都不了解,那么做出來的產(chǎn)品一定有問題。

編程語言的應(yīng)用框架

Objective-C和Java之間有很多不同之處,如果把Objective-C的編程風(fēng)格帶到Java里面的話,很多代碼也許會和底層的應(yīng)用框架沖突。簡單地說,就是需要注意一些區(qū)別:

去掉Objective-C里面的類前綴,因?yàn)镴ava里有顯式的命名空間和包結(jié)構(gòu),所以就沒必要用類前綴了。

實(shí)例變量的前綴用“m”,不用“_”,在寫代碼的過程中要多利用JavaDoc文檔。這樣能使代碼更清晰,更適合團(tuán)隊(duì)合作。

注意檢查NULL值,Objective-C對空值檢查做的很好,不過Java沒有。

不直接使用屬性,如果需要setter和getter,需要?jiǎng)?chuàng)建一個(gè)getVariableName()方法,然后顯式調(diào)用它。如果直接使用“this.object”不會調(diào)用自定義的getter方法,你必須使用this.getObject這樣的方法。

同樣的,方法命名時(shí)帶有g(shù)et和set前綴來標(biāo)示它是getter和setter方法,Java的方法很喜歡寫成actions或者queries等,比如Java會使用getCell(),而不用cellForRowAtIndexPath。

項(xiàng)目結(jié)構(gòu)

Android 應(yīng)用程序主要分為兩部分。***部分是Java源代碼,以Java包結(jié)構(gòu)排布,也可以根據(jù)自己的喜好進(jìn)行結(jié)構(gòu)排布。最基本的結(jié)構(gòu)就是分為這幾個(gè)頂層目 錄:activities、fragments、views、adapters和data(models和managers)。

第 二部分是res文件夾,就是“resource”的簡稱,res目錄存放的是圖片、xml布局文件,還有其它xml值文件,是非代碼資源的一部分。在 IOS上,圖片只需要匹配兩個(gè)尺寸,而在Android上有很多種屏幕尺寸需要考慮,Android上用文件夾來管理管理圖片、字符串,還有其它的屏幕配 置數(shù)值等。res文件夾里也含有類似IOS中xib文件的xml文件,還有存儲字符串資源、整數(shù)值,以及樣式的xml文件。

***,在項(xiàng)目結(jié)構(gòu)上還有一點(diǎn)相似的地方,就是AndroidManifest.xml文件。這個(gè)文件相當(dāng)于IOS的Project-Info.plist文 件,它存儲了activities、application還有Intent的信息,要了解更多關(guān)于Intent的資料,可以繼續(xù)閱讀這篇文章。

Activities

Activities 是Android APP最基本的可視單元,就像UIViewControllers是IOS最基本的顯示組件一樣。Android系統(tǒng)使用一個(gè)Activity棧來管理 Activity,而IOS使用UINavigationController進(jìn)行管理。當(dāng)APP啟動(dòng)的時(shí)候,Android系統(tǒng)會把Main Activity壓棧,值得注意的是這是還可以再運(yùn)行別的APP Activity,然后把它放到Activity棧中。返回鍵默認(rèn)會從Activity棧進(jìn)行pop操作,所以如果用戶按下返回鍵,就可以切換運(yùn)行已運(yùn)行 的App了。

Activities還可以用Intent組件初始化別的Activity,初始化時(shí) 可攜帶數(shù)據(jù)。啟動(dòng)一個(gè)新的Activity類似于IOS上創(chuàng)建一個(gè)UIViewController。最基本的啟動(dòng)一個(gè)新的Activity的方式就是創(chuàng) 建一個(gè)帶有data的Intent組件。Android上實(shí)現(xiàn)自定義Intent初始化器的***方法就是寫一個(gè)靜態(tài)getter方法。在Activity 結(jié)束的時(shí)候也可以返回?cái)?shù)據(jù),在Activity結(jié)束的時(shí)候可以往Intent里面放置額外的數(shù)據(jù)。

IOS 和Android的一個(gè)大的區(qū)別是,任何一個(gè)在AndroidManifest文件中注冊的Activity都可以作為程序的入口,為Activity設(shè) 置一個(gè)intent filter屬性比如“media intent”,就可以處理系統(tǒng)的媒體文件了。***的例子就是編輯照片Activity。它可以打開一張照片,然后進(jìn)行修改,***在Activity結(jié)束 時(shí)返回修改后的照片。

附加提醒:要想在Activity和Fragment之間傳遞對象,必須要實(shí) 現(xiàn)Parcelable接口,就像在IOS里需要遵循協(xié)議一樣。還有,Parcelable對象可以存在于Activity或者Fragment的 savedInstanceState里,這樣在它們被銷毀后可以更容易重建它們的狀態(tài)。

下面就來看看怎么在一個(gè)Activity中啟動(dòng)另一個(gè)Activity,然后在第二個(gè)Activity結(jié)束時(shí)進(jìn)行返回。

啟動(dòng)其它Activity并返回結(jié)果

// A request code is a unique value for returning activities private static final int REQUEST_CODE_NEXT_ACTIVITY = 1234;   protected void startNextActivity() {     // Intents need a context, so give this current activity as the context     Intent nextActivityIntent = new Intent(this, NextActivity.class);        startActivityForResult(nextActivityResult, REQUEST_CODE_NEXT_ACTIVITY); }   @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {     switch (requestCode) {     case REQUEST_CODE_NEXT_ACTIVITY:         if (resultCode == RESULT_OK) {             // This means our Activity returned successfully. For now, Toast this text.               // This just creates a simple pop-up message on the screen.                 Toast.makeText(this, "Result OK!", Toast.LENGTH_SHORT).show();             }             return;         }             super.onActivityResult(requestCode, resultCode, data); }

Fragment 的概念在Android上比較獨(dú)特,從Android3.0開始引入。Fragment是一個(gè)迷你版的控制器,可以顯示在Activity上。它有自己的 狀態(tài)和邏輯,同時(shí)在一個(gè)屏幕上支持多個(gè)Fragment同時(shí)顯示。Activity充當(dāng)Fragment的控制器,F(xiàn)ragment沒有自己的上下文環(huán) 境,只能依賴Activity存在。

使用Fragment***的例子就是在平板上的應(yīng)用。可以在屏幕左邊放一個(gè)fragment列表,然后在屏幕的右邊放fragment的詳細(xì)信息。Fragment可以把屏幕分成可重復(fù)利用的小塊,分別控制管理。不過要注意Fragment的生命周期,會有些細(xì)微的差別。

IOS程序員必須知道的Android要點(diǎn)有哪些

Fragment 是實(shí)現(xiàn)Android結(jié)構(gòu)化的一種新的方式,就像IOS中的不用UITableview而用UICollectionView實(shí)現(xiàn)列表數(shù)據(jù)結(jié)構(gòu)化。因?yàn)橹?使用Activity而不用Fragment的話,會簡單一些。不過,之后你會遇到麻煩。如果不使用Fragment代替全盤使用Activity的話, 在后面需要利用intent和進(jìn)行多屏幕支持的時(shí)候就會遇到困難。

下面看一個(gè)UITableViewController的例子和一個(gè)ListFragment的地鐵時(shí)刻表示例。

表格實(shí)現(xiàn)

IOS程序員必須知道的Android要點(diǎn)有哪些

@interface MBTASubwayTripTableTableViewController ()   @property (assign, nonatomic) MBTATrip *trip;   @end   @implementation MBTASubwayTripTableTableViewController   -(instancetype)initWithTrip:(MBTATrip *)trip {     self = [super initWithStyle:UITableViewStylePlain];     if (self) {         _trip = trip;         [self setTitle:trip.destination];     }     return self; }   -(void)viewDidLoad {     [super viewDidLoad];           [self.tableView registerClass:[MBTAPredictionCell class] forCellReuseIdentifier:[MBTAPredictionCell reuseId]];     [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([MBTATripHeaderView class]) bundle:nil] forHeaderFooterViewReuseIdentifier:[MBTATripHeaderView reuseId]]; }   #pragma mark - UITableViewDataSource   -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {     return 1; }   -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {     return [self.trip.predictions count]; }   #pragma mark - UITableViewDelegate   -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {     return [MBTATripHeaderView heightWithTrip:self.trip]; }   -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {     MBTATripHeaderView *headerView = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:[MBTATripHeaderView reuseId]];     [headerView setFromTrip:self.trip];     return headerView; }   -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[MBTAPredictionCell reuseId] forIndexPath:indexPath];           MBTAPrediction *prediction = [self.trip.predictions objectAtIndex:indexPath.row];     [(MBTAPredictionCell *)cell setFromPrediction:prediction];           return cell; }   -(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {     return NO; }   - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {     [tableView deselectRowAtIndexPath:indexPath animated:YES]; }   @end

List Fragment實(shí)現(xiàn)

IOS程序員必須知道的Android要點(diǎn)有哪些

public class TripDetailFragment extends ListFragment {       /**      * The configuration flags for the Trip Detail Fragment.      */     public static final class TripDetailFragmentState {         public static final String KEY_FRAGMENT_TRIP_DETAIL = "KEY_FRAGMENT_TRIP_DETAIL";     }       protected Trip mTrip;       /**      * Use this factory method to create a new instance of      * this fragment using the provided parameters.      *      * @param trip the trip to show details      * @return A new instance of fragment TripDetailFragment.      */     public static TripDetailFragment newInstance(Trip trip) {         TripDetailFragment fragment = new TripDetailFragment();         Bundle args = new Bundle();         args.putParcelable(TripDetailFragmentState.KEY_FRAGMENT_TRIP_DETAIL, trip);         fragment.setArguments(args);         return fragment;     }       public TripDetailFragment() { }       @Override     public View onCreateView(LayoutInflater inflater, ViewGroup container,                              Bundle savedInstanceState) {         Prediction[] predictions= mTrip.predictions.toArray(new Prediction[mTrip.predictions.size()]);         PredictionArrayAdapter predictionArrayAdapter = new PredictionArrayAdapter(getActivity(), predictions);         setListAdapter(predictionArrayAdapter);         return super.onCreateView(inflater,container, savedInstanceState);     }       @Override     public void onViewCreated(View view, Bundle savedInstanceState) {         super.onViewCreated(view, savedInstanceState);         TripDetailsView headerView = new TripDetailsView(getActivity());         headerView.updateFromTripObject(mTrip);         getListView().addHeaderView(headerView);     } }

下面,我們來分析Android上特有的一些組件。

Android通用組件

ListView和Adapter

ListView 和IOS的UITableView最像,也是使用最頻繁的組件之一。類似于UITableView的 UITableViewController,ListView也有一個(gè)ListActivity,還有ListFragment。這些組件會更好地處理 一些布局問題,也為操作數(shù)據(jù)適配器提供了便利,這個(gè)接下來會說到。下面這個(gè)例子就是使用ListFragment來展示數(shù)據(jù),類似TableView的 datasource。

關(guān)于datasource,Android上沒有datasource和 delegate,只有Adapter。Adapter有很多種形式,主要功能其實(shí)就是為了把datasource和delegate合在一起。 Adapter拿到數(shù)據(jù)然后填充到Listview中,在ListView中初始化響應(yīng)的組件并顯示出來,下面是arrayAdapter的使用:

public class PredictionArrayAdapter extends ArrayAdapter {       int LAYOUT_RESOURCE_ID = R.layout.view_three_item_list_view;       public PredictionArrayAdapter(Context context) {         super(context, R.layout.view_three_item_list_view);     }       public PredictionArrayAdapter(Context context, Prediction[] objects) {         super(context, R.layout.view_three_item_list_view, objects);     }       @Override     public View getView(int position, View convertView, ViewGroup parent)     {         Prediction prediction = this.getItem(position);         View inflatedView = convertView;         if(convertView==null)         {             LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);             inflatedView = inflater.inflate(LAYOUT_RESOURCE_ID, parent, false);         }           TextView stopNameTextView = (TextView)inflatedView.findViewById(R.id.view_three_item_list_view_left_text_view);         TextView middleTextView = (TextView)inflatedView.findViewById(R.id.view_three_item_list_view_middle_text_view);         TextView stopSecondsTextView = (TextView)inflatedView.findViewById(R.id.view_three_item_list_view_right_text_view);           stopNameTextView.setText(prediction.stopName);         middleTextView.setText("");         stopSecondsTextView.setText(prediction.stopSeconds.toString());           return inflatedView;     } }

可 以看到,adapter里面有一個(gè)很重要的方法叫g(shù)etView,和IOS的cellForRowAtIndexPath方法一樣。還有一個(gè)相似之處就是 循環(huán)利用的策略,和IOS6上的實(shí)現(xiàn)很相似。在Android和IOS上循環(huán)利用View都很重要,事實(shí)上它對列表的實(shí)現(xiàn)有很大幫助。這個(gè)adapter 很簡單,使用了一個(gè)內(nèi)建的類ArrayAdapter來存放數(shù)據(jù),也解釋了怎么把數(shù)據(jù)填入ListView中。

AsyncTask

對于IOS上的Grand Central Dispatch,Android上也有AsyncTask。它是異步操作工具的又一選擇,用一種很友好的方式實(shí)現(xiàn)異步任務(wù)。不過AsyncTask有點(diǎn)超出了本文的范圍,所以本人還是推薦你看看這里。

Activity的生命周期

IOS開發(fā)者在寫Android的過程中還要注意的就是Android的生命周期??梢韵葟腁ctivity的生命周期文檔開始:

IOS程序員必須知道的Android要點(diǎn)有哪些

本 質(zhì)上Activity的生命周期很像UIViewController的生命周期,主要區(qū)別在于Android上可以任意銷毀Activity,所以保證 Activity的數(shù)據(jù)和狀態(tài)很重要,如果在onCreate()中保存了的話,可以在saved state中恢復(fù)Activity的狀態(tài)。***的方法就是使用saveInstanceState來存儲bundled數(shù)據(jù),例如下面的 TripListActivity是示例工程的一部分,用來保存當(dāng)前顯示的數(shù)據(jù):

public static Intent getTripListActivityIntent(Context context, TripList.LineType lineType) {     Intent intent = new Intent(context, TripListActivity.class);     intent.putExtra(TripListActivityState.KEY_ACTIVITY_TRIP_LIST_LINE_TYPE, lineType.getLineName());     return intent; }   public static final class TripListActivityState {     public static final String KEY_ACTIVITY_TRIP_LIST_LINE_TYPE = "KEY_ACTIVITY_TRIP_LIST_LINE_TYPE"; }       TripList.LineType mLineType;           @Override protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    mLineType = TripList.LineType.getLineType(getIntent().getStringExtra(TripListActivityState.KEY_ACTIVITY_TRIP_LIST_LINE_TYPE)); }

還 有一個(gè)要注意的地方就是屏幕旋轉(zhuǎn):如果屏幕發(fā)生旋轉(zhuǎn),會改變Activity的生命周期。也就是說,Activity會先被銷毀,然后再重建。如果已經(jīng)保 存了數(shù)據(jù)和狀態(tài),Activity可以重建原來的狀態(tài),實(shí)現(xiàn)無縫重建。很多APP開發(fā)者在遇到APP旋轉(zhuǎn)時(shí)會出現(xiàn)問題,因?yàn)锳ctivity沒有處理旋轉(zhuǎn) 的改變。注意不要用鎖定屏幕的方向來解決這個(gè)問題,因?yàn)檫@樣會存在一個(gè)隱含的生命周期的bug,在某些情況下還是可能發(fā)生的。

Fragment生命周期

Fragment的生命周期和Activity的很像,但是有一些區(qū)別:

IOS程序員必須知道的Android要點(diǎn)有哪些

還 有一個(gè)問題就是Fragment和Activity通信的問題。需要注意的是onAttach()方法在onActivityCreated()方法之前 被調(diào)用,這就意味著在fragment創(chuàng)建完成后Activity還不能保證已經(jīng)存在。如果需要為父Activity設(shè)置接口或者代理,則需要在 onActivityCreated()方法調(diào)用之后。

Fragment也有可能會在系統(tǒng)需要的時(shí)候被創(chuàng)建和銷毀。如果要保存它的狀態(tài),那么也要像Activity一樣進(jìn)行處理。下面這個(gè)是示例項(xiàng)目中的一個(gè)小例子,trip列表Fragment會記錄相應(yīng)的數(shù)據(jù),和上面的地鐵時(shí)間示例一樣:

/**  * The configuration flags for the Trip List Fragment.  */ public static final class TripListFragmentState {     public static final String KEY_FRAGMENT_TRIP_LIST_LINE_TYPE = "KEY_FRAGMENT_TRIP_LIST_LINE_TYPE";     public static final String KEY_FRAGMENT_TRIP_LIST_DATA = "KEY_FRAGMENT_TRIP_LIST_DATA"; }   /**  * Use this factory method to create a new instance of  * this fragment using the provided parameters.  *  * @param lineType the subway line to show trips for.  * @return A new instance of fragment TripListFragment.  */ public static TripListFragment newInstance(TripList.LineType lineType) {     TripListFragment fragment = new TripListFragment();     Bundle args = new Bundle();     args.putString(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_LINE_TYPE, lineType.getLineName());     fragment.setArguments(args);     return fragment; }   protected TripList mTripList; protected void setTripList(TripList tripList) {     Bundle arguments = this.getArguments();     arguments.putParcelable(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_DATA, tripList);     mTripList = tripList;     if (mTripArrayAdapter != null) {         mTripArrayAdapter.clear();         mTripArrayAdapter.addAll(mTripList.trips);     } }   @Override public void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     if (getArguments() != null) {         mLineType = TripList.LineType.getLineType(getArguments().getString(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_LINE_TYPE));         mTripList = getArguments().getParcelable(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_DATA);     } }

還 要注意的是,F(xiàn)ragment經(jīng)常會在onCreate方法中利用bundled參數(shù)重建自己的狀態(tài)。而自定義的Trip列表模型類相關(guān)的setter方 法也會把對象添加到bundled參數(shù)中。這樣就可以保證在Fragment被銷毀或者重建時(shí),比如屏幕旋轉(zhuǎn)后,可以利用***的數(shù)據(jù)去重建狀態(tài)。

關(guān)于布局

和Android上其它部分的開發(fā)工作一樣,指定布局文件也有自己的優(yōu)缺點(diǎn)。Android上的布局文件都存放在res/layouts文件夾中,以易讀的xml形式存儲。

地鐵列表布局

IOS程序員必須知道的Android要點(diǎn)有哪些

xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     tools:context="com.example.androidforios.app.activities.MainActivity$PlaceholderFragment">               android:id="@+id/fragment_subway_list_listview"         android:layout_width="match_parent"         android:layout_height="match_parent"         android:paddingBottom="@dimen/Button.Default.Height"/>               android:id="@+id/fragment_subway_list_Button"         android:layout_width="match_parent"         android:layout_height="@dimen/Button.Default.Height"         android:minHeight="@dimen/Button.Default.Height"         android:background="@drawable/button_red_selector"         android:text="@string/hello_world"         android:textColor="@color/Button.Text"         android:layout_alignParentBottom="true"         android:gravity="center"/>

下面這個(gè)是IOS上用UITableView和UIButton來制作的類似效果:

IOS程序員必須知道的Android要點(diǎn)有哪些

IOS程序員必須知道的Android要點(diǎn)有哪些

可以發(fā)現(xiàn),Android的布局文件更容易閱讀和理解,而且提供了多種布局方式,我們只介紹了其中的一小部分。

通常來說,我們接觸的最基本的UI結(jié)構(gòu)就是ViewGroup的子類,RelativeLayout、LinearLayout、FrameLayout是最常用的。這些ViewGroup的子類可以容納別的View,并包含了一些排布控件的屬性。

一個(gè)很好的例子就是上面用到的RelativeLayout,在里面可以使用android:layout_alignParentBottom="true"來把按鈕定位到布局底部。

***,如果要在Fragment或者Activity中使用這些控件的話,可以在onCreateView()方法中使用布局的資源ID:

@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {     return inflater.inflate(R.layout.fragment_subway_listview, container, false); }

布局小貼士

請使用dp(density-independent pixels),不直接使用dx(pixels);

不要在可視化編輯器中移動(dòng)布局組件——通常來說可視化編輯器在你調(diào)好高和寬后,會為組件添加一些多余的像素,所以***就是直接操作xml文件;

如果在布局的height和width看到有用fill_parent這個(gè)屬性的話,你會發(fā)現(xiàn)在API 8的時(shí)候這個(gè)屬性就已經(jīng)被限制了,改用match_parent替換。

如果要了解更多關(guān)于這方面的內(nèi)容可以看看這篇文章——responsive android applications。

數(shù)據(jù)

Android上的數(shù)據(jù)存儲也和IOS上差不多:

SharedPreferences、NSUserDefaults;

內(nèi)存存儲對象;

internal、external文件讀寫document directory文件讀寫;

SQLite數(shù)據(jù)庫存儲Core Data形式數(shù)據(jù)庫存儲。

其中最基本的區(qū)別就是Core Data。在Android上可以直接訪問sqlite數(shù)據(jù)庫并可以返回cursor對象得到結(jié)果。更詳細(xì)的介紹請看這篇文章—— using SQLite on Android。

“IOS程序員必須知道的Android要點(diǎn)有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI