I have written an app which downloads a large txt file using Java URL and BufferedInputStream
. The file downloads quite fast in around 4 seconds for a 20 - 30Mb file. The file is actually logs. While reading the file in line by line the data is stored in an ArrayList
of String
.
I then traverse through the ArrayList
and build a TableLayout
with rows and textviews for each line. However this process takes forever (more than 8 minutes) to finally complete and update the UI.
Is there a quicker way I can download this text and display it. I have opened the file with the native browser and its very quick but I don't want to use the native browser in my app.
Thanks
You should use a RecyclerView
for this. It will only inflate the TextView
s that are currently needed, and recycles them, which drastically improves performance.
Add a RecycleView
to your layout:
<android.support.v7.widget.RecyclerView
android:id="@+id/loggingRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Then, you need to define in a layout file how each single item of the RecyclerView
should look like, similar to this text_row_item.xml
file:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/list_item_height"
android:layout_marginLeft="@dimen/margin_medium"
android:layout_marginRight="@dimen/margin_medium"
android:gravity="center_vertical">
<TextView
android:id="@+id/logLine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/element_text"/>
</FrameLayout>
Next, define an adapter class which maps the input data to the individual RecyclerView
items:
class CustomAdapter(private val logLines: Array<String>) :
RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
/**
* Provide a reference to the type of views that you are using
* (custom ViewHolder)
*/
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView
init {
// Define click listener for the ViewHolder's View
textView = view.findViewById(R.id.logLine)
}
}
// Create new views (invoked by the layout manager)
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
// Create a new view, which defines the UI of the list item
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.text_row_item, viewGroup, false)
return ViewHolder(view)
}
// Replace the contents of a view (invoked by the layout manager)
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
// Get element from your dataset at this position and replace the
// contents of the view with that element
viewHolder.textView.text = logLines[position]
}
// Return the size of your dataset (invoked by the layout manager)
override fun getItemCount() = logLines.size
}
Finally, assign the adapter to the RecyclerView
in your layout like this:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val logData = arrayOf("Log Statement 1", "Log Statement 2", "Log Statement 3")
val customAdapter = CustomAdapter(logData )
val recyclerView: RecyclerView = findViewById(R.id.loggingRecyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = customAdapter
}
}