异步任务阻止UI线程

时间:2017-02-18 00:21:08

标签: android multithreading sqlite android-asynctask

更新

感谢@EmanuelSeibold,我能够确定更新Recyclerview的问题。 AsyncTask在后台工作正常,只有recyclerview的适配器更新冻结了UI。

UPDATE2

我发现这确实是我的布局设置。我忘了删除RecyclerView周围的nestedScrollView。这似乎导致渲染冲突。

我在这里挖掘了答案和博客文章,但似乎无法找到解决方案。

我对Android开发很新,并试图了解多线程。

场景:我有一个应用程序,它包含一个带有课程数据的SQLite数据库,并实现了一个查询该数据库的搜索功能。这会阻止UI线程约3秒钟。 因此,我实现了AsyncTask以保持UI响应,但在搜索过程中我的UI仍然被阻止。

提前致谢!

这里是代码:

搜索活动

public class Activity_Search extends Activity_Base {

  private RecyclerView rv;


  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_search);
      setActionBarTitle(R.string.title_search);

      findViewById(R.id.searchCourseTitle).setOnKeyListener(new View.OnKeyListener() {
          @Override
          public boolean onKey(View v, int keyCode, KeyEvent event) {
              switch(keyCode) {
                  case KeyEvent.KEYCODE_ENTER:
                      startSearch();
                      break;
                  default:
                      return false;
              }
              return true;
          }
      });


      rv = (RecyclerView) findViewById(R.id.searchRecycler);

      Adapter_Search adapter = new Adapter_Search(this, null);
      rv.setAdapter(adapter);
      rv.setLayoutManager(new LinearLayoutManager(this));

      FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.search_FAB);
      fab.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {
              startSearch();
          }
      });
  }

  private void startSearch() {
      findViewById(R.id.searchCourseTitle).clearFocus();
      if (this.getCurrentFocus() != null) {
          InputMethodManager imm =
                  (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
          imm.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0);
      }

      {getting input}

      String[] columns = {...};


      String selection = {formatting input};

      Async_Search search = new Async_Search(this);
      search.execute(columns, new String[]{selection});
  }

  public void onSearchCompleted(Cursor results) {
      ((Adapter_Search) rv.getAdapter()).changeCursor(results);
  }
}

的AsyncTask

public class Async_Search extends AsyncTask<String[], Void, Cursor> {

  private Activity activity;

  public Async_Search (Activity activity) {
      this.activity = activity;
  }

  @Override
  protected Cursor doInBackground(String[]... params) {
      SQLiteDatabase db = SQL_Database.getInstance(activity).getWritableDatabase();

      String[] columns = params[0];
      String selection = params[1][0];

      return db.query(...)
  }

  @Override
  protected void onPostExecute(Cursor results) {
      ((Activity_Search) activity).onSearchCompleted(results);
  }
}

Recycler adapter

public class Adapter_Search extends RecyclerCursorAdapter<Adapter_Search.ViewHolder>{

public static class ViewHolder extends RecyclerView.ViewHolder {
    public TextView name, ects, studipCode, termYear, lecturers, fields;

    public ViewHolder (View view) {
        super(view);
        {id lookups} 
    }
}

public Adapter_Search(Context context, Cursor cursor) {
    super(context, cursor);
}

@Override
public ViewHolder onCreateViewHolder (ViewGroup parent, int ViewType) {
    View view = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.search_list_entry, parent, false);
    ViewHolder viewHolder = new ViewHolder(view);
    return viewHolder;
}

@Override
public void onBindViewHolder (ViewHolder viewHolder, Cursor cursor) {

    TextView name, ects, studipCode, termYear, lecturers, fields;
    name = viewHolder.name;
    ects = viewHolder.ects;
    studipCode = viewHolder.studipCode;
    termYear = viewHolder.termYear;
    lecturers = viewHolder.lecturers;
    fields = viewHolder.fields;

    String termandyear = cursor.getString(cursor.getColumnIndexOrThrow(SQL_Database.COURSE_COLUMN_TERM)) +
            String.format("%.2s",cursor.getString(cursor.getColumnIndexOrThrow(SQL_Database.COURSE_COLUMN_YEAR)));

    name.setText(cursor.getString(cursor.getColumnIndexOrThrow(SQL_Database.COURSE_COLUMN_COURSE)));
    String credits = cursor.getString(cursor.getColumnIndexOrThrow(SQL_Database.COURSE_COLUMN_ECTS)) + " ECTS";
    ects.setText(credits);
    {and so on} 
}

}

基础适配器类

public abstract class RecyclerCursorAdapter <ViewHolder extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<ViewHolder> {

private Context mContext;

private Cursor mCursor;

private boolean mDataValid;

private int mRowIdColumn;

private DataSetObserver mDataSetObserver;

public RecyclerCursorAdapter(Context context, Cursor cursor) {
    mContext = context;
    mCursor = cursor;
    mDataValid = cursor != null;
    mRowIdColumn = mDataValid ? mCursor.getColumnIndex("_id") : -1;
    mDataSetObserver = new NotifyingDataSetObserver();
    if (mCursor != null) {
        mCursor.registerDataSetObserver(mDataSetObserver);
    }
}

public Cursor getCursor() {
    return mCursor;
}

@Override
public int getItemCount() {
    if (mDataValid && mCursor != null) {
        return mCursor.getCount();
    }
    return 0;
}

@Override
public long getItemId(int position) {
    if (mDataValid && mCursor != null && mCursor.moveToPosition(position)) {
        return mCursor.getLong(mRowIdColumn);
    }
    return 0;
}

@Override
public void setHasStableIds(boolean hasStableIds) {
    super.setHasStableIds(true);
}

public abstract void onBindViewHolder(ViewHolder viewHolder, Cursor cursor);

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
    if (!mDataValid) {
        throw new IllegalStateException("this should only be called when the cursor is valid");
    }
    if (!mCursor.moveToPosition(position)) {
        throw new IllegalStateException("couldn't move cursor to position " + position);
    }
    onBindViewHolder(viewHolder, mCursor);
}

/**
 * Change the underlying cursor to a new cursor. If there is an existing cursor it will be
 * closed.
 */
public void changeCursor(Cursor cursor) {
    Cursor old = swapCursor(cursor);
    if (old != null) {
        old.close();
    }
}

/**
 * Swap in a new Cursor, returning the old Cursor.  Unlike
 * {@link #changeCursor(Cursor)}, the returned old Cursor is <em>not</em>
 * closed.
 */
public Cursor swapCursor(Cursor newCursor) {
    if (newCursor == mCursor) {
        return null;
    }
    final Cursor oldCursor = mCursor;
    if (oldCursor != null && mDataSetObserver != null) {
        oldCursor.unregisterDataSetObserver(mDataSetObserver);
    }
    mCursor = newCursor;
    if (mCursor != null) {
        if (mDataSetObserver != null) {
            mCursor.registerDataSetObserver(mDataSetObserver);
        }
        mRowIdColumn = newCursor.getColumnIndexOrThrow("_id");
        mDataValid = true;
        notifyDataSetChanged();
    } else {
        mRowIdColumn = -1;
        mDataValid = false;
        notifyDataSetChanged();
        //There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
    }
    return oldCursor;
}

private class NotifyingDataSetObserver extends DataSetObserver {
    @Override
    public void onChanged() {
        super.onChanged();
        mDataValid = true;
        notifyDataSetChanged();
    }

    @Override
    public void onInvalidated() {
        super.onInvalidated();
        mDataValid = false;
        notifyDataSetChanged();
        //There is no notifyDataSetInvalidated() method in RecyclerView.Adapter
    }
}

}

1 个答案:

答案 0 :(得分:0)

也许尝试从异步搜索中删除这些行。

gpa

而是这样打电话:

first_name, last_name = input("Please input your First Name and Last Name: ").split()
gpa = float(input("Please enter your GPA: "))


honor_message = ""

if gpa <=0:
    print("GPA can not be negative or 0")
else:         
    if 3.75 <= gpa <= 4.0:
        honor_message="\033[1;31;0m Excellent \x1b[0m"
    elif 3.5 <= gpa <= 3.74:
        honor_message = "\033[1;31;0m Good \x1b[0m"
    elif 3.25 <= gpa <= 3.49:
        honor_message = "\033[1;31;0m    Satisfactory \x1b[0m"
    else:
        honor_message

    print("Some text some text".center(60))
    print("Some text some text Some text some text".center(60))
    print("Some text some text".center(60))
    print(first_name.center(60).rstrip(), last_name)
    print("Some text some text".center(60))
    print("Some text some text".center(60))
    print(honor_message.center(60))
    print("Some text some text".center(60))

我不知道这是否有效,但我的Asynctask并没有使用你的活动。