Search code examples
android

Quickest way of displaying large text in android app


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


Solution

  • You should use a RecyclerView for this. It will only inflate the TextViews 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
    
        }
    }