Settings + adding mutexes whenever possible.

This commit is contained in:
Vladislav Khorev 2014-11-19 12:08:10 +00:00
parent 6f234a435c
commit 75dd42a703
20 changed files with 678 additions and 271 deletions

View File

@ -23,9 +23,31 @@
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<!--
<activity
android:name=".SearchResultActivity"
android:label="@string/app_name"
android:configChanges="orientation"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
-->
</application>
</manifest>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -2,7 +2,6 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"

View File

@ -32,7 +32,6 @@
android:background="@drawable/see_more_button"
android:gravity="right|center_vertical"
android:paddingRight="28dp"
android:text="Узнать больше"
android:textSize="16sp" />
</LinearLayout>

View File

@ -9,7 +9,7 @@
tools:context="fishrungames.bashgid.MainPageFragment" >
<TextView
android:id="@+id/textView1"
android:id="@+id/selectLanguageTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"

View File

@ -32,14 +32,12 @@
android:gravity="left|center_vertical"
android:minHeight="0dip"
android:minWidth="0dip"
android:text="yrrttedf"
android:textColor="@color/text_grey" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="rtrrtrt" />
android:layout_height="wrap_content" />
</LinearLayout>

View File

@ -1,7 +1,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" >
<item android:id="@+id/search"
<item android:id="@+id/action_search"
android:title="@string/search_title"
android:icon="@drawable/abc_ic_search_api_mtrl_alpha"
app:showAsAction="always"

View File

@ -8,6 +8,9 @@
<string name="action_settings">Настройки</string>
<string name="select_language">Выберите язык:</string>
<string name="search_title">Поиск</string>
<string name="news_record_not_available">Запись недоступна</string>

View File

@ -6,6 +6,9 @@
<string name="navigation_drawer_close">关闭导航窗口</string>
<string name="action_settings">设置</string>
<string name="select_language">选择语言:</string>
<string name="search_title">搜索标题</string>
<string name="news_record_not_available">无法查看新闻记录</string>

View File

@ -7,14 +7,17 @@
<string name="action_settings">Settings</string>
<string name="select_language">Select language:</string>
<string name="lang_english">English</string>
<string name="lang_russian">Русский</string>
<string name="lang_chinese">中文</string>
<string name="search_title">Search</string>
<string name="search_hint">Search hint</string>
<string name="news_record_not_available">Record is not available</string>
<string name="other_news">Other news…</string>

View File

@ -6,103 +6,105 @@ import java.util.Locale;
import fishrungames.bashgid.core.NewsManager.NewsRecord;
import fishrungames.bashgid.core.db.NewsDataSource;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.support.v4.app.Fragment;
import android.app.SearchManager;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.support.v4.widget.DrawerLayout;
public class MainActivity extends ActionBarActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks
{
public class MainActivity extends ActionBarActivity
implements NavigationDrawerFragment.NavigationDrawerCallbacks {
public static final String TAG_FROM_MAINFRAGMENT_TO_NEWSRECORDFRAGMENT = "TAG_FROM_MAINFRAGMENT_TO_NEWSRECORDFRAGMENT";
public static final String TAG_FROM_NEWSLISTFRAGMENT_TO_NEWSRECORDFRAGMENT = "TAG_FROM_NEWSLISTFRAGMENT_TO_NEWSRECORDFRAGMENT";
static MainActivity instance = null;
private NavigationDrawerFragment mNavigationDrawerFragment = null;
public NewsDataSource newsDataSource;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SetupDrawer();
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new WelcomeFragment()).commit();
instance = this;
newsDataSource = new NewsDataSource(this);
newsDataSource.open();
}
public static MainActivity getInstance()
{
return instance;
}
public void OnSelectEnglish(View view)
static MainActivity instance = null;
private NavigationDrawerFragment mNavigationDrawerFragment = null;
public NewsDataSource newsDataSource = null;
@Override
protected void onCreate(Bundle savedInstanceState)
{
Locale.setDefault(Locale.US);
Configuration config = new Configuration();
config.locale = Locale.US;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
getSupportActionBar().setTitle(R.string.app_name);
SetupDrawer();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SetupDrawer();
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new WelcomeFragment()).commit();
instance = this;
newsDataSource = new NewsDataSource(this);
newsDataSource.open();
}
public static MainActivity getInstance()
{
return instance;
}
public void OnSelectEnglish(View view)
{
Locale.setDefault(Locale.US);
Configuration config = new Configuration();
config.locale = Locale.US;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
getSupportActionBar().setTitle(R.string.app_name);
SetupDrawer();
OpenMainScreen();
}
public void OnSelectRussian(View view)
{
Locale locale = new Locale("ru");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
getSupportActionBar().setTitle(R.string.app_name);
SetupDrawer();
Locale locale = new Locale("ru");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
getSupportActionBar().setTitle(R.string.app_name);
SetupDrawer();
OpenMainScreen();
}
public void OnSelectChinese(View view)
{
Locale.setDefault(Locale.CHINA);
Configuration config = new Configuration();
config.locale = Locale.CHINA;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
getSupportActionBar().setTitle(R.string.app_name);
SetupDrawer();
Locale.setDefault(Locale.CHINA);
Configuration config = new Configuration();
config.locale = Locale.CHINA;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
getSupportActionBar().setTitle(R.string.app_name);
SetupDrawer();
OpenMainScreen();
}
public void OnSelectSemiDetails(Integer pos)
{
//getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, new SemiDetailsFragment()).addToBackStack(null).commit();
// getSupportFragmentManager().beginTransaction().add(R.id.fragment_container,
// new SemiDetailsFragment()).addToBackStack(null).commit();
}
public void OpenMainScreen()
{
@ -110,7 +112,7 @@ implements NavigationDrawerFragment.NavigationDrawerCallbacks {
mNavigationDrawerFragment.EnableDrawer();
}
public void OpenNewsScreen()
{
@ -119,122 +121,145 @@ implements NavigationDrawerFragment.NavigationDrawerCallbacks {
mNavigationDrawerFragment.EnableDrawer();
}
public void OpenSettingsScreen()
{
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new SettingsFragment()).commit();
mNavigationDrawerFragment.EnableDrawer();
}
public void OpenNewsRecordScreen(NewsRecord newsRecord, String tag)
{
//Xperimental -- addToBackStack provoke error "Class not found". Need to resolve somehow!
//getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new NewsRecordFragment(newsRecord)).addToBackStack(null).commit();
//I added workaround:
// Xperimental -- addToBackStack provoke error "Class not found". Need
// to resolve somehow!
// getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
// new NewsRecordFragment(newsRecord)).addToBackStack(null).commit();
// I added workaround:
NewsRecordFragment newsRecordFragment = new NewsRecordFragment(newsRecord);
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, newsRecordFragment, tag).commit();
mNavigationDrawerFragment.EnableDrawer();
}
@Override
public void onAttachFragment(Fragment fragment)
{
super.onAttachFragment(fragment);
}
public void SetupDrawer()
{
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
if (mNavigationDrawerFragment != null)
{
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
// Set up the drawer.
mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout));
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.global, menu);
/*
SearchManager searchManager =
(SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView =
(SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setSearchableInfo(
searchManager.getSearchableInfo(getComponentName()));
*/
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings)
{
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onNavigationDrawerItemSelected(int position)
{
if (position == 1)
{
OpenMainScreen();
}
else if (position == 2)
{
OpenNewsScreen();
}
else if (position == 8)
{
OpenSettingsScreen();
}
}
@Override
public void onBackPressed()
{
if (getSupportFragmentManager().findFragmentByTag(TAG_FROM_MAINFRAGMENT_TO_NEWSRECORDFRAGMENT) != null)
{
OpenMainScreen();
return;
}
if (getSupportFragmentManager().findFragmentByTag(TAG_FROM_NEWSLISTFRAGMENT_TO_NEWSRECORDFRAGMENT) != null)
{
OpenNewsScreen();
return;
}
super.onBackPressed();
/*
* AddToBackStack is falling. Here is workaround
* if(getSupportFragmentManager().getBackStackEntryCount() != 0) {
* getSupportFragmentManager().popBackStack(); } else {
* super.onBackPressed(); }
*/
}
@Override
protected void onResume()
{
newsDataSource.open();
super.onResume();
}
@Override
protected void onPause()
{
newsDataSource.close();
super.onPause();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onNavigationDrawerItemSelected(int position)
{
if (position == 1)
{
OpenMainScreen();
}
else if (position == 2)
{
OpenNewsScreen();
}
}
@Override
public void onBackPressed() {
if ( getSupportFragmentManager().findFragmentByTag(TAG_FROM_MAINFRAGMENT_TO_NEWSRECORDFRAGMENT) != null)
{
OpenMainScreen();
return;
}
if ( getSupportFragmentManager().findFragmentByTag(TAG_FROM_NEWSLISTFRAGMENT_TO_NEWSRECORDFRAGMENT) != null)
{
OpenNewsScreen();
return;
}
super.onBackPressed();
/*
* AddToBackStack is falling. Here is workaround
if(getSupportFragmentManager().getBackStackEntryCount() != 0) {
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
}*/
}
@Override
protected void onResume() {
//Xperimental -- opening and closing leads to fail
//newsDataSource.open();
super.onResume();
}
@Override
protected void onPause() {
//Xperimental -- opening and closing leads to fail
//newsDataSource.close();
super.onPause();
}
}

View File

@ -47,7 +47,7 @@ public class MainPageFragment extends Fragment implements NewsUpdatedCallbackInt
ListView listView;
View header;
NewsManager.RemoveCallbackInterface downloadNewsCanceller;
NewsManager.RemoveCallbackInterface downloadNewsCanceller = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -84,7 +84,11 @@ public class MainPageFragment extends Fragment implements NewsUpdatedCallbackInt
@Override
public void onDestroyView()
{
downloadNewsCanceller.RemoveCallback();
if (downloadNewsCanceller != null)
{
downloadNewsCanceller.RemoveCallback();
downloadNewsCanceller = null;
}
super.onDestroyView();
}

View File

@ -3,9 +3,11 @@ package fishrungames.bashgid;
import android.support.v7.app.ActionBarActivity;
import android.app.Activity;
import android.app.SearchManager;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.SearchView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.content.Context;
@ -258,10 +260,11 @@ public class NavigationDrawerFragment extends Fragment {
// showGlobalContextActionBar, which controls the top-left area of the action bar.
inflater.inflate(R.menu.global, menu);
//inflater.inflate(R.menu.global, menu);
showGlobalContextActionBar();
super.onCreateOptionsMenu(menu, inflater);
}
@Override
@ -271,6 +274,11 @@ public class NavigationDrawerFragment extends Fragment {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
if (item.getItemId() == R.id.action_search) {
return true;
}
if (item.getItemId() == R.id.action_settings) {
Toast.makeText(getActivity(), "Example action.", Toast.LENGTH_SHORT).show();

View File

@ -31,7 +31,7 @@ public class NewsListFragment extends Fragment implements NewsUpdatedCallbackInt
ArrayList<NewsRecord> newsRecordArr;
NewsManager.RemoveCallbackInterface downloadNewsCanceller;
NewsManager.RemoveCallbackInterface downloadNewsCanceller = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -57,7 +57,11 @@ public class NewsListFragment extends Fragment implements NewsUpdatedCallbackInt
@Override
public void onDestroyView()
{
downloadNewsCanceller.RemoveCallback();
if (downloadNewsCanceller != null)
{
downloadNewsCanceller.RemoveCallback();
downloadNewsCanceller = null;
}
super.onDestroyView();
}

View File

@ -0,0 +1,22 @@
package fishrungames.bashgid;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class SettingsFragment extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_settings_page, container, false);
return rootView;
}
}

View File

@ -5,6 +5,8 @@ import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.Semaphore;
import fishrungames.bashgid.MainActivity;
import fishrungames.bashgid.R;
@ -20,6 +22,10 @@ public class ImageManager {
static ImageManager instance = null;
private volatile Semaphore downloadingFileNameSetMutex = new Semaphore(1, true);
private volatile HashSet<String> downloadingFileNameSet = new HashSet<String>();
public static ImageManager getInstance()
{
if (instance == null)
@ -43,6 +49,8 @@ public class ImageManager {
public void ApplyImageToImageView(ImageView imageView, String imageId)
{
//Xperimental -- Should be called only in main thread
if (imageId.startsWith("R.drawable."))
{
Integer resourceId = PredefinedImageId.get(imageId);
@ -64,14 +72,40 @@ public class ImageManager {
if (f.exists())
{
Bitmap bitmap = BitmapFactory.decodeFile( MainActivity.getInstance().getFileStreamPath(fileName).getAbsolutePath());
imageView.setImageBitmap(bitmap);
boolean fileIsBusy = false;
try
{
downloadingFileNameSetMutex.acquire();
try
{
fileIsBusy = downloadingFileNameSet.contains(fileName);
} finally
{
downloadingFileNameSetMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in ApplyImageToImageView", "Error in ApplyImageToImageView");
}
if (!fileIsBusy)
{
Bitmap bitmap = BitmapFactory.decodeFile( MainActivity.getInstance().getFileStreamPath(fileName).getAbsolutePath());
imageView.setImageBitmap(bitmap);
}
}
else
{
Log.e("Error: ", "Image requested but not downloaded: " + imageId);
imageView.setImageResource(R.drawable.transparent);
}
}
@ -97,26 +131,76 @@ public class ImageManager {
return;
}
try {
InputStream is = (InputStream) new URL(imageUrl).getContent();
FileOutputStream out = null;
out = MainActivity.getInstance().openFileOutput(fileName, Context.MODE_PRIVATE);
byte [] buf = new byte[1024];
int numRead;
while ( (numRead = is.read(buf) ) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
boolean fileIsBusy = false;
try
{
downloadingFileNameSetMutex.acquire();
try
{
if (downloadingFileNameSet.contains(fileIsBusy))
{
fileIsBusy = true;
}
else
{
downloadingFileNameSet.add(fileName);
}
} finally
{
downloadingFileNameSetMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in DownloadImageIfNeeded", "Error in DownloadImageIfNeeded");
}
if (!fileIsBusy)
{
try {
InputStream is = (InputStream) new URL(imageUrl).getContent();
FileOutputStream out = null;
out = MainActivity.getInstance().openFileOutput(fileName, Context.MODE_PRIVATE);
byte [] buf = new byte[1024];
int numRead;
while ( (numRead = is.read(buf) ) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (Exception e) {
e.printStackTrace();
}
try
{
downloadingFileNameSetMutex.acquire();
try
{
} catch (Exception e) {
e.printStackTrace();
}
downloadingFileNameSet.remove(fileName);
} finally
{
downloadingFileNameSetMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in DownloadImageIfNeeded", "Error in DownloadImageIfNeeded");
}
}
}
public String GetImageLocalUrl(String imageUrl)

View File

@ -4,16 +4,38 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.concurrent.Semaphore;
import android.util.Log;
import fishrungames.bashgid.MainActivity;
import fishrungames.bashgid.core.db.BashgidSqliteHelper;
public class NewsManager {
private static NewsManager instance = null;
private static final String [] urlArr = {
"https://www.bashkortostan.ru/presscenter/news/rss/",
"http://www.bashedu.ru/rss.xml",
"http://www.bashinform.ru/rss/all.xml",
"http://www.minkult-rb.ru/news/rss/",
"http://02.mvd.ru/news/rss/"
};
private static NewsManager instance = null;
private static volatile boolean SynchronizationInProcess = false; //Not strict, so don't need mutex
private volatile Semaphore newsRecordMutex = new Semaphore(1, true);
private ArrayList<NewsRecord> newsRecord = new ArrayList<NewsRecord>();
public static boolean CanCallSynchronization()
{
return SynchronizationInProcess;
}
//Xperimental -- need do something with this. Change to semaphore?
public static volatile boolean SynchronizationInProcess = false;
public static NewsManager GetInstance()
@ -60,16 +82,18 @@ public class NewsManager {
}
}
ArrayList<NewsRecord> newsRecord = new ArrayList<NewsRecord>();
public RemoveCallbackInterface DownloadNews(NewsUpdatedCallbackInterface callback)
{
DownloadNewsRunnable downloadNewsRunnable = new DownloadNewsRunnable(callback);
Thread thread = new Thread(downloadNewsRunnable);
thread.start();
DownloadNewsRunnable downloadNewsRunnable = null;
if (CanCallSynchronization())
{
downloadNewsRunnable = new DownloadNewsRunnable(callback);
Thread thread = new Thread(downloadNewsRunnable);
thread.start();
}
return downloadNewsRunnable;
}
@ -77,70 +101,123 @@ public class NewsManager {
class DownloadNewsRunnable implements Runnable, RemoveCallbackInterface
{
NewsUpdatedCallbackInterface callback;
private volatile Semaphore callbackMutex = new Semaphore(1, true);
NewsUpdatedCallbackInterface callback = null;
public DownloadNewsRunnable(NewsUpdatedCallbackInterface callback)
{
this.callback = callback;
try
{
callbackMutex.acquire();
try
{
this.callback = callback;
} finally
{
callbackMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in DownloadNewsRunnable", "Error in DownloadNewsRunnable");
}
}
@Override
public void RemoveCallback()
{
callback = null;
try
{
callbackMutex.acquire();
try
{
callback = null;
} finally
{
callbackMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in DownloadNewsRunnable", "Error in DownloadNewsRunnable");
}
}
@Override
public void run()
{
if (SynchronizationInProcess)
{
return;
}
SynchronizationInProcess = true;
final String [] urlArr = {
"https://www.bashkortostan.ru/presscenter/news/rss/",
"http://www.bashedu.ru/rss.xml",
"http://www.bashinform.ru/rss/all.xml",
"http://www.minkult-rb.ru/news/rss/",
"http://02.mvd.ru/news/rss/"
};
SynchronizationInProcess = true;
ArrayList<NewsRecord> localNewsRecord = MainActivity.getInstance().newsDataSource.getNews();
ArrayList<String> imageToDownloadList = new ArrayList<String>();
for (int i = 0; i < urlArr.length; i++)
{
LoadNewsAndImagesFromRss2(urlArr[i], localNewsRecord, imageToDownloadList);
Collections.sort(localNewsRecord, new NewsSortComparator());
//NewsSortComparator
//Xperimental -- need mutex right here
newsRecord = localNewsRecord;
MainActivity.getInstance().newsDataSource.replaceNews(newsRecord);
//Xperimental -- need mutex here, too
if (callback != null)
{
callback.OnNewsUpdated();
}
}
Collections.sort(localNewsRecord, new NewsSortComparator());
try
{
newsRecordMutex.acquire();
try
{
newsRecord = localNewsRecord;
MainActivity.getInstance().newsDataSource.replaceNews(newsRecord);
} finally
{
newsRecordMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in DownloadNewsRunnable", "Error in DownloadNewsRunnable");
}
try
{
callbackMutex.acquire();
try
{
if (callback != null)
{
callback.OnNewsUpdated();
}
} finally
{
callbackMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in DownloadNewsRunnable", "Error in DownloadNewsRunnable");
}
for (String imageToDownload : imageToDownloadList)
{
ImageManager.getInstance().DownloadImageIfNeeded(imageToDownload);
}
SynchronizationInProcess = false;
SynchronizationInProcess = false;
}
}
@ -157,14 +234,46 @@ public class NewsManager {
public NewsManager()
{
newsRecord = MainActivity.getInstance().newsDataSource.getNews();
try
{
newsRecordMutex.acquire();
try
{
newsRecord = MainActivity.getInstance().newsDataSource.getNews();
} finally
{
newsRecordMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in NewsManager constructor", "Error in NewsManager constructor");
}
}
public ArrayList<NewsRecord> getNews()
{
return newsRecord;
ArrayList<NewsRecord> result = new ArrayList<NewsRecord>();
try
{
newsRecordMutex.acquire();
try
{
result.addAll(newsRecord);
} finally
{
newsRecordMutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error in NewsManager constructor", "Error in NewsManager constructor");
}
return result;
}

View File

@ -7,6 +7,7 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@ -36,6 +37,11 @@ public class XmlProcessor
{
Log.e("Error: ", e.getMessage());
return null;
} catch (DOMException e)
{
//Xperimental -- need to learn more about this exception
Log.e("Error: ", e.getMessage());
return null;
} catch (SAXException e)
{
Log.e("Error: ", e.getMessage());

View File

@ -4,6 +4,7 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Locale;
import java.util.concurrent.Semaphore;
import fishrungames.bashgid.core.NewsManager;
@ -12,6 +13,7 @@ import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
public class NewsDataSource
{
@ -19,25 +21,82 @@ public class NewsDataSource
//Xperimental -- move somewhere
public static final SimpleDateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
private SQLiteDatabase database;
private SQLiteDatabase database = null;
private BashgidSqliteHelper dbHelper;
private BashgidSqliteHelper dbHelper = null;
private String[] allColumns = { BashgidSqliteHelper.COLUMN_ID, BashgidSqliteHelper.COLUMN_TITLE, BashgidSqliteHelper.COLUMN_DESCRIPTION,
BashgidSqliteHelper.COLUMN_IMAGE_ID, BashgidSqliteHelper.COLUMN_PUBDATE };
private final Semaphore mutex = new Semaphore(1, true);
public NewsDataSource(Context context) {
dbHelper = new BashgidSqliteHelper(context);
public NewsDataSource(Context context)
{
try
{
mutex.acquire();
try
{
dbHelper = new BashgidSqliteHelper(context);
} finally
{
mutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error when creating BashgidSqliteHelper", "Error when creating BashgidSqliteHelper");
}
}
public void open() throws SQLException
{
database = dbHelper.getWritableDatabase();
try
{
mutex.acquire();
try
{
database = dbHelper.getWritableDatabase();
} finally
{
mutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error when opening NewsDataSource", "Error when opening NewsDataSource");
database = null;
}
}
public void close()
{
dbHelper.close();
try
{
mutex.acquire();
try
{
if (dbHelper != null)
{
dbHelper.close();
database = null;
}
} finally
{
mutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error when closing NewsDataSource", "Error when closing NewsDataSource");
}
}
public void createNewsRecord(NewsManager.NewsRecord newsRecord)
@ -50,14 +109,52 @@ public class NewsDataSource
values.put(BashgidSqliteHelper.COLUMN_IMAGE_ID, newsRecord.imageId);
values.put(BashgidSqliteHelper.COLUMN_PUBDATE, iso8601Format.format(newsRecord.pubDate));
database.insert(BashgidSqliteHelper.TABLE_NEWS, null, values);
try
{
mutex.acquire();
try
{
if (database != null)
{
database.insert(BashgidSqliteHelper.TABLE_NEWS, null, values);
}
} finally
{
mutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error when calling createNewsRecord", "Error when calling createNewsRecord");
}
}
public void replaceNews(ArrayList<NewsManager.NewsRecord> newsRecordArr)
{
database.delete(BashgidSqliteHelper.TABLE_NEWS, null, null);
try
{
mutex.acquire();
try
{
if (database != null)
{
database.delete(BashgidSqliteHelper.TABLE_NEWS, null, null);
}
} finally
{
mutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error when calling replaceNews", "Error when calling replaceNews");
}
for (NewsManager.NewsRecord newsRecord : newsRecordArr)
{
@ -70,18 +167,39 @@ public class NewsDataSource
{
ArrayList<NewsManager.NewsRecord> newsRecordArr = new ArrayList<NewsManager.NewsRecord>();
Cursor cursor = database.query(BashgidSqliteHelper.TABLE_NEWS, allColumns, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast())
/*
try
{
NewsManager.NewsRecord newsRecord = cursorToNewsRecord(cursor);
newsRecordArr.add(newsRecord);
cursor.moveToNext();
mutex.acquire();
try
{
*/
if (database != null)
{
Cursor cursor = database.query(BashgidSqliteHelper.TABLE_NEWS, allColumns, null, null, null, null, null);
cursor.moveToFirst();
while (!cursor.isAfterLast())
{
NewsManager.NewsRecord newsRecord = cursorToNewsRecord(cursor);
newsRecordArr.add(newsRecord);
cursor.moveToNext();
}
cursor.close();
}
/*
} finally
{
mutex.release();
}
} catch (InterruptedException ie)
{
Log.e("Error when calling replaceNews", "Error when calling replaceNews");
}
// make sure to close the cursor
cursor.close();
*/
return newsRecordArr;
}