リファクタ

This commit is contained in:
tateisu 2018-01-29 22:27:43 +09:00
parent 1b238d7db2
commit 03bb0c40ea
10 changed files with 265 additions and 224 deletions

6
.idea/kotlinc.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinCommonCompilerArguments">
<option name="coroutinesState" value="enable" />
</component>
</project>

View File

@ -26,6 +26,12 @@ android {
}
kotlin {
experimental {
coroutines 'enable'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
@ -37,4 +43,7 @@ dependencies {
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
}

View File

@ -13,7 +13,7 @@
android:theme="@style/AppTheme"
>
<activity android:name=".ActMain">
<activity android:name=".ActList">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@ -21,7 +21,7 @@
</intent-filter>
</activity>
<activity android:name=".ActApngView"/>
<activity android:name=".ActViewer"/>
</application>

View File

@ -1,75 +0,0 @@
package jp.juggler.apng.sample
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.View
import android.widget.TextView
import jp.juggler.apng.ApngFrames
import kotlin.concurrent.thread
class ActApngView : AppCompatActivity() {
companion object {
const val EXTRA_RES_ID = "res_id"
const val EXTRA_CAPTION = "caption"
fun open(context: Context, resId:Int, caption:String){
val intent =Intent( context, ActApngView::class.java)
intent.putExtra(EXTRA_RES_ID,resId)
intent.putExtra(EXTRA_CAPTION,caption)
context.startActivity(intent)
}
}
private lateinit var handler : Handler
private lateinit var apngView : ApngView
private lateinit var tvError : TextView
override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState)
this.handler = Handler()
val intent = this.intent
val resId = intent.getIntExtra(EXTRA_RES_ID,0)
this.title = intent.getStringExtra(EXTRA_CAPTION) ?: "?"
setContentView(R.layout.act_apng_view)
this.apngView = findViewById(R.id.apngView)
this.tvError = findViewById(R.id.tvError)
thread(start=true){
try {
this@ActApngView.resources.openRawResource(resId).use {
val apngFrames = ApngFrames.parseApng(it, 1024)
handler.post {
if(isDestroyed) return@post
apngView.visibility = View.VISIBLE
tvError.visibility = View.GONE
apngView.apngFrames = apngFrames
}
}
}catch(ex:Throwable){
ex.printStackTrace()
Log.e(ActMain.TAG,"load error: ${ex.javaClass.simpleName} ${ex.message}")
val message = "%s %s".format( ex.javaClass.simpleName, ex.message)
handler.post{
if(isDestroyed) return@post
apngView.visibility = View.GONE
tvError.visibility = View.VISIBLE
tvError.text = message
}
}
}
}
override fun onDestroy() {
super.onDestroy()
apngView.apngFrames?.dispose()
}
}

View File

@ -0,0 +1,167 @@
package jp.juggler.apng.sample
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.*
import jp.juggler.apng.ApngFrames
import kotlinx.coroutines.experimental.*
import kotlinx.coroutines.experimental.android.UI
import java.lang.ref.WeakReference
class ActList : AppCompatActivity() {
companion object {
const val TAG = "ActList"
}
class WeakRef<T : Any>(t : T) : WeakReference<T>(t) {
operator fun invoke() : T? = get()
}
fun <T : Any> ref(t : T) = WeakRef(t)
class ListItem(val id : Int, val caption : String)
private lateinit var listView : ListView
private lateinit var listAdapter : MyAdapter
override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.act_list)
this.listView = findViewById(R.id.listView)
listAdapter = MyAdapter()
listView.adapter = listAdapter
listView.onItemClickListener = listAdapter
launch(UI) {
val list = async(CommonPool) {
// RawリソースのIDと名前の一覧
R.raw::class.java.fields
.mapNotNull {
val id = it.get(null) as? Int
if(id == null) {
null
} else {
ListItem(
id,
resources.getResourceName(id).replaceFirst(""".+/""".toRegex(), "")
)
}
}
.toMutableList()
.let { list ->
list.sortBy { item -> item.caption }
list
}
}.await()
if(isDestroyed) return@launch
listAdapter.list.addAll(list)
listAdapter.notifyDataSetChanged()
}
}
inner class MyAdapter : BaseAdapter(), AdapterView.OnItemClickListener {
val list = ArrayList<ListItem>()
override fun getCount() : Int {
return list.size
}
override fun getItem(position : Int) : Any {
return list[position]
}
override fun getItemId(position : Int) : Long {
return list[position].id.toLong()
}
override fun getView(
position : Int,
viewArg : View?,
parent : ViewGroup?
) : View {
val view : View
val holder : MyViewHolder
if(viewArg == null) {
view = layoutInflater.inflate(R.layout.lv_item, parent, false)
holder = MyViewHolder(view, ref(this@ActList))
view.tag = holder
} else {
view = viewArg
holder = view.tag as MyViewHolder
}
holder.bind(list[position])
return view
}
override fun onItemClick(
parent : AdapterView<*>?,
view : View?,
position : Int,
id : Long
) {
val item = list[position]
ActViewer.open(this@ActList, item.id, item.caption)
}
}
class MyViewHolder(
viewRoot : View,
private val activity : WeakRef<ActList>
) {
private val tvCaption : TextView = viewRoot.findViewById(R.id.tvCaption)
private val apngView : ApngView = viewRoot.findViewById(R.id.apngView)
private var lastId : Int = 0
private var lastJob : Job? = null
fun bind(listItem : ListItem) {
tvCaption.text = listItem.caption
val resId = listItem.id
if(lastId != resId) {
lastId = resId
apngView.apngFrames?.dispose()
apngView.apngFrames = null
Log.d(TAG, "loading start: id=$resId")
launch(UI) {
try {
if(activity()?.isDestroyed != false) return@launch
lastJob?.cancelAndJoin()
val job = async(CommonPool) {
activity()?.resources?.openRawResource(resId)?.use { inStream ->
ApngFrames.parseApng(inStream, 128)
}
}
lastJob = job
val apngFrames = job.await()
if(activity()?.isDestroyed == false
&& lastId == resId
&& apngFrames != null
) {
Log.d(TAG, "loading complete: resId=$resId")
apngView.apngFrames = apngFrames
} else {
apngFrames?.dispose()
}
} catch(ex : Throwable) {
ex.printStackTrace()
Log.e(TAG, "load error: ${ex.javaClass.simpleName} ${ex.message}")
}
}
}
}
}
}

View File

@ -1,140 +0,0 @@
package jp.juggler.apng.sample
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.*
import jp.juggler.apng.ApngFrames
import kotlin.concurrent.thread
class ActMain : AppCompatActivity() {
companion object {
const val TAG = "ActMain"
}
private lateinit var listView : ListView
private lateinit var listAdapter: MyAdapter
private lateinit var handler: Handler
override fun onCreate(savedInstanceState : Bundle?) {
handler = Handler()
super.onCreate(savedInstanceState)
setContentView(R.layout.act_main)
this.listView = findViewById(R.id.listView)
listAdapter = MyAdapter()
listView.adapter = listAdapter
listView.onItemClickListener = listAdapter
thread(start=true){
// RawリソースのIDと名前の一覧
val list = ArrayList<ListItem>()
R.raw::class.java.fields
.mapNotNull { it.get(null) as? Int}
.forEach { list.add(
ListItem(
it,
resources.getResourceName(it).replaceFirst(""".+/""".toRegex(), "")
)
)}
list.sortBy { it.caption }
handler.post{
if(isDestroyed) return@post
listAdapter.list.addAll(list)
listAdapter.notifyDataSetChanged()
}
}
}
class ListItem(val id:Int,val caption:String)
inner class MyAdapter :BaseAdapter(), AdapterView.OnItemClickListener {
val list = ArrayList<ListItem>()
override fun getCount() : Int {
return list.size
}
override fun getItem(position : Int) : Any {
return list[position]
}
override fun getItemId(position : Int) : Long {
return list[position].id.toLong()
}
override fun getView(
position : Int,
viewArg : View?,
parent : ViewGroup?
) : View {
val view:View
val holder: MyViewHolder
if( viewArg == null ){
view = layoutInflater.inflate(R.layout.lv_main,parent,false)
holder = MyViewHolder(view)
view.tag = holder
}else{
view = viewArg
holder = view.tag as MyViewHolder
}
holder.bind( list[position])
return view
}
override fun onItemClick(
parent : AdapterView<*>?,
view : View?,
position : Int,
id : Long
) {
val item = list[position]
ActApngView.open(this@ActMain, item.id, item.caption)
}
}
inner class MyViewHolder(viewRoot:View){
private val tvCaption : TextView = viewRoot.findViewById(R.id.tvCaption)
private val apngView: ApngView = viewRoot.findViewById(R.id.apngView)
private var lastId : Int = -1
fun bind(listItem : ListItem) {
tvCaption.text = listItem.caption
val resId = listItem.id
if( lastId != resId){
Log.d(TAG,"loading start: resId=$resId lastId=$lastId")
lastId =resId
apngView.apngFrames?.dispose()
apngView.apngFrames=null
thread (start=true){
try {
resources.openRawResource(resId).use { inStream->
val apngFrames = ApngFrames.parseApng(inStream, 128)
handler.post( {
if(isDestroyed) return@post
if( lastId != resId) {
Log.d(TAG,"loading cancelled: resId=$resId,lastId=$lastId")
}else{
Log.d(TAG,"loading complete: resId=$resId")
apngView.apngFrames = apngFrames
}
})
}
}catch(ex:Throwable){
ex.printStackTrace()
Log.e(TAG,"load error: ${ex.javaClass.simpleName} ${ex.message}")
}
}
}
}
}
}

View File

@ -0,0 +1,79 @@
package jp.juggler.apng.sample
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.view.View
import android.widget.TextView
import jp.juggler.apng.ApngFrames
import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.launch
class ActViewer : AppCompatActivity() {
companion object {
const val EXTRA_RES_ID = "res_id"
const val EXTRA_CAPTION = "caption"
fun open(context : Context, resId : Int, caption : String) {
val intent = Intent(context, ActViewer::class.java)
intent.putExtra(EXTRA_RES_ID, resId)
intent.putExtra(EXTRA_CAPTION, caption)
context.startActivity(intent)
}
}
private lateinit var apngView : ApngView
private lateinit var tvError : TextView
override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState)
val intent = this.intent
val resId = intent.getIntExtra(EXTRA_RES_ID, 0)
this.title = intent.getStringExtra(EXTRA_CAPTION) ?: "?"
setContentView(R.layout.act_apng_view)
this.apngView = findViewById(R.id.apngView)
this.tvError = findViewById(R.id.tvError)
launch(UI) {
try {
if(isDestroyed) return@launch
val apngFrames = async(CommonPool) {
resources.openRawResource(resId).use {
ApngFrames.parseApng(it, 1024)
}
}.await()
if(isDestroyed) {
apngFrames.dispose()
} else {
apngView.visibility = View.VISIBLE
tvError.visibility = View.GONE
apngView.apngFrames = apngFrames
}
} catch(ex : Throwable) {
ex.printStackTrace()
Log.e(ActList.TAG, "load error: ${ex.javaClass.simpleName} ${ex.message}")
val message = "%s %s".format(ex.javaClass.simpleName, ex.message)
if(! isDestroyed) {
apngView.visibility = View.GONE
tvError.visibility = View.VISIBLE
tvError.text = message
}
}
}
}
override fun onDestroy() {
super.onDestroy()
apngView.apngFrames?.dispose()
}
}

View File

@ -1,8 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.2.20'
ext.kotlin_version = '1.2.21'
ext.kotlin_coroutines_version = '0.21.2'
ext.anko_version='0.10.4'
repositories {
@ -13,11 +12,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.google.gms:google-services:3.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
}
}