002. Encyclopédie des anecdotes / QiuShiBaiKe [android]

002 Anecdote Encyclopedia Qiushibaike



La deuxième application est Encyclopédie des embarras

Code source: https://github.com/iOSDevLog/1day1app



910914-9eb38c77caad887e.jpeg002.QiuShiBaiKe

Analysez la demande.

  1. De http://qiushibaike.com Prenez json Les données
  2. json Conversion de données en kotlin classe de données
  3. Afficher les données

Développement

  • Créer Studio Android projet



  • AndroidManifest.xml Ajouter des autorisations de fenêtre supérieure



implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.34' implementation 'io.reactivex.rxjava2:rxjava:2.1.0' implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' implementation 'com.squareup.retrofit2:converter-gson:2.3.0' implementation 'com.squareup.picasso:picasso:2.5.2' implementation 'com.android.support:recyclerview-v7:27.0.2' implementation 'com.android.support:cardview-v7:27.0.2'
  • build.gradle (Module: application) Ajouter une bibliothèque dépendante
interface IQBRequest { @GET('article/list/text') fun fetchQBEntity(@Query('page') page: Int): Observable }
  • Créer QBEntity

Utiliser des plugins JsonToKotlinClass

  • Créer IQBRequest
class QBRequestUnitTest { private val BASE_URL = 'http://m2.qiushibaike.com/' @Test fun request_isSuccess() { val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build() val qbRequest = retrofit.create(IQBRequest::class.java) val page = 1 qbRequest.fetchQBEntity(page) .subscribe({ result -> println(result) assert(result.items.count() > 0) assert(result.count > 0) }, { error -> println('onError') error.printStackTrace() assert(false) }, { println('onComplete') assert(true) }, { println('start') }) } }
  • Test IQBRequest
class PullToRefreshAdapter : BaseQuickAdapter(R.layout.qb_cell, ArrayList()) { override fun convert(helper: BaseViewHolder, item: Item) { helper.setImageResource(R.id.head_imageview, R.drawable.iosdevlog) helper.setText(R.id.content_textview, item.content) } }
  • Créer une cellule d'affichage
RecyclerView
  • créer Actualiser l'adaptateur
// LifeCycle override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) Thread.setDefaultUncaughtExceptionHandler(this) mRecyclerView = findViewById(R.id.recycleview) mSwipeRefreshLayout = findViewById(R.id.swipeLayout) mSwipeRefreshLayout.setOnRefreshListener(this) mSwipeRefreshLayout.setColorSchemeColors(Color.YELLOW) mRecyclerView.layoutManager = LinearLayoutManager(this) initAdapter() } // Helper private fun initAdapter() { pullToRefreshAdapter = PullToRefreshAdapter() pullToRefreshAdapter.setOnLoadMoreListener(this, mRecyclerView) pullToRefreshAdapter.openLoadAnimation(BaseQuickAdapter.SLIDEIN_BOTTOM) mRecyclerView.adapter = pullToRefreshAdapter mRecyclerView.addOnItemTouchListener(object : OnItemClickListener() { override fun onSimpleItemClick(adapter: BaseQuickAdapter, view: View, position: Int) { Toast.makeText(root@xxxxx, Integer.toString(position), Toast.LENGTH_LONG).show() } }) }
  • Dans activity_main Ajouter à BaseQuickAdapter.RequestLoadMoreListener
// Refresh override fun onLoadMoreRequested() { mSwipeRefreshLayout.isEnabled = false fetch(currentPage).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ result -> Log.d(TAG, result.toString()) pullToRefreshAdapter.addData(result.items) }, { error -> error.printStackTrace() mSwipeRefreshLayout.isEnabled = true mSwipeRefreshLayout.isRefreshing = false Toast.makeText(root@xxxxx, R.string.network_error, Toast.LENGTH_LONG).show() pullToRefreshAdapter.setEnableLoadMore(true) pullToRefreshAdapter.loadMoreFail() }, { Log.d(TAG, 'onComplete') currentPage += 1 mSwipeRefreshLayout.isEnabled = true mSwipeRefreshLayout.isRefreshing = false pullToRefreshAdapter.setEnableLoadMore(true) pullToRefreshAdapter.loadMoreComplete() }, { Log.d(TAG, 'onStart') }) } override fun onRefresh() { pullToRefreshAdapter.setEnableLoadMore(false) currentPage = 1 fetch(currentPage).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ result -> Log.d(TAG, result.toString()) pullToRefreshAdapter.setNewData(result.items) }, { error -> Log.d(TAG, 'onError') error.printStackTrace() mSwipeRefreshLayout.isRefreshing = false pullToRefreshAdapter.setEnableLoadMore(true) }, { Log.d(TAG, 'onComplete') mSwipeRefreshLayout.isRefreshing = false pullToRefreshAdapter.setEnableLoadMore(true) currentPage += 1 }, { Log.d(TAG, 'onStart') }) } private fun fetch(page: Int): Observable { val retrofit = Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build() val qbRequest = retrofit.create(IQBRequest::class.java) return qbRequest.fetchQBEntity(page) }
  • Activité principale initialisation
Thread.UncaughtExceptionHandler
  • Activité principale atteindre override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) Thread.setDefaultUncaughtExceptionHandler(this) ... } // UncaughtExceptionHandler override fun uncaughtException(t: Thread?, e: Throwable?) = e!!.printStackTrace() , 1SwipeRefreshLayout.OnRefreshListener`
override fun onResume() { super.onResume() Handler().postDelayed({ mSwipeRefreshLayout.isRefreshing = true onRefresh() }, 10) }
  • (optionnel) Activité principale Réalisez override fun convert(helper: BaseViewHolder, item: Item) { if (item.user != null) { val imageView = helper.getView(R.id.head_imageview) Picasso.with(mContext) .load('http:' + item.user.medium) .resize(40, 40) .centerCrop() .transform(CircleTransform()) .into(imageView) helper.setText(R.id.username_textview, item.user.login) helper.setText(R.id.username_detail, item.user.age.toString() + ' ' + item.user.astrology + ' Like: ' + item.votes.up + ' Step: ' + item.votes.down ) val gender = when (item.user.gender) { 'F' -> R.drawable.female 'M' -> R.drawable.male else -> R.drawable.male } helper.setImageResource(R.id.gender_imageview, gender) } val published_at = java.lang.Long.valueOf(item.published_at) val simpleDateFormat = SimpleDateFormat('yyyy-MM-dd HH:mm:ss') val published_string = simpleDateFormat.format( Date(published_at * 1000L)) helper.setText(R.id.datetime_textview, published_string) helper.setText(R.id.content_textview, item.content) } inner class CircleTransform : Transformation { override fun transform(source: Bitmap): Bitmap { val size = Math.min(source.width, source.height) val x = (source.width - size) / 2 val y = (source.height - size) / 2 val squaredBitmap = Bitmap.createBitmap(source, x, y, size, size) if (squaredBitmap != source) { source.recycle() } val config = if (source.config != null) source.config else Bitmap.Config.ARGB_8888 val bitmap = Bitmap.createBitmap(size, size, config) val canvas = Canvas(bitmap) val paint = Paint() val shader = BitmapShader(squaredBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) paint.setShader(shader) paint.setAntiAlias(true) val r = size / 2f canvas.drawCircle(r, r, r, paint) squaredBitmap.recycle() return bitmap } override fun key(): String { return 'circle' } }
  • L'interface peut afficher les dernières données en temps réel.
|_+_|
  • Charger les informations utilisateur

référence: https://gist.github.com/julianshen/5829333

|_+_|