亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android MVP BaseFragment 通用式封裝的實(shí)現(xiàn)

 更新時(shí)間:2019年08月14日 14:45:59   作者:Android架構(gòu)師丨小熊  
這篇文章主要介紹了Android MVP BaseFragment 通用式封裝的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

這篇已經(jīng)是我們的 BaseMVP 基礎(chǔ)框架系列文章的第六篇了,BaseMVP 已經(jīng)被我們封裝了快差不多了,從上篇的文章(Android MVP 架構(gòu)(五)MVP 多個(gè) Presenter 依賴(lài)注入)中,我們解決了多的 Presenter 的問(wèn)題,這是利用依賴(lài)注入及反射的方式,動(dòng)態(tài)的去實(shí)例化不同 Presenter 層實(shí)現(xiàn)類(lèi),并且與同一個(gè) View 做了綁定和解綁的操作,這就是一個(gè) View 對(duì)多 Presenter 的需要手動(dòng) new 的解決方案。

BaseMVP 基礎(chǔ)框架的搭建,到這里的話(huà),還缺少一點(diǎn)東西。我們之前只封裝過(guò)了一個(gè)基類(lèi)的 BaseActivity 類(lèi),這個(gè)類(lèi)是提供給 Activity 來(lái)繼承的,但是,我們的實(shí)際項(xiàng)目中,難免會(huì)有 Fragment 的出現(xiàn),于是乎,今天我們又帶大家來(lái)封裝一個(gè) BaseFragment 基類(lèi)吧,盡量的把基礎(chǔ)框架給完善。

要封裝 BaseFragment 基類(lèi),參考 BaseActivity 的封裝并不難,因?yàn)?Activity 和 Fragment 的生命周期很相似,而且 Fragment 是寄托在 Activity 上的,所以說(shuō)白了都差不多,不過(guò)代碼肯定有一點(diǎn)偏差。對(duì)比之前的版本,這一次我在包中添加了一個(gè) BaseFragment 基類(lèi),以及添加了幾個(gè)測(cè)試它的類(lèi)。

下面我們來(lái)看看 BaseFragment 基類(lèi)吧,直接上代碼:

 

新建 BaseFragment 基類(lèi):

package com.test.mvp.mvpdemo.mvp.v6.basemvp;
 
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.test.mvp.mvpdemo.mvp.v6.inject.InjectPresenter;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
 
public abstract class BaseFragment extends Fragment implements IBaseView {
 
 private List<BasePresenter> mInjectPresenters;
 
 private View mLayoutView;
 
 protected abstract @LayoutRes int setLayout();
 
 protected abstract void initViews(@Nullable Bundle savedInstanceState);
 
 protected abstract void initData();
 
 @SuppressWarnings("ConstantConditions")
 protected <T extends View> T $(@IdRes int viewId) {
  return this.getView().findViewById(viewId);
 }
 
 @SuppressWarnings({"unchecked", "TryWithIdenticalCatches"})
 @Nullable
 @Override
 public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
  View view = inflater.inflate(setLayout(), container, false);
 
  mInjectPresenters = new ArrayList<>();
 
  //獲得已經(jīng)申明的變量,包括私有的
  Field[] fields = this.getClass().getDeclaredFields();
  for (Field field : fields) {
   //獲取變量上面的注解類(lèi)型
   InjectPresenter injectPresenter = field.getAnnotation(InjectPresenter.class);
   if (injectPresenter != null) {
    try {
     Class<? extends BasePresenter> type = (Class<? extends BasePresenter>) field.getType();
     BasePresenter mInjectPresenter = type.newInstance();
     //綁定
     mInjectPresenter.attach(this);
     field.setAccessible(true);
     field.set(this, mInjectPresenter);
     mInjectPresenters.add(mInjectPresenter);
    } catch (IllegalAccessException e) {
     e.printStackTrace();
    } catch (java.lang.InstantiationException e) {
     e.printStackTrace();
    } catch (ClassCastException e) {
     e.printStackTrace();
     throw new RuntimeException("SubClass must extends Class:BasePresenter");
    }
   }
  }
  return view;
 }
 
 @Override
 public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
  super.onViewCreated(view, savedInstanceState);
 
  initViews(savedInstanceState);
  initData();
 }
 
 @Override
 public void onDestroy() {
  super.onDestroy();
  for (BasePresenter presenter : mInjectPresenters) {
   presenter.detach();
  }
  mInjectPresenters.clear();
  mInjectPresenters = null;
 }
}

由于上篇文章中,我們使用了依賴(lài)注入,所以這里的 BaseFragment 類(lèi)的泛型參數(shù)就給我們?nèi)サ袅?。還有 BaseActivity 在這一版本中,我也去除了這個(gè)泛型參數(shù),如圖:

去除之后:

這里的 BaseActivity 就顯得干凈簡(jiǎn)潔了一點(diǎn),不然每次都需要傳入一個(gè)參數(shù),我覺(jué)得想想都累。好了,我們的 BaseFragment 與 BaseActivity 幾乎都一樣吧,這里也就不做多的解釋了,可以去看前面的幾篇文章中有對(duì)代碼的講解。

寫(xiě)完了一個(gè) BaseFragment 基類(lèi)后,然后就是迫不及待的去測(cè)試一些,到底能不能工作。這里,我新建了一個(gè) SecondActivity 類(lèi),目的就是為了在新的 Activity 中存放一個(gè) Fragment 用于測(cè)試。SecondActivity 沒(méi)有什么難度的代碼,就是在里面存放這一個(gè) SecondFragment,對(duì)了這里的 SecondActivity 并不是繼承我們的 BaseActivity 類(lèi),這就是一個(gè)普通的 Activity ,要特別注意。代碼很簡(jiǎn)單,如下:

新建 SecondActivity 類(lèi):

public class SecondActivity extends AppCompatActivity {
 
 @Override
 protected void onCreate(@Nullable Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_second);
  /**
   * 開(kāi)啟一個(gè) fragment
   */
  getSupportFragmentManager().beginTransaction().replace(R.id.second_container, new SecondFragment()).commit();
 }
}

SecondActivity 的布局:是一個(gè) FrameLayout 用于存放 SecondFragment。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context=".mvc.MainActivity">
 
 <FrameLayout
  android:id="@+id/second_container"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />
 
</android.support.constraint.ConstraintLayout>

接下來(lái),才是我們的 BaseFragment 類(lèi)的正真使用。我們新建一個(gè) SecondFragment 實(shí)現(xiàn)類(lèi),繼承與 BaseFragment 類(lèi),這里的 SecondFragment 就是 MVP 的 View 層了,與我們的 Activity 一樣,同屬于 View 層。這里,我偷懶,把 MainActivity 類(lèi)的基本代碼都考過(guò)來(lái)了。這里就不要太在意什么業(yè)務(wù)邏輯了,我們只要能測(cè)試 MVP 中的 BaseFragment 能夠工作就好了。來(lái)看代碼:

View 層:新建 SecondFragment 實(shí)現(xiàn)類(lèi):

package com.test.mvp.mvpdemo.mvp.v6.view;
 
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.widget.TextView;
import android.widget.Toast;
import com.test.mvp.mvpdemo.R;
import com.test.mvp.mvpdemo.mvp.v6.SecondContract;
import com.test.mvp.mvpdemo.mvp.v6.basemvp.BaseFragment;
import com.test.mvp.mvpdemo.mvp.v6.inject.InjectPresenter;
import com.test.mvp.mvpdemo.mvp.v6.presenter.SecondPresenter;
 
public class SecondFragment extends BaseFragment implements SecondContract.ISecondView {
 
 private TextView tvFragment;
 
 @InjectPresenter
 private SecondPresenter mPresenter;
 
 @Override
 protected int setLayout() {
  return R.layout.fragment_second;
 }
 
 @Override
 protected void initViews(@Nullable Bundle savedInstanceState) {
  tvFragment = $(R.id.tv_fragment);
 }
 
 @Override
 protected void initData() {
  mPresenter.handlerData();
 }
 
 @Override
 public void showDialog() {
//  Toast.makeText(getContext(), "this is Fragment", Toast.LENGTH_SHORT).show();
 }
 
 @SuppressWarnings("ConstantConditions")
 @Override
 public void succes(String content) {
  getActivity().runOnUiThread(new Runnable() {
   @Override
   public void run() {
    Toast.makeText(getContext(), "" + content, Toast.LENGTH_SHORT).show();
    tvFragment.setText(content);
   }
  });
 }
 
}

與之對(duì)應(yīng)的就是 SecondPresenter 了,我們的 Presenter 層代碼如下,代碼與前面幾篇文章一樣,這里不做介紹了,代碼如下所示:

###Presenter 層:新建 SecondPresenter 實(shí)現(xiàn)類(lèi):

package com.test.mvp.mvpdemo.mvp.v6.presenter;
 
import com.test.mvp.mvpdemo.mvp.v6.SecondContract;
import com.test.mvp.mvpdemo.mvp.v6.basemvp.BasePresenter;
import com.test.mvp.mvpdemo.mvp.v6.model.SecondModel;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;
 
public class SecondPresenter extends BasePresenter<SecondContract.ISecondView, SecondModel> implements SecondContract.ISecondPresenter {
 
 @Override
 public void handlerData() {
  getView().showDialog();
 
  getModel().requestBaidu(new Callback() {
   @Override
   public void onFailure(Call call, IOException e) {
   }
 
   @Override
   public void onResponse(Call call, Response response) throws IOException {
    String content = response.body().string();
    getView().succes(content);
   }
  });
 }
}

 接下來(lái)剩余的就是我們的 Model 層了,我們與之對(duì)應(yīng)的是 SecondModel 類(lèi),還是請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù),因?yàn)槲覀冎罢?qǐng)求的是百度首頁(yè)的網(wǎng)頁(yè)文本,為了形成區(qū)別,我這里將 URL 改成了我的 博客 地址,哈哈。代碼如下:

Model 層:新建 SecondModel 實(shí)現(xiàn)類(lèi):

package com.test.mvp.mvpdemo.mvp.v6.model;
 
import com.test.mvp.mvpdemo.mvp.v6.SecondContract;
import com.test.mvp.mvpdemo.mvp.v6.basemvp.BaseModel;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
 
public class SecondModel extends BaseModel implements SecondContract.ISecondModel {
 @Override
 public void requestBaidu(Callback callback) {
  OkHttpClient client = new OkHttpClient();
  Request request = new Request.Builder()
    .url("https://blog.csdn.net/smile_running")
    .build();
  client.newCall(request).enqueue(callback);
 }
}

最后,還有一個(gè)它們的契約類(lèi),其中都是接口類(lèi)型。代碼如下:

新建 SecondContract 接口類(lèi):

package com.test.mvp.mvpdemo.mvp.v6;
 
import com.test.mvp.mvpdemo.mvp.v6.basemvp.IBasePresenter;
import com.test.mvp.mvpdemo.mvp.v6.basemvp.IBaseView;
 
import okhttp3.Callback;
 
public interface SecondContract {
 interface ISecondModel {
  void requestBaidu(Callback callback);
 }
 
 interface ISecondView extends IBaseView {
  void showDialog();
 
  void succes(String content);
 }
 
 interface ISecondPresenter extends IBasePresenter {
  void handlerData();
 }
}

分包情況就是文章篇頭的那張包圖,好了,把代碼寫(xiě)完了,就跑起來(lái)試試吧。

這里的運(yùn)行情況是,從 MainActivity 中點(diǎn)擊 textview 跳轉(zhuǎn)到 SecondActivity,由于在 SecondActivity 顯示的是我們的 SecondFragment ,所以會(huì)從網(wǎng)絡(luò)上獲取我的博客的地址文本,返回將數(shù)據(jù)設(shè)置到 SecondFragment 的 textview 上,運(yùn)行效果就是這樣,如下圖:

好吧,效果雖然簡(jiǎn)單了點(diǎn),但我們的 BaseFragment 算是封裝完成了,經(jīng)過(guò)測(cè)試,也是能夠派上用場(chǎng)的了。經(jīng)過(guò)我們的不懈努力,又把 BaseMVP 基礎(chǔ)框架的搭建工作推進(jìn)了一小步,在 BaseFragment 的封裝過(guò)程中,我寫(xiě)的代碼確實(shí)出現(xiàn)了一些小失誤,這個(gè)是我們,原因是,我沒(méi)有去拷貝代碼!哈哈哈哈,好氣啊,花了我好大把時(shí)間去改這個(gè)錯(cuò)誤。

記錄錯(cuò)誤原因:在子線(xiàn)程中更新 UI 操作。

錯(cuò)誤代碼如下:在 SecondFragment 中更新 UI

 @Override
 public void succes(String content) {
  Toast.makeText(getContext(), "" + content, Toast.LENGTH_SHORT).show();
  tvFragment.setText(content);
 }

這個(gè)不是很簡(jiǎn)單嘛,這都不會(huì)改!

這可不一樣,它報(bào)的錯(cuò)誤信息可并不是子線(xiàn)程修改主線(xiàn)程異常,而是這么一堆錯(cuò)誤日志:

07-09 23:51:21.887 9769-9788/com.test.mvp.mvpdemo E/EGL_adreno: tid 9788: eglSurfaceAttrib(1319): error 0x3009 (EGL_BAD_MATCH)
07-09 23:51:21.915 9769-9788/com.test.mvp.mvpdemo E/EGL_adreno: tid 9788: eglSurfaceAttrib(1319): error 0x3009 (EGL_BAD_MATCH)
07-09 23:51:23.362 9769-9788/com.test.mvp.mvpdemo E/EGL_adreno: tid 9788: eglSurfaceAttrib(1319): error 0x3009 (EGL_BAD_MATCH)
07-09 23:51:27.742 9769-9788/com.test.mvp.mvpdemo E/EGL_adreno: tid 9788: eglSurfaceAttrib(1319): error 0x3009 (EGL_BAD_MATCH)
07-09 23:51:28.069 9769-9798/com.test.mvp.mvpdemo E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
 Process: com.test.mvp.mvpdemo, PID: 9769
 java.lang.reflect.UndeclaredThrowableException
  at $Proxy2.succes(Unknown Source)
  at com.test.mvp.mvpdemo.mvp.v6.presenter.SecondPresenter$1.onResponse(SecondPresenter.java:25)
  at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
  at java.lang.Thread.run(Thread.java:818)
  Caused by: java.lang.reflect.InvocationTargetException
  at java.lang.reflect.Method.invoke(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:372)
  at com.test.mvp.mvpdemo.mvp.v6.basemvp.BasePresenter$1.invoke(BasePresenter.java:31)
  at java.lang.reflect.Proxy.invoke(Proxy.java:397)
  at $Proxy2.succes(Unknown Source) 
  at com.test.mvp.mvpdemo.mvp.v6.presenter.SecondPresenter$1.onResponse(SecondPresenter.java:25) 
  at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138) 
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
  at java.lang.Thread.run(Thread.java:818) 
  Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
  at android.os.Handler.<init>(Handler.java:200)
  at android.os.Handler.<init>(Handler.java:114)
  at android.widget.Toast$TN.<init>(Toast.java:359)
  at android.widget.Toast.<init>(Toast.java:100)
  at android.widget.Toast.makeText(Toast.java:273)
  at com.test.mvp.mvpdemo.mvp.v6.view.SecondFragment.succes(SecondFragment.java:44)
  at java.lang.reflect.Method.invoke(Native Method) 
  at java.lang.reflect.Method.invoke(Method.java:372) 
  at com.test.mvp.mvpdemo.mvp.v6.basemvp.BasePresenter$1.invoke(BasePresenter.java:31) 
  at java.lang.reflect.Proxy.invoke(Proxy.java:397) 
  at $Proxy2.succes(Unknown Source) 
  at com.test.mvp.mvpdemo.mvp.v6.presenter.SecondPresenter$1.onResponse(SecondPresenter.java:25) 
  at okhttp3.RealCall$AsyncCall.run(RealCall.kt:138) 
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
  at java.lang.Thread.run(Thread.java:818) 
07-09 23:51:28.126 9769-9788/com.test.mvp.mvpdemo E/EGL_adreno: tid 9788: eglSurfaceAttrib(1319): error 0x3009 (EGL_BAD_MATCH) 

首先,我看了標(biāo)記中的第一個(gè)和第二個(gè)錯(cuò)誤原因,原來(lái)是反射那塊有問(wèn)題,根據(jù)它代碼中提示的位置,說(shuō)我的 Presenter 中的 getView() 方法出錯(cuò)了,如:

點(diǎn)擊去看了下,是動(dòng)態(tài)代理的代碼,這里搞什么鬼,我又沒(méi)修改這里的代碼,怎么就錯(cuò)了呢?

一臉懵逼的我,回頭看了看,在這里嘗試了斷點(diǎn)調(diào)試,沒(méi)有什么結(jié)果。后來(lái)意外發(fā)現(xiàn),我的把上面圖中的 getView().succes(content) 注釋掉了就不報(bào)錯(cuò)了。這才找到了原因,原來(lái)是這里的數(shù)據(jù)是通過(guò)網(wǎng)絡(luò)請(qǐng)求傳過(guò)來(lái)的,我們的 okhttp 需要轉(zhuǎn)到 ui 線(xiàn)程中去更新,這個(gè)我是知道的。

所以要記得,切到主線(xiàn)程去更新 UI 操作。雖然發(fā)生了一點(diǎn)小失誤,剛開(kāi)始以為是動(dòng)態(tài)代理的問(wèn)題,所以查了好多關(guān)于動(dòng)態(tài)代理的知識(shí),借此還能學(xué)到一點(diǎn)額外的知識(shí),美滋滋,哈哈。

這里的 BaseFragment 還是有代碼重復(fù)的問(wèn)題,比如我們的依賴(lài)注入那塊代碼,就放到下篇文章中去解決這個(gè)問(wèn)題吧,這篇文章已經(jīng)完成我們?cè)撏瓿傻娜蝿?wù)了,明天的事情放到后天干吧,哈哈哈哈。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android OnFocuChangeListener焦點(diǎn)事件詳解

    Android OnFocuChangeListener焦點(diǎn)事件詳解

    這篇文章主要為大家詳細(xì)介紹了Android OnFocuChangeListener焦點(diǎn)事件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • android Palette調(diào)色板使用詳解

    android Palette調(diào)色板使用詳解

    本篇文章主要介紹了android Palette調(diào)色板使用詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • Android截屏分享功能

    Android截屏分享功能

    最近項(xiàng)目經(jīng)理交給我一個(gè)任務(wù),要求實(shí)現(xiàn)android截屏功能,包括Android截屏獲取圖片、將圖片保存到本地、通知系統(tǒng)相冊(cè)更新、通過(guò)微信、QQ、微博分享截屏圖片。小編把實(shí)現(xiàn)思路分享到腳本之家平臺(tái),需要的朋友參考下
    2017-12-12
  • Android實(shí)現(xiàn)簡(jiǎn)單的banner輪播圖

    Android實(shí)現(xiàn)簡(jiǎn)單的banner輪播圖

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)單的banner輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • Android使用SoundPool播放音效

    Android使用SoundPool播放音效

    這篇文章主要為大家詳細(xì)介紹了Android使用SoundPool播放音效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-07-07
  • Android自定義控件單位尺寸實(shí)現(xiàn)代碼

    Android自定義控件單位尺寸實(shí)現(xiàn)代碼

    這篇文章主要介紹了Android自定義控件單位尺寸實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • Android 高仿斗魚(yú)滑動(dòng)驗(yàn)證碼

    Android 高仿斗魚(yú)滑動(dòng)驗(yàn)證碼

    這篇文章主要介紹了Android 高仿斗魚(yú)滑動(dòng)驗(yàn)證碼的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-11-11
  • 在Flutter中制作翻轉(zhuǎn)卡片動(dòng)畫(huà)的完整實(shí)例代碼

    在Flutter中制作翻轉(zhuǎn)卡片動(dòng)畫(huà)的完整實(shí)例代碼

    最近Flutter的勢(shì)頭是越來(lái)越猛了,作為一個(gè)Android程序猿,我自然也是想要趕緊嘗試一把,這篇文章主要給大家介紹了關(guān)于在Flutter中制作翻轉(zhuǎn)卡片動(dòng)畫(huà)的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • Android使用Websocket實(shí)現(xiàn)聊天室

    Android使用Websocket實(shí)現(xiàn)聊天室

    這篇文章主要為大家詳細(xì)介紹了Android使用Websocket實(shí)現(xiàn)聊天室,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • Android Studio無(wú)法執(zhí)行Java類(lèi)的main方法問(wèn)題及解決方法

    Android Studio無(wú)法執(zhí)行Java類(lèi)的main方法問(wèn)題及解決方法

    這篇文章主要介紹了Android Studio無(wú)法執(zhí)行Java main方法的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03

最新評(píng)論