คุณสมบัติภาษา Java 7 พร้อม Android


188

แค่สงสัยว่ามีใครลองใช้คุณสมบัติภาษา Java 7 ใหม่กับ Android หรือไม่ ฉันรู้ว่า Android อ่าน bytecode ที่ Java พ่นออกมาและเปลี่ยนเป็น dex ดังนั้นฉันเดาคำถามของฉันคือมันสามารถเข้าใจ bytecode ของ Java 7 ได้หรือไม่?


10
หรือคุณอาจใช้คุณสมบัติภาษา Java 7 แต่คอมไพล์ไปยัง Java 6 bytecode?
MatrixFrog

2
Android Studio จะแจ้งเตือนคุณเมื่อสร้างโครงการใหม่: "ด้วย minSdkVersion น้อยกว่า 19 คุณไม่สามารถใช้การลองกับทรัพยากร แต่คุณสมบัติภาษา Java 7 อื่น ๆ ใช้ได้"
IgorGanapolsky

1
ใช่ฉันรู้ :) ในที่สุดเราก็ใช้ Java 7 ในโครงการของเรา
Daniel Ryan

คำตอบ:


165

หากคุณกำลังใช้Android สตูดิโอที่ Java 7 ภาษาควรเปิดใช้งานโดยอัตโนมัติโดยไม่ต้องแพทช์ใด ๆ การลองใช้ทรัพยากรต้องใช้ API ระดับ 19+ และเนื้อหา NIO 2.0 ขาดหายไป

ถ้าคุณไม่สามารถใช้ Java 7 คุณสมบัติดู@Nunoคำตอบ 's build.gradleเกี่ยวกับวิธีการแก้ไขของคุณ

ต่อไปนี้เป็นเพื่อประโยชน์ทางประวัติศาสตร์เท่านั้น


ส่วนเล็ก ๆ ของ Java 7 สามารถใช้กับ Android ได้อย่างแน่นอน (หมายเหตุ: ฉันเพิ่งทดสอบบน 4.1)

ก่อนอื่นคุณไม่สามารถใช้ ADT ของ Eclipse ได้เนื่องจากมีการเข้ารหัสยากที่มีเพียงคอมไพเลอร์ Java 1.5 และ 1.6 เท่านั้น คุณสามารถคอมไพล์ ADT อีกครั้ง แต่ฉันพบว่าไม่มีวิธีง่ายๆในการทำเช่นนั้นนอกเหนือจากการคอมไพล์ Android ทั้งหมดใหม่ด้วยกัน

แต่คุณไม่จำเป็นต้องใช้ Eclipse ตัวอย่างเช่นAndroid Studio 0.3.2 , IntelliJ IDEA CEและ IDEs ที่ใช้ javac อื่น ๆ รองรับการคอมไพล์เป็น Android และคุณสามารถตั้งค่าความสอดคล้องได้สูงสุดถึง Java 8 ด้วย:

  • ไฟล์→โครงสร้างโครงการ→โมดูล→ (เลือกโมดูลที่บานหน้าต่างที่ 2) →ระดับภาษา→ (เลือก "7.0 - Diamonds, ARM, multi-catch, ฯลฯ ")

การเปิดใช้งาน Java 7 บน IntelliJ

คุณลักษณะนี้อนุญาตให้ใช้ภาษา Java 7 เท่านั้นและคุณแทบจะไม่ได้รับประโยชน์อะไรเลยเนื่องจากการปรับปรุงครึ่งหนึ่งมาจากห้องสมุด คุณลักษณะที่คุณสามารถใช้ได้คือคุณสมบัติที่ไม่ขึ้นอยู่กับไลบรารี:

  • ผู้ประกอบการเพชร ( <>)
  • สวิตช์สตริง
  • หลายรายการ ( catch (Exc1 | Exc2 e))
  • ขีดเส้นใต้ในตัวเลขตัวอักษร ( 1_234_567)
  • ตัวอักษรไบนารี ( 0b1110111)

และคุณสมบัติเหล่านี้ไม่สามารถนำมาใช้เลย :

  • tryคำสั่งเมื่อใช้ทรัพยากร - เพราะต้องใช้อินเตอร์เฟซที่ไม่ได้มีอยู่ "java.lang.AutoCloseable" (นี้สามารถนำมาใช้ในที่สาธารณะ 4.4 ขึ้นไป)
  • คำอธิบายประกอบ @SafeVarargs - เนื่องจาก "java.lang.SafeVarargs" ไม่มีอยู่

... "ยัง" :) ปรากฎว่าแม้ว่าห้องสมุด Android จะกำหนดเป้าหมายที่ 1.6 แต่ที่มาของ Android นั้นมีอินเตอร์เฟสเช่นAutoCloseableและอินเทอร์เฟซแบบดั้งเดิมเช่นCloseableนั้นสืบทอดมาจาก AutoCloseable (SafeVarargs หายไปจริงๆ) เราสามารถยืนยันการมีอยู่ของมันผ่านการสะท้อนกลับ พวกเขาถูกซ่อนไว้เพียงเพราะ Javadoc มี@hideแท็กซึ่งทำให้ "android.jar" ไม่รวมไว้ด้วย

มีคำถามที่มีอยู่แล้วฉันจะสร้าง Android SDK ด้วย API ที่ซ่อนอยู่และภายในได้อย่างไร ในการรับวิธีการเหล่านั้นกลับมา คุณเพียงแค่ต้องแทนที่การอ้างอิง "android.jar" ที่มีอยู่ของแพลตฟอร์มปัจจุบันด้วยของเราที่กำหนดเองแล้ว Java 7 APIs จำนวนมากจะสามารถใช้ได้ (ขั้นตอนจะคล้ายกับที่อยู่ใน Eclipse ตรวจสอบโครงสร้างโครงการ→ SDK)

เพิ่มเติมจาก AutoCloseable (เฉพาะ) คุณลักษณะของไลบรารี Java 7 ต่อไปนี้ยังเปิดเผย:

  • คอนสตรัคเตอร์การเชื่อมโยงข้อยกเว้นใน ConcurrentModificationException, LinkageError และ AssertionError
  • วิธีการคงที่. compare () แบบดั้งเดิมสำหรับ: Boolean.compare (), Byte.compare (), Short.compare (), Character.compare (), Integer.compare (), Long.compare ()
  • สกุลเงิน : .getAvailableCurrencies (), .getDisplayName () (แต่ไม่มี. getNumericCode ())
  • BitSet : .previousSetBit () .previousClearBit () .valueOf () .toLongArray () .toByteArray ()
  • คอลเล็กชัน : .emptyEnumeration (), .emptyIterator (), .emptyListIterator ()
  • AutoCloseable
  • Throwable : .addSuppressed (), .getSuppressed () และตัวสร้างอาร์กิวเมนต์ 4 ตัว
  • ตัวอักษร : .compare (), .isSurrogate (), .getName (), .highSurrogate (), .lowSurrogate (), .isBmpCodePoint () (แต่ไม่มี. isAlphabetic () และ. isIdeographic ()
  • ระบบ: .lineSeparator () (ไม่มีเอกสาร?)
  • java.lang.reflect.Modifier : .classModifiers (), .constructorModifiers (), .fieldModifiers (), .interfaceModifiers (), .methodModifiers ()
  • NetworkInterface : .getIndex (), .getByIndex ()
  • InetSocketAddress : .getHostString ()
  • InetAddress : .getLoopbackAddress ()
  • คนตัดไม้: .getGlobal ()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer : .hasQueuedPredecessors ()
  • DeflaterOutputStream : 3 constructors ด้วย "syncFlush"
  • Deflater : .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate () พร้อมอาร์กิวเมนต์ 4 ตัว

นั่นคือทั้งหมดที่ โดยเฉพาะอย่างยิ่ง NIO 2.0 ไม่มีอยู่และ Arrays.asList ยังคงเป็น @SafeVarargs


2
คำตอบที่ดี ฉันหวังว่าการสนับสนุนระดับ jvm เต็มรูปแบบจะเกิดขึ้นเร็ว ๆ นี้ในอนาคตnio2และสินค้าอื่น ๆ จะเป็นข่าวดีอย่างแน่นอน
SD

4
มีค่าที่จะกล่าวถึงAutoCloseableอินเทอร์เฟซที่ไม่มีอยู่ในรันไทม์ของ Android จนกว่า ICS (หรืออาจจะจนถึง HoneyComb) ดังนั้นแม้ว่าคุณจะใช้ android.jar ที่ได้รับการติดตั้งแล้วคุณจะได้รับNoClassDefFoundErrorในระบบ 2.x
ไอดอล

2
@deviant: ต้องมีการปรับเปลี่ยน Dalvik VM เนื่องจาก Java 8 แลมบ์ดาใช้invokedynamicซึ่งไม่รองรับโดย JVM ที่กำหนดเป้าหมายเป็น Java 6
kennytm

2
คุณอาจต้องการเพิ่มการอัปเดตที่เป็นของ Android studio 3.2, รองรับภาษาระดับ 7 อย่างสมบูรณ์เช่นเดียวกับลองกับทรัพยากรถ้าคุณกำลังคอมไพล์ KitKat
JRaymond

4
ตอนนี้ลองใช้ทรัพยากรกับ SDK 19 (Android Kitkat) ได้แล้ว ดูtools.android.com/recent/androidstudio032released
Mohamed El-Nakib

70

แก้ไข: ในขณะที่เขียนนี้รุ่นล่าสุดคือ Android 9 และ Eclipse Indigo สิ่งที่มีการเปลี่ยนแปลงตั้งแต่นั้นมา

  • คำตอบที่เป็นประโยชน์

ใช่ฉันได้ลองแล้ว แต่นี่ไม่ใช่การทดสอบที่ยอดเยี่ยมเนื่องจากความเข้ากันได้ถูก จำกัด ไว้ที่ระดับ 6 โดยไม่มีวิธี (ไม่มีวิธีที่ง่ายอย่างน้อย) ในการใช้ Java 7:

  • ก่อนอื่นฉันติดตั้ง JDK7 บนเครื่องที่ไม่มีการติดตั้ง JDK อื่น - Eclipse และ Android ไม่ได้ติดตั้ง:

7 คือการติดตั้งบนเครื่องนี้เท่านั้น

  • จากนั้นฉันก็ติดตั้ง Eclipse Indigo ใหม่และตรวจสอบว่ามันใช้ JDK 7 จริง ๆ (เพราะนี่เป็นอันเดียวและนี่คืออันที่ฉันเลือกฉันจะแปลกใจ)

7 คือ Eclipse ที่ใช้โดยเฉพาะเท่านั้น

  • จากนั้นฉันติดตั้ง Android SDK เวอร์ชันล่าสุด (แก้ไข: Honeycomb, API13 ณ เวลาที่โพสต์นี้ถูกเขียน) พบ JDK 7 ของฉันและติดตั้งอย่างถูกต้อง เช่นเดียวกับ ADT

  • แต่ฉันประหลาดใจเมื่อพยายามรวบรวมและเรียกใช้แอพ Hello Word Android ความเข้ากันได้ถูกตั้งค่าเป็น Java 6 โดยไม่มีวิธีบังคับให้เป็น Java 7:

ความเข้ากันได้ถูก จำกัด ไว้ที่ Java 6

  • ฉันลองกับโปรเจคที่ไม่ใช่ Android, Java ปกติและฉันมีคำอธิบาย ดูเหมือนว่าระดับความเข้ากันได้จะถูก จำกัด โดย Eclipse (ดูข้อความที่ด้านล่างของภาพต่อไปนี้):

Eclipse จำกัด ตัวเองให้เข้ากันได้ระดับ 6

ดังนั้นผมจึงHello Worldทำงานและยังปพลิเคชันอื่น ๆ ที่มีความซับซ้อนมากขึ้นและใช้SQLite, Listview, SensorและCameraแต่นี้พิสูจน์เดียวที่จัดการของ Java 7 เข้ากันได้น่าจะทำได้ดีและการทำงานร่วมกับ Android

ดังนั้นมีคนลองกับ Ant เก่าที่ดีเพื่อข้ามข้อ จำกัด Eclipse ที่เห็นด้านบนหรือไม่

  • คำตอบที่เป็นประโยชน์

อย่างไรก็ตาม SDK ได้รับการออกแบบมาเพื่อใช้กับ Java 5 หรือ 6 ตามที่อธิบายไว้ที่นี่

เราอาจมีบางสิ่งที่ทำงานร่วมกับ Java 7 แต่มันจะใช้งานได้ "โดยไม่ได้ตั้งใจ" การสร้าง DEX อาจทำงานได้อย่างถูกต้องหรือไม่และเมื่อสร้าง DEX แล้วอาจทำงานได้หรือไม่ สิ่งนี้เพราะใช้ JDK ที่ไม่ผ่านการรับรองจะให้ผลลัพธ์ที่ไม่คาดคิดตามคำจำกัดความ

แม้ว่าจะมีใครบางคนสร้างแอพ Android สำเร็จภายใต้ Java 7 ธรรมดาสิ่งนี้ไม่ผ่านการรับรอง JDK กระบวนการเดียวกันที่นำไปใช้กับแอปพลิเคชันอื่นอาจล้มเหลวหรือแอปพลิเคชันที่เกิดขึ้นอาจมีข้อบกพร่องที่เชื่อมโยงกับการใช้ JDK นั้น ไม่แนะนำ.

สำหรับผู้ที่มีส่วนร่วมในการพัฒนา webapps สิ่งนี้เหมือนกับการปรับใช้เว็บแอพพลิเคชั่นที่สร้างขึ้นภายใต้ Java 5 หรือ 6 ภายใต้แอพพลิเคชันเซิร์ฟเวอร์ที่มีคุณสมบัติสำหรับ Java 4 เท่านั้น (ตัวอย่างเช่น Weblogic 8) สิ่งนี้อาจใช้งานได้ แต่นี่ไม่ใช่สิ่งที่สามารถแนะนำเพื่อวัตถุประสงค์อื่นได้


1
ขอบคุณสำหรับการตรวจสอบรายละเอียด ดังนั้นดูเหมือนว่าคุณไม่สามารถใช้คุณลักษณะของภาษา Java 7 แต่ยังคงใช้ Java 7 เป็น Java 6. หวังว่าการเปลี่ยนแปลงนี้เร็ว ๆ นี้ :)
แดเนียลไรอัน

นี่คือกับ Eclipse ด้วย Ant นี่อาจเป็นไปได้ หวังว่าคนที่ผมจะทำแบบทดสอบและผมโทษตัวเองว่าเป็นคนขี้เกียจเกินไปที่จะทำมัน :)
Shlublu

ใช่ Varga แต่ฉันไม่คิดว่าข้อ จำกัด ของรุ่นคอมไพเลอร์มาจาก Ant แต่มาจาก Eclipse
Shlublu

2
นอกจากนี้โปรดทราบว่าหากคุณเล่นด้วยจาวาหลายเวอร์ชันเครื่องมือที่ให้นั้นไม่สามารถใช้งานร่วมกันได้ สิ่งที่ฉันหมายถึงคือถ้าคุณลงชื่อแอปของคุณครั้งแรกด้วย jarsigner จากเครื่องมือ java 6 และหลังจากนั้นก็ติดตั้ง java 7 และลงนามในเวอร์ชันใหม่ของแอพของเราด้วย jarsigner ที่มาพร้อมกับ java 7 และ keystore เดียวกันก่อนหน้านี้ !
Timo

38

อ้างอิงจาก dalvikvm.com:

dx ที่รวมอยู่ใน Android SDK แปลงไฟล์ Java Class ของคลาส Java ที่คอมไพล์โดยคอมไพเลอร์ Java ปกติเป็นรูปแบบไฟล์คลาสอื่น (รูปแบบ. dex)

นั่นหมายความว่าไฟล์ต้นฉบับ. java ไม่สำคัญว่าเป็นไฟล์. class bytecode เท่านั้น

เท่าที่ผมทราบเพียงinvokedynamicถูกเพิ่มลงใน bytecode JVM ใน Java 7 ส่วนที่เหลือเป็นเข้ากันได้กับภาษา Java 6. Java ตัวเองไม่ได้ใช้invokedynamic คุณสมบัติใหม่อื่น ๆ เช่นคำสั่งswitchโดยใช้String s หรือ multi- catchเป็นเพียงน้ำตาล syntatic และไม่ต้องการการเปลี่ยนรหัสไบต์ ตัวอย่างเช่น multi- catchเพียงคัดลอกcatch -block สำหรับแต่ละข้อยกเว้นที่เป็นไปได้

ปัญหาเดียวที่ควรเกิดขึ้นคือคลาสใหม่ที่นำเสนอใน Java 7 หายไปใน Android เช่นAutoCloseableดังนั้นฉันไม่แน่ใจว่าคุณสามารถใช้คุณสมบัติลองด้วยทรัพยากรได้หรือไม่

ความคิดเห็นใด ๆ ฉันพลาดอะไรไปรึเปล่า?


2
ตอนนี้ปัญหาก็คือเราจะกำหนดค่าอย่างไรให้ซอร์สโค้ด Java 7 รวบรวมไปยังไฟล์คลาส Java 6 โดยเฉพาะใน eclipse
Randy Sugianto 'Yuku'

คำถามเดียวที่เหลืออยู่คือทำไมคุณถึงต้องกังวล
Warpzit

@ Warpzit คำถามที่ใหญ่กว่าควรเป็นเพราะเหตุใดนักพัฒนาจะไม่รำคาญกับความสับสนทั้งหมดนี้หรือไม่?
Amit

@Amit เพราะเขารู้ตัวดีว่า Android นั้นแตกต่างจาก Java และเพื่อที่จะทำงานกับ Android เขาต้องใช้เครื่องมือที่มีให้
Warpzit

2
@Warpzit คำถามเดียวของเขาคือ " Can Android เข้าใจ Java 7? " ไม่รู้ไม่เคยมีวิธีการแก้ปัญหา / คำตอบ ...
Amit

12

ในฐานะของ Android SDK v15 พร้อมกับ Eclipse 3.7.1, Java 7 ไม่ได้รับการสนับสนุนสำหรับการพัฒนา Android การตั้งค่าความเข้ากันได้ของแหล่งข้อมูลให้กับ 1.7 คำสั่งตั้งค่าความเข้ากันได้ของไฟล์. class เป็น 1.7 ซึ่งนำไปสู่ข้อผิดพลาดต่อไปนี้โดยคอมไพเลอร์ Android:

Android ต้องการคอมไพเลอร์ตามระดับ 5.0 หรือ 6.0 พบ '1.7' แทน โปรดใช้เครื่องมือ Android> แก้ไขคุณสมบัติของโครงการ


5

หากต้องการขยายคำตอบข้างต้นโดย @KennyTM หากคุณกำหนดเป้าหมายเป็น 4.0.3 ขึ้นไป ( minSdkVersion = 15 ) คุณสามารถใช้ API ที่ซ่อนอยู่ได้โดยเพิ่มคลาสไม่กี่คลาสลงใน android.jar SDK เป้าหมายของคุณ

เมื่อคุณทำสิ่งนี้แล้วคุณสามารถใช้การลองกับทรัพยากรใน Closeable ใด ๆ รวมทั้งใช้ AutoCloseable ในคลาสของคุณเอง

ฉันได้สร้างรหัสไปรษณีย์ที่มีซอร์สและไบนารีของคลาสทั้งหมดที่จำเป็นต้องแก้ไขใน android.jar เพื่อให้ API เหล่านี้พร้อมใช้งาน คุณเพียงแค่ต้องแกะมันออกและเพิ่มไบนารีไปยัง
android-sdk / platforms / android-NN / android.jar

คุณสามารถดาวน์โหลดได้จากที่นี่: http://db.tt/kLxAYWbr

ยังมีโน้ตคือว่าในคู่ที่ผ่านมาของเดือน, เอลเลียตฮิวจ์สได้ทำกระทำไม่กี่ต้นไม้ Android: เสร็จปิด AutoCloseable , เพิ่ม SafeVarargs , APIs ต่างๆ unhidden , คงคอนสตรัคได้รับการคุ้มครอง Throwable ของและเพิ่มการสนับสนุนสำหรับไฟล์ระดับรุ่น 51 DX . ดังนั้นในที่สุดก็มีความคืบหน้าบางอย่างเกิดขึ้น

แก้ไข (เมษายน 2014):

ด้วยการเปิดตัว SDK 19 ไม่จำเป็นต้องแก้ไข android.jar อีกต่อไปกับ API เพิ่มเติม

วิธีที่ดีที่สุดในการใช้ทรัพยากรทดลองใน Android Studio สำหรับแอปที่มีเป้าหมายที่ 4.0.3 ขึ้นไป ( minSdkVersion = 15 ) คือการเพิ่มสิ่งต่อไปนี้compileOptionsในของคุณbuild.gradle:

android {
    compileSdkVersion 19
    buildToolsVersion '19.0.3'

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 19
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_7
        targetCompatibility JavaVersion.VERSION_1_7
    }
}

Android Studio จะบ่นว่าไม่สามารถใช้การลองกับทรัพยากรในระดับ API นี้ได้ แต่ประสบการณ์ของฉันคือสิ่งที่ทำได้ โครงการจะสร้างและรันโดยไม่มีปัญหาบนอุปกรณ์ที่มี 4.0.3 ขึ้นไป ฉันไม่มีปัญหากับเรื่องนี้กับแอพที่ติดตั้งลงในอุปกรณ์ 500k +

ข้อผิดพลาดของ Android Studio

หากต้องการเพิกเฉยต่อคำเตือนนี้ให้เพิ่มสิ่งต่อไปนี้ในlint.xml:

<issue id="NewApi">
    <ignore regexp="Try-with-resources requires API level 19"/>
</issue>

1
ฉันพบว่ามันน่าสนใจที่การเตือนรหัส Android Studio บอกว่าการลองกับทรัพยากรนั้นใหม่ใน API 13 และฉันควรใช้งาน แม้ว่าจะไม่มีเวลาที่จะทดสอบว่ามันทำงานถูกต้องหรือไม่
Daniel Ryan

1

ดูเหมือนว่าการทำเช่นนี้เพื่อทำงานกับมดที่บริสุทธิ์นั้นเป็นเรื่องเล็กน้อย

แต่มันใช้งานได้สำหรับฉัน: http://www.informit.com/articles/article.aspx?p=1966024


1
ฉันค้นหาสิ่งนี้มาเป็นเวลานาน หากต้องการลดปัญหาของผู้คนในการกรองบทความคุณจะต้องเปลี่ยนบรรทัด `<property name =" java.source "value =" 1.5 "/>` บรรทัดใน build.xml ที่ให้บริการโดย android (ไม่ใช่ใน โครงการของคุณ!) สำหรับฉันมันอยู่ใน /opt/android-sdk-update-manager/tools/ant/build.xml
Mateusz Kowalczyk

ไม่คุณทำไม่ได้ คุณสามารถเขียนทับคุณสมบัติเหล่านั้นด้วยcustom_rules.xmlดูคำตอบของฉันที่นี่: stackoverflow.com/a/24608415/194894
Flow

1

เพื่อที่จะใช้คุณสมบัติ Java 7 ในการสร้างรหัสโดยระบบการสร้างบนพื้นฐานของ Android เพียงวางสิ่งต่อไปนี้ในcustom_rules.xmlไดเรกทอรีรากของโครงการของคุณ:

custom_rules.xml:

<project name="custom_android_rules">
    <property name="java.target" value="1.7" />
    <property name="java.source" value="1.7" />
</project>

0

บางคนอาจสนใจโครงการ git นี้ที่ฉันพบซึ่งดูเหมือนว่าอนุญาตให้เรียกใช้ Java 7 บน Android https://github.com/yareally/Java7-on-Android

อย่างไรก็ตามมีความเสี่ยงมากเกินไปหากฉันเพิ่มสิ่งนี้ลงในโครงการปัจจุบันที่ฉันทำงานอยู่ ดังนั้นฉันจะรอจนกว่า Google จะสนับสนุน Java 7 อย่างเป็นทางการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.