Reworked the text file preview system to avoid UI freezes with large text files

This commit is contained in:
Jorge Antonio Diaz-Benito Soriano 2014-10-18 23:46:01 +02:00
parent 7cc88a22d1
commit ec9f1c7eb8
3 changed files with 135 additions and 40 deletions

View file

@ -5,25 +5,19 @@
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"> android:layout_marginEnd="8dp">
<ScrollView <ListView
android:id="@+id/text_scrollview" android:id="@+id/text_preview_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:scrollbars="vertical" android:visibility="gone"
android:fillViewport="true" android:divider="@null"
android:visibility="gone"> android:dividerHeight="0dp"
android:focusable="false"
<TextView android:focusableInTouchMode="false" />
android:id="@+id/text_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</ScrollView>
<ProgressBar <ProgressBar
android:id="@+id/progress_bar" android:id="@+id/progress_bar"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center" />
android:visibility="gone" />
</FrameLayout> </FrameLayout>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?><!--
ownCloud Android client application
Copyright (C) 2012-2013 ownCloud Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2,
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:layout_gravity="center" />

View file

@ -1,13 +1,15 @@
package com.owncloud.android.ui.preview; package com.owncloud.android.ui.preview;
import android.accounts.Account; import android.accounts.Account;
import android.content.Context;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.Menu;
@ -26,6 +28,8 @@ import java.io.BufferedWriter;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner; import java.util.Scanner;
public class PreviewTextFragment extends FileFragment { public class PreviewTextFragment extends FileFragment {
@ -34,9 +38,8 @@ public class PreviewTextFragment extends FileFragment {
private static final String TAG = PreviewTextFragment.class.getSimpleName(); private static final String TAG = PreviewTextFragment.class.getSimpleName();
private Account mAccount; private Account mAccount;
private TextView mTextPreview; private ListView mTextPreviewList;
private ProgressBar mProgressBar; private ProgressBar mProgressBar;
private ScrollView mScrollView;
/** /**
* Creates an empty fragment for previews. * Creates an empty fragment for previews.
@ -64,8 +67,8 @@ public class PreviewTextFragment extends FileFragment {
View ret = inflater.inflate(R.layout.text_file_preview, container, false); View ret = inflater.inflate(R.layout.text_file_preview, container, false);
mScrollView = (ScrollView) ret.findViewById(R.id.text_scrollview); mTextPreviewList = (ListView) ret.findViewById(R.id.text_preview_list);
mTextPreview = (TextView) ret.findViewById(R.id.text_preview); mTextPreviewList.setAdapter(new TextLineAdapter());
mProgressBar = (ProgressBar) ret.findViewById(R.id.progress_bar); mProgressBar = (ProgressBar) ret.findViewById(R.id.progress_bar);
return ret; return ret;
@ -118,44 +121,41 @@ public class PreviewTextFragment extends FileFragment {
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
Log_OC.e(TAG, "onStart"); Log_OC.e(TAG, "onStart");
loadAndShowTextPreview(getFile().getStoragePath(), mTextPreview);
} }
private void loadAndShowTextPreview(String location, TextView textView) { private void loadAndShowTextPreview() {
new TextLoadAsyncTask().execute(location, textView); new TextLoadAsyncTask().execute(getFile().getStoragePath());
} }
/** /**
* Reads the file to preview and shows its contents. Too critical to be anonymous. * Reads the file to preview and shows its contents. Too critical to be anonymous.
*/ */
private class TextLoadAsyncTask extends AsyncTask<Object, Void, StringWriter> { private class TextLoadAsyncTask extends AsyncTask<Object, StringWriter, Void> {
TextView mTextView;
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE); ((TextLineAdapter) mTextPreviewList.getAdapter()).clear();
} }
@Override @Override
protected StringWriter doInBackground(java.lang.Object... params) { protected Void doInBackground(java.lang.Object... params) {
if (params.length != 2) if (params.length != 1)
throw new IllegalArgumentException("The parameters to " + TextLoadAsyncTask.class.getName() + " must be (1) the file location and (2) the text view to update"); throw new IllegalArgumentException("The parameter to " + TextLoadAsyncTask.class.getName() + " must be the file location only");
final String location = (String) params[0]; final String location = (String) params[0];
mTextView = (TextView) params[1];
FileInputStream inputStream = null; FileInputStream inputStream = null;
Scanner sc = null; Scanner sc = null;
StringWriter source = new StringWriter();
BufferedWriter bufferedWriter = new BufferedWriter(source);
try { try {
inputStream = new FileInputStream(location); inputStream = new FileInputStream(location);
sc = new Scanner(inputStream); sc = new Scanner(inputStream);
while (sc.hasNextLine()) { while (sc.hasNextLine()) {
bufferedWriter.append(sc.nextLine()); StringWriter target = new StringWriter();
if (sc.hasNextLine()) bufferedWriter.append("\n"); BufferedWriter bufferedWriter = new BufferedWriter(target);
if (sc.hasNextLine())
bufferedWriter.write(sc.nextLine());
bufferedWriter.close();
publishProgress(target);
} }
bufferedWriter.close();
IOException exc = sc.ioException(); IOException exc = sc.ioException();
if (exc != null) throw exc; if (exc != null) throw exc;
} catch (IOException e) { } catch (IOException e) {
@ -172,15 +172,90 @@ public class PreviewTextFragment extends FileFragment {
sc.close(); sc.close();
} }
} }
return source; return null;
} }
@Override @Override
protected void onPostExecute(final StringWriter stringWriter) { protected void onProgressUpdate(StringWriter... values) {
super.onPostExecute(stringWriter); super.onProgressUpdate(values);
//Using a ListView allows to show large text without the UI freeze that happens
//when calling TextView#setText() with a large CharSequence
((TextLineAdapter) mTextPreviewList.getAdapter()).add(values[0].toString());
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
mProgressBar.setVisibility(View.GONE); mProgressBar.setVisibility(View.GONE);
mScrollView.setVisibility(View.VISIBLE); mTextPreviewList.setVisibility(View.VISIBLE);
mTextView.setText(new String(stringWriter.getBuffer())); }
}
private class TextLineAdapter extends BaseAdapter {
private static final int LIST_ITEM_LAYOUT = R.layout.text_file_preview_list_item;
private final List<String> items = new ArrayList<>();
private void add(String line) {
items.add(line);
notifyDataSetChanged();
}
private void clear() {
items.clear();
notifyDataSetChanged();
}
@Override
public int getCount() {
return items.size();
}
@Override
public String getItem(int position) {
if (position >= items.size())
throw new IllegalArgumentException();
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView =
((LayoutInflater) getActivity().getApplicationContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.inflate(
LIST_ITEM_LAYOUT, null);
viewHolder = new ViewHolder();
viewHolder.setLineView((TextView) convertView.findViewById(R.id.text_preview));
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.getLineView().setText(items.get(position));
return convertView;
}
}
private static class ViewHolder {
private TextView lineView;
private ViewHolder() {
}
public TextView getLineView() {
return lineView;
}
public void setLineView(TextView lineView) {
this.lineView = lineView;
} }
} }
@ -300,6 +375,8 @@ public class PreviewTextFragment extends FileFragment {
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
Log_OC.e(TAG, "onResume"); Log_OC.e(TAG, "onResume");
loadAndShowTextPreview();
} }
@Override @Override