3

アプリに ListView があり、getView() メソッドをオーバーライドして、行のテキストに応じて行の ImageView src を変更できるようにしました。

問題は、ListView のスクロールが遅れていることに気付きました。DDMS をチェックすると、ListView がスクロールされるたびにガベージ コレクターが呼び出されているようで、スクロールが遅くなります。

また、BufferedReader から行を読み取るときに、アプリの別の部分でガベージ コレクターが呼び出されていることに気付きました。これにより、2,000 行のファイルを開くのに約 47 秒かかります。携帯電話にインストールしたファイル エクスポーラーが開くと、約2秒で同じファイル。

私の質問は、ガベージ コレクションが 200 ミリ秒ごとに一定の原因で発生している可能性があることと、それを防ぐにはどうすればよいかということです。それは私のアプリを本当に遅くしています。私が解決しなければ、一部のユーザーを先延ばしにするのではないかと心配しています。

ありがとう、アレックス。

リストビュー getView():

class IconicAdapter extends ArrayAdapter<String> {
  IconicAdapter(){
    super(FileBrowser.this, R.layout.filebrowser_listview_row, R.id.listtext, directoryEntries);
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent){
    View row = super.getView(position, convertView, parent);
    TextView text = (TextView) row.findViewById(R.id.listtext);
    ImageView icon = (ImageView) row.findViewById(R.id.listicon);

    entryFullFileName = directoryEntries.get(position).toString();

    if(entryFullFileName.contains(".") && !entryFullFileName.matches("^\\.+$")){
      String[] parts = entryFullFileName.split("\\.");
      lastIndex = parts.length - 1;
      fileType = parts[lastIndex];
    }else{
      fileType = "";
    }

     if(fileIsDir.get(position) == true){
      icon.setImageResource(R.drawable.folderlightblue);
     }else if(fileType.equals("html")){
      icon.setImageResource(R.drawable.filehtml);
     }else if(fileType.equals("css")){
      icon.setImageResource(R.drawable.filecss);
     }else if(fileType.equals("js")){
      icon.setImageResource(R.drawable.filejs);
     }else if(fileIsDir.get(position) == false){
      icon.setImageResource(R.drawable.fileplain);
     }

   return(row);
  }
}  

ファイルを開くコード

先日、ファイルを開くのにかかった秒数をログに記録するコードを削除しましたが、47 秒かかり、明らかに時間がかかりすぎました。再び while ループが実行されている間、ガベージ コレクターへの呼び出しが絶え間なくあります。ファイルの読み取りが遅い原因を推測しています-はい、この関数は、ファイルの読み取り中にprogressDialogが表示されているスレッドで呼び出されます

private String getLocalFileContents(String fileUri){
  try{
    String contents = "";
    BufferedReader in = new BufferedReader(new FileReader(fileUri));
    String line;
    while((line = in.readLine()) != null){
      contents += line + "\n";
    }
    in.close();

    return contents;
  }catch(Exception e){
    toast.setText("Failed to open sdcard file, try again.");
  }
 return null;
}

アップデート:

ファイル読み取りの問題は解決されました。文字列の連結により、各ループの後にガベージ コレクターが呼び出され、ファイルの読み取りが劇的に遅くなることが判明しました。回答で示唆されているように、代わりに StringBuilder を使用しましたが、すぐに開きます-万歳!

2回目の更新:

ListView をスクロールするときに一定の GC が呼び出される原因はわかっていますが、これは ListView の属性 android:cacheColorHint="@android:color/transparent" ですが、回避策はわかりません。

4

4 に答える 4

1

一般に、不必要に多くのオブジェクトを作成しているため、ガベージ コレクションが発生しています。あなたのコードを手伝う方が簡単ですが、とにかく試してみます。

リストの場合、 を呼び出すたびにビューを再作成している可能性がありますgetView。代わりに、適切な場合に再利用する必要がありconvertViewます。メソッドを構築する方法については、この他の SO の質問に対する私の回答を参照してくださいgetView

あなたのファイル読み取りの問題は推測するのが少し難しいですが、47 秒は 2,000 行の途方もなく長いようです。そのループでオブジェクトも作成していますか?

アップデート:

どうやらあなたの問題は実際にはViewオブジェクト自体にあるわけではありませんが、View. RegEx の一致、文字列の分割 (および関連する文字列オブジェクトの作成) など、毎回かなりの作業を行っています。それぞれの作業をやり直す必要がないように、少なくともこの結果をキャッシュする必要があります。アイテムが表示されるたびに。

于 2011-08-23T19:36:21.057 に答える
1

最適化の 1 つは、ファイルタイプを取得するために文字列全体の分割を停止することです。次のようなものを使用できます

String fileType = "";
int lastDot = entryFullFileName.lastIndexOf(".");
if(lastDot!=-1) {
    fileType = entryFullFileName.substring()
}

ただし、47 秒もかからないはずです。

于 2011-08-23T19:50:12.007 に答える
0

はい、android:cacheColorHint="@android:color/transparent" は一部の OS バージョンでガベージ コレクターの過剰な呼び出しを引き起こしています (最新のものでこれが修正されているかどうかはわかりません)。

まあ、使わないようにしてください。たとえば、デザイナーと話をして、遅延の原因について説明し、透明な背景を使用しないことに同意しました。

于 2013-01-11T09:17:50.297 に答える
0

EfficientAdapter を見てください ここにリンクがあります

そして、他のスレッドで効率的なアダプターと getView メソッドについて詳しく説明しました。ここにリンクがあります

この助けを願っています!!!

于 2011-08-23T19:50:08.793 に答える